3. logcat日志分析
做Camera HAL层调试,说白了就是跟logcat打交道。我刚开始带项目那会儿,每天盯着几十万行log找问题,眼睛都快瞎了。后来慢慢摸出门道,发现只要抓住几个关键标签,效率能翻好几倍。
今天我就把这套方法拆开揉碎了讲给你听。你想想看,如果连log都不会看,那调试就像蒙着眼睛走路,对吧?
3.1 必须记住的三个核心log标签
Android Camera HAL层调试,你只需要盯住三个标签。其他的可以暂时忽略,等出了问题再回头查。
| 标签名 | 所属模块 | 典型用途 |
|---|---|---|
| CAM_HAL | HAL层通用 | HAL接口调用、参数传递、错误码 |
| CamX | Qualcomm平台 | Pipeline配置、Sensor控制、ISP处理 |
| CHI | Qualcomm平台 | Usecase切换、Node图构建、XML解析 |
CAM_HAL 是通用标签,所有HAL层的核心流程都会打这个标签。我习惯先过滤这个,看整体流程是否走通。
CamX 和 CHI 是Qualcomm平台特有的。如果你用MTK平台,对应的是 MtkCam 和 MtkCam3。道理是一样的,只是名字不同。
我的经验: 遇到预览黑屏问题,先看CAM_HAL有没有返回错误。如果CAM_HAL一切正常,再切到CamX看Sensor有没有出图。我曾经有个案子,CAM_HAL显示正常,但CamX报了个Sensor初始化超时,折腾了两天才发现是MCLK频率配错了。
3.2 log等级设置:别让垃圾信息淹了你
默认的log等级是 INFO,但调试HAL层时,这个等级远远不够。你需要把等级降到 DEBUG 甚至 VERBOSE。
怎么设置?两种方法:
- adb命令临时设置(推荐,重启后失效)
- 修改prop文件永久设置(需要root权限)
// 临时设置,只对当前adb会话有效
adb shell setprop persist.vendor.camera.debug.logs 1
adb shell setprop persist.vendor.camera.debug.meta 1
// 设置单个标签的log等级
adb shell setprop log.tag.CAM_HAL VERBOSE
adb shell setprop log.tag.CamX VERBOSE
adb shell setprop log.tag.CHI VERBOSE
// 重启cameraserver让设置生效
adb shell killall cameraserver
小技巧: 我习惯写个脚本,一键设置所有需要的log等级。不然每次手动敲太累了。脚本里加上 adb root 和 adb remount,省得每次都要输密码。
为什么要设成VERBOSE?因为很多关键信息只在VERBOSE等级输出。比如Sensor的帧率、曝光时间、增益值,这些在DEBUG等级是看不到的。
注意: 生产环境千万别开VERBOSE。log量会暴增,影响性能。我见过有人把VERBOSE开了一整天,结果log文件撑爆了/data分区,手机直接变砖。
3.3 过滤与抓取技巧:精准定位问题
logcat默认会输出所有进程的log,信息量太大。你需要学会过滤。
最基本的过滤方法:
// 只显示CAM_HAL标签的log
adb logcat -s CAM_HAL
// 同时显示多个标签
adb logcat -s CAM_HAL CamX CHI
// 显示某个进程的log(比如cameraserver)
adb logcat --pid=$(adb shell pidof cameraserver)
// 保存到文件,方便后续分析
adb logcat -s CAM_HAL CamX CHI > camera_log.txt
我个人最常用的是 -s 参数加时间戳:
adb logcat -v time -s CAM_HAL CamX CHI
这样每条log前面都有时间戳,方便看时序。比如Sensor配置和Stream配置之间的时间差,一眼就能看出来。
还有一个技巧:用 grep 做二次过滤。比如我只想看错误相关的log:
adb logcat -s CAM_HAL | grep -i "error\|fail\|fatal"
避坑指南: 我曾经在调试双摄时,发现log里一直报错,但就是找不到原因。后来才发现是grep过滤太严格,把关键信息漏掉了。所以我的习惯是:先抓全量log,再用grep过滤。全量log留着,万一需要回溯呢?
3.4 常见错误log解读:看到这些别慌
下面是我总结的几个高频错误log,你遇到时可以直接对照排查。
| 错误log内容 | 可能原因 | 排查方向 |
|---|---|---|
CAM_HAL: configureStreams failed: -38 |
Stream配置参数不合法 | 检查分辨率、格式、buffer数是否匹配 |
CamX: Sensor power up failed |
Sensor上电时序异常 | 检查MCLK、AVDD、DVDD、IOVDD电压 |
CHI: Usecase switch timeout |
Usecase切换超时 | 检查XML配置,确认Node图是否完整 |
CAM_HAL: processCaptureRequest timeout |
Capture请求处理超时 | 检查ISP处理时间,确认是否帧率过高 |
CamX: Buffer queue full |
Buffer队列满了 | 检查Consumer端是否及时释放buffer |
举个例子,configureStreams failed: -38 这个错误我遇到过不下十次。错误码-38对应的是 EINVAL,意思是参数无效。但具体是哪个参数无效?
我的排查步骤:
- 先看log里打印的Stream配置信息,确认分辨率、格式是否正确
- 再看App层请求的Stream数量和HAL层支持的最大数量是否一致
- 最后检查是否有重复的Stream ID
有一次我排查了半天,最后发现是App层传了一个 YUV420_888 格式,但Sensor只支持 NV12。这种问题,不看log根本想不到。
我的习惯: 遇到错误log,先看错误码。每个错误码都有对应的含义,比如-22是 EINVAL,-12是 ENOMEM。记住几个常见的,排查速度能快很多。
3.5 实战:用log定位预览黑屏问题
我拿一个真实案例给你演示一下。某次项目,预览黑屏,但拍照正常。
第一步,抓log:
adb logcat -v time -s CAM_HAL CamX CHI > preview_black.log
第二步,看CAM_HAL:
// 发现configureStreams正常返回0
// 但processCaptureRequest返回了-22
// 错误码-22 = EINVAL,参数无效
第三步,看CamX:
// 发现Sensor输出正常,帧率稳定在30fps
// 但ISP处理时,报了一个"Invalid buffer format"
第四步,看CHI:
// 发现Usecase配置里,Preview Node的输出格式是NV21
// 但App请求的是YUV420_888
// 格式不匹配,导致ISP无法处理
问题找到了:XML里Preview Node的格式配错了。改成NV12后,预览正常。
总结一下: 看log就像破案,要有步骤。先看整体流程(CAM_HAL),再看具体模块(CamX/CHI),最后定位到具体参数。别一上来就扎进细节,容易迷失方向。
3.6 本章知识体系
下面这张图是我自己画的,把本章的核心逻辑串起来了。你保存下来,调试时对照着看。
这张图把三个核心标签、log等级设置、过滤抓取技巧、常见错误解读串在了一起。你调试时,按这个流程走,基本不会漏掉关键信息。
好了,logcat分析这块就讲这么多。记住一句话:log是死的,人是活的。多练、多总结,你也能成为log分析高手。
可可精品资料库