4. 长时间运行测试:Camera Open/Close循环、Preview持续与录像拍照交替

长时间运行测试是验证 Camera HAL 稳定性的核心手段,旨在暴露资源泄漏、内存碎片、死锁、电源管理异常以及驱动老化等间歇性故障。本章围绕三类典型长时间测试场景展开:Open/Close 循环、Preview 持续与录像拍照交替,分别对应 HAL 层资源管理、流处理持久性以及多模式切换的稳定性。

4.1 测试场景与关键指标

下表汇总了三种长时间测试的典型配置、监控指标与通过标准:

测试场景 持续时间 / 循环次数 核心监控指标 通过标准
Open/Close 循环 10000 次 内存泄漏、文件描述符泄漏、Camera 服务重启次数 0 次服务重启,内存增量 < 5%
Preview 持续 24 小时 帧率稳定性、CPU 占用率、温度、ANR 次数 帧率波动 < 10%,无 ANR
录像与拍照交替 8 小时 录像文件完整性、拍照成功率、音视频同步偏移 拍照成功率 100%,音视频偏移 < 33ms
测试环境要求:所有长时间测试必须在恒温环境下进行(25°C ± 2°C),并保持设备充电状态。建议使用自动化测试框架(如 Google 的 Camera ITS 或自研脚本)驱动,避免人工操作引入的时序偏差。

4.2 Open/Close 循环测试(10000次)

该测试模拟应用频繁打开和关闭 Camera 设备,验证 HAL 层在资源分配与释放过程中的健壮性。常见故障包括:CameraService 崩溃、驱动句柄泄漏以及内存碎片化。

4.2.1 测试流程与关键检查点

  1. 初始化状态记录:测试前记录 /proc/meminfo、lsof 输出、dmesg 日志。
  2. 循环执行 Open/Close:每次 Open 后等待 500ms,Close 后等待 200ms,避免背靠背操作。
  3. 周期性检查:每 1000 次循环检查一次内存增量与文件描述符数量。
  4. 异常处理:若 Open 返回错误或 CameraService 重启,立即记录上下文并继续测试。
  5. 后处理分析:对比测试前后的资源快照,计算泄漏量。
常见泄漏模式:HAL 层在 close() 中未释放 gralloc buffer、未关闭 sensor 驱动节点、未销毁 pipeline 线程。建议在 close() 函数末尾添加 LOG_ASSERT 检查内部引用计数是否归零。

4.2.2 资源泄漏检测脚本示例

#!/system/bin/sh
# 资源监控脚本片段,用于 Open/Close 循环测试
LOG_FILE="/data/camera_leak_test.log"
PID=$(pidof cameraserver)

echo "=== Test Start ===" > $LOG_FILE
cat /proc/$PID/status | grep VmRSS >> $LOG_FILE
lsof -p $PID | wc -l >> $LOG_FILE

for i in $(seq 1 10000); do
    # 执行 Open/Close 操作(由测试框架触发)
    sleep 0.5

    # 每 1000 次采样一次
    if [ $((i % 1000)) -eq 0 ]; then
        echo "Loop $i:" >> $LOG_FILE
        cat /proc/$PID/status | grep VmRSS >> $LOG_FILE
        lsof -p $PID | wc -l >> $LOG_FILE
        dmesg -c | grep -i "camera\|ion\|dma" >> $LOG_FILE
    fi
done

echo "=== Test End ===" >> $LOG_FILE

4.2.3 Open/Close 循环故障树

下图展示了 Open/Close 循环测试中可能出现的故障路径与根因分析方向:

Open/Close 循环故障树 Open/Close 循环失败 CameraService 崩溃 内存持续增长 Open 返回错误 HAL 死锁 驱动句柄泄漏 Gralloc Buffer 未释放 Sensor 初始化失败 根因:close() 中未释放 pipeline 资源 或驱动层引用计数未正确递减

4.3 Preview 持续测试(24小时)

Preview 持续测试验证 Camera HAL 在长时间视频流处理中的稳定性。核心风险包括:帧率下降、CPU 过载、热降频导致画面卡顿以及ISP 管线溢出。

4.3.1 测试配置与监控方案

  • 分辨率与帧率:使用设备支持的最大分辨率(如 1920x1080 @ 30fps)。
  • 帧率监控:通过 adb shell dumpsys media.camera 或 HAL 层注入的帧时间戳日志,每 5 分钟统计一次平均帧率。
  • 温度监控:读取 /sys/class/thermal/thermal_zone*/temp,记录 SoC 与电池温度。
  • ANR 检测:监听 data/anr/ 目录下是否有新生成的 traces 文件。
注意:Preview 持续测试中,如果帧率在 2 小时内持续下降超过 15%,应立即停止测试并检查 ISP 驱动是否有丢帧或 buffer 堆积现象。常见原因为 HAL 层未及时归还 buffer 给驱动。

4.3.2 Preview 持续测试状态机

下图描述了 Preview 持续测试中 HAL 层的状态流转与关键监控点:

Preview 持续测试状态机 IDLE PREVIEW_ACTIVE THERMAL_THROTTLE ERROR STOPPED startPreview() 温度 > 85°C 温度回落 帧率 < 15fps stopPreview() release() 监控点: 每 5min 检查帧率 & 温度

4.4 录像与拍照交替测试(8小时)

该测试模拟用户在实际使用中频繁切换录像与拍照模式,验证 HAL 层在流配置切换、buffer 重分配以及音视频同步方面的稳定性。典型故障包括:拍照黑帧、录像文件损坏以及音视频不同步。

4.4.1 交替测试策略

阶段 操作 持续时间 验证点
1 启动录像(1080p@30fps) 5 分钟 录像文件正常写入,音视频 pts 连续
2 停止录像,立即拍照(连拍 5 张) 10 秒 每张照片 exif 信息完整,无黑帧
3 切换回录像(4K@30fps) 5 分钟 分辨率切换后帧率稳定
4 重复步骤 1-3,共 8 小时 — 无 crash,无 ANR,无文件损坏

4.4.2 音视频同步偏移检测

在录像过程中,HAL 层需要为每个视频帧和音频帧打上精确的时间戳。检测偏移的方法如下:

# 使用 ffprobe 分析录像文件中的音视频时间戳
ffprobe -v quiet -show_entries frame=pts_time,media_type \
  -of csv=p=0 recording.mp4 | awk -F',' '
{
  if ($2 == "video") v_pts = $1;
  if ($2 == "audio") a_pts = $1;
}
END {
  diff = (v_pts - a_pts) * 1000;  # 转换为毫秒
  if (diff < -33 || diff > 33)
    printf "WARNING: AV sync offset = %.2f ms\n", diff;
  else
    printf "OK: AV sync offset = %.2f ms\n", diff;
}'
偏移根因分析:如果偏移量持续增大,通常是因为 HAL 层在录像/拍照切换时未正确重置音频时间戳基准,或者视频帧在 ISP 管线中排队时间过长。建议在 configure_streams() 中检查 timestamp base 是否被正确更新。

4.4.3 录像拍照交替流程图

下图展示了 8 小时交替测试中 HAL 层的核心操作序列与故障注入点:

录像拍照交替测试流程图 开始交替测试 录像 5 分钟 停止录像 连拍 5 张 切换分辨率 8 小时完成? 测试结束 否,继续循环 故障注入点: 切换时强制释放 buffer

4.5 故障排查实战要点

在长时间运行测试中,故障排查应遵循以下优先级顺序:

  1. 检查 dmesg 与 logcat:搜索 "camera"、"HAL"、"buffer"、"timeout" 等关键词,定位首次异常发生的时间点。
  2. 分析内存快照:使用 dumpsys meminfo 或 procrank 对比测试前后的内存占用,重点关注 native heap 与 GPU buffer 的增长。
  3. 复现最小化场景:将 10000 次循环缩减为 100 次,并增加每次操作的延迟,观察是否仍然触发故障。
  4. 检查驱动层状态:通过 cat /d/ion/heaps 或 cat /proc/mtk_camera(MTK 平台)查看驱动 buffer 分配情况。
  5. 验证 HAL 层资源释放:在 close() 函数中添加日志,打印每个子模块的引用计数,确认是否归零。
经验法则:如果 Open/Close 循环在 3000 次左右开始出现内存增长,通常指向某个 buffer 在 close() 中未被释放;如果在 8000 次左右出现,则更可能是内存碎片化问题。根据出现时机可以快速缩小排查范围。