第1章:相机调试三板斧——Systrace、Camera2测试工具与dumpsys

做Android相机开发,最头疼的是什么?

不是API不会调,而是出了问题不知道从哪查。我刚开始接触相机开发那会儿,经常遇到预览卡顿、拍照延迟、对焦不准这类问题。那时候我只会对着代码一遍遍看,结果往往是浪费时间。

后来一位老前辈跟我说了一句话,我到现在都记得:「别猜,用工具说话」

今天我就把这套「三板斧」教给你。它们分别是:Systrace、Camera2 API测试工具、以及adb shell dumpsys media.camera。这三样东西用熟了,相机调试对你来说就不再是玄学。


1.1 Systrace:相机性能分析的「显微镜」

1.1.1 为什么需要Systrace?

你想想看,相机预览卡顿,到底是CPU不够快?还是GPU渲染跟不上?还是驱动层丢帧了?

普通日志只能告诉你「发生了什么」,但Systrace能告诉你「每一毫秒发生了什么」

我个人习惯,只要遇到相机性能问题,第一件事就是抓一份Systrace。它能把系统里所有线程的活动按时间轴展示出来,哪个阶段耗时多、哪个线程在空转,一眼就能看出来。

1.1.2 怎么抓Systrace?

其实很简单。老版本用atrace,新版本用Perfetto。我推荐直接用Perfetto,因为它更现代,UI也更友好。

命令行方式(适合自动化):

# 抓取10秒的trace,包含相机相关标签
adb shell perfetto -t 10s -o /data/misc/perfetto-traces/trace.perfetto \
  --categories camera,hal,graphics,audio,input

# 拉取到本地
adb pull /data/misc/perfetto-traces/trace.perfetto .

图形化方式(适合日常调试):

  1. 打开浏览器访问 ui.perfetto.dev
  2. 点击「Record new trace」
  3. 在「Categories」中勾选 camerahalgraphics
  4. 点击「Start recording」,然后操作手机相机
  5. 点击「Stop」,自动下载trace文件
我的小技巧:抓trace时尽量只做单一操作。比如只测试「打开相机」或只测试「拍照」。混在一起分析起来很痛苦,我踩过这个坑。

1.1.3 怎么看Systrace?

打开trace文件后,你会看到一堆彩色条带。别慌,我教你重点看三个地方:

关注点 怎么看 常见问题
SurfaceFlinger 看是否有掉帧(红色标记) GPU渲染超时
Camera HAL 看processCaptureRequest耗时 HAL层处理太慢
App主线程 看是否有长时间阻塞 UI线程做了耗时操作

举个例子。我曾经遇到一个预览卡顿问题,查代码怎么也找不到原因。抓了Systrace一看,发现Camera HAL线程每隔几帧就有一个明显的空档期——原来是驱动层在某个分辨率下没有做好流水线处理。后来换了预览尺寸,问题就解决了。

注意:Systrace只能抓取有trace标签的代码段。如果你自己写的代码没有加trace标签,是看不到的。建议在关键路径上加:Trace.beginSection("mySection")

1.2 Camera2 API测试工具:快速验证你的相机逻辑

1.2.1 官方测试工具

Google其实提供了一个非常好用的测试工具,叫「Camera2 API Test」。它藏在CTS测试包里,但你可以单独拿出来用。

我个人习惯在开发新功能时,先用这个工具跑一遍,看看设备支持哪些能力。比如:

  • 是否支持RAW输出?
  • 支持哪些AE(自动曝光)模式?
  • 最大预览尺寸是多少?

安装方式很简单:

# 从CTS包中提取
unzip android-cts-*.zip
cd android-cts/testcases/
adb install CtsCameraTestCases.apk

然后打开应用,选择对应的测试项。它会自动验证你的Camera2实现是否符合规范。

1.2.2 自己写测试工具

当然,官方工具只能测通用场景。我建议你针对自己的业务,写一套自动化测试脚本。

核心思路是这样的:

// 伪代码示例
CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
String[] cameraIds = manager.getCameraIdList();

for (String id : cameraIds) {
    CameraCharacteristics chars = manager.getCameraCharacteristics(id);
    
    // 检查是否支持闪光灯
    Boolean flashAvailable = chars.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
    
    // 检查支持的AE模式
    int[] aeModes = chars.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);
    
    // 检查最大预览尺寸
    StreamConfigurationMap map = chars.get(
        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
    Size[] previewSizes = map.getOutputSizes(ImageFormat.YUV_420_888);
    
    Log.d("CameraTest", "Camera " + id + " preview sizes: " + 
          Arrays.toString(previewSizes));
}
避坑指南:我曾经在测试某款国产手机时,发现它声称支持CONTROL_AE_MODE_ON,但实际拍照时AE根本不工作。后来用这个测试工具一跑,发现是驱动层实现有bug。所以,不要完全相信参数列表,一定要实际验证

1.3 adb shell dumpsys media.camera:相机状态的「体检报告」

1.3.1 这个命令能干什么?

说白了,dumpsys media.camera就是把你手机里相机相关的所有状态,一股脑打印出来。包括:

  • 当前打开的相机ID
  • 当前的预览尺寸、拍照尺寸
  • 当前的AE/AWB/AF状态
  • HAL层的版本信息
  • 是否有异常错误

我遇到相机打不开的问题时,第一反应就是跑这个命令。它往往能直接告诉我问题出在哪。

1.3.2 怎么用?

# 查看所有相机信息
adb shell dumpsys media.camera

# 只看某个特定相机(比如ID为0的后置相机)
adb shell dumpsys media.camera -c 0

# 只看HAL层信息
adb shell dumpsys media.camera -v hal

1.3.3 实战案例

有一次,用户反馈说「相机打开后黑屏」。我远程连上他的手机,跑了dumpsys media.camera,发现输出中有这么一行:

Camera 0: State: ERROR (3)
Error: 3 (CAMERA_ERROR_SERVER_DIED)

看到CAMERA_ERROR_SERVER_DIED,我立刻明白了——是Camera Service进程崩溃了。后来查下来,是因为某个三方应用占用了太多内存,导致系统杀掉了Camera Service。

你看,如果没有这个命令,我可能还在傻傻地看代码。

注意:dumpsys的输出非常长,建议用grep过滤关键信息。比如:adb shell dumpsys media.camera | grep -i error

1.4 本章知识体系

下面这张图,帮你把今天讲的三板斧串起来:

相机调试三板斧 Systrace Camera2测试工具 dumpsys media.camera 性能分析 • 查看每毫秒的线程活动 • 定位掉帧原因 • 分析HAL层耗时 • 检查GPU渲染 • 发现空转/阻塞 功能验证 • 检查设备能力列表 • 验证AE/AWB/AF • 测试预览/拍照尺寸 • 自动化回归测试 • 发现驱动层bug 状态诊断 • 查看相机打开状态 • 检查错误码 • 获取HAL版本信息 • 查看当前配置参数 • 定位Service崩溃

1.5 总结

今天这三样工具,说白了就是:

  • Systrace——看性能,找卡顿根源
  • Camera2测试工具——验功能,确认设备能力
  • dumpsys media.camera——查状态,快速定位问题

我个人的工作流是这样的:遇到问题,先跑dumpsys看有没有明显错误;没有的话,抓Systrace分析性能;最后用测试工具验证猜想。这套流程帮我解决过至少80%的相机问题。

嗯,工具就介绍到这里。下一章我们开始动手写代码,从打开相机预览开始。


公众号:蓝海资料掘金营,微信deep3321