高通 camx 的日志分两大块:UMD(User Mode Driver,用户层) 和 KMD(Kernel Mode Driver,内核层)。
遇到任何问题,先把"案发现场"固定下来——日志、dump、状态信息。本章讲清楚怎么抓、怎么看、怎么分析。
CamX 的 UMD 日志格式如下:
CamX: [<VerbosityLevel>][<Group>] <File>:<Line Number> <Function Name> <Message>
实际例子:
CamX: [INFO][CORE] camxsession.cpp:123 Session::ProcessCaptureRequest() frame_number=42
| 等级 | 对应属性 | 说明 |
|---|---|---|
| ERROR | logErrorMask |
错误,默认输出 |
| WARNING | logWarningMask |
警告 |
| INFO | logInfoMask |
信息 |
| DEBUG | logDebugMask |
调试 |
| VERBOSE | logVerboseMask |
详细 |
各组定义在 camx/src/utils/camxtypes.h 中:
| 分组名 | bit | 掩码 | 模块 |
|---|---|---|---|
| CamxLogGroupCore | 1<<0 | 0x1 | Session/Pipeline/Node |
| CamxLogGroupCSL | 1<<1 | 0x2 | CSL 层(与 Kernel 通信) |
| CamxLogGroupISP | 1<<2 | 0x4 | ISP 硬件 |
| CamxLogGroupStats | 1<<3 | 0x8 | 3A Stats |
| CamxLogGroupMeta | 1<<4 | 0x10 | Metadata |
| CamxLogGroupHAL | 1<<5 | 0x20 | HAL3 接口 |
| CamxLogGroupCHI | 1<<6 | 0x40 | CHI 层 |
| CamxLogGroupSensor | 1<<7 | 0x80 | Sensor 驱动 |
| CamxLogGroupAEC | 1<<8 | 0x100 | AE 算法 |
| CamxLogGroupAWB | 1<<9 | 0x200 | AWB 算法 |
| CamxLogGroupAF | 1<<10 | 0x400 | AF 算法 |
# setprop 方式(实时生效)
adb shell setprop persist.vendor.camera.logInfoMask 0x8 # ISP Info
adb shell setprop persist.vendor.camera.logDebugMask 0x7 # Core+CSL+ISP Debug
# camxoverridesettings.txt 方式(重启 Provider 生效)
adb shell "echo logInfoMask=0x8 >> /vendor/etc/camera/camxoverridesettings.txt"
adb shell killall -9 vendor.camera-provider-2-4
掩码计算方法:多个分组同时开启 = 各分组掩码相加(或运算)
例: 同时打开 Core(0x1) + CSL(0x2) + ISP(0x4)
掩码 = 0x1 + 0x2 + 0x4 = 0x7
例: 同时打开 ISP(0x4) + Stats(0x8) + AEC(0x100)
掩码 = 0x4 + 0x8 + 0x100 = 0x10C
# 打开 CAM_SENSOR + CAM_CSID 的 kernel 日志
adb shell "echo 0x101 > /sys/module/cam_debug_util/parameters/debug_mdl"
adb shell cat /proc/kmsg > kmd_logs.txt
Kernel 各模块 mask:
CAM_SENSOR = 0x1 Sensor 驱动
CAM_ICP = 0x20 ICP 模块
CAM_CSIPHY = 0x80 CSIPHY(MIPI 物理层)
CAM_CSID = 0x100 CSID(MIPI 协议解码)
CAM_CCI = 0x200 CCI(I2C 控制器)
CAM_ISP = 0x400 ISP
这是一次完整的拍照请求(preview + capture)应该能看到的日志链。按这个顺序找,找到哪一步断了,问题就在哪一步。
// ① App 发起预览请求
// HAL3 入口收到 setRepeatingRequest
[CamX] [HAL] camxhal3entry.cpp: ProcessCaptureRequest() frame_number=1
// ② CHI 层受理
[CHI] chxusecase.cpp: SubmitChiRequest() frame_number=1
// ③ Session 建立 Request 映射
[CamX] [REQMAP] camxsession.cpp: chiFrameNum: 1 <==> requestId: 1
// ④ Pipeline 开始处理预览帧
[CamX] [CORE] camxpipeline.cpp: Pipeline::ProcessRequest() pipelineId=0 req=1
// ⑤ Node 处理(每帧都有)
[CamX] [CORE] camxnode.cpp: ProcessRequestResult() node=IFE req=1 processingTime=2.1ms
[CamX] [CORE] camxnode.cpp: ProcessRequestResult() node=IPE req=1 processingTime=1.8ms
// ⑥ 硬件处理完成(每帧都有,标记帧率)
[CamX] [CORE] camxpipeline.cpp: CSLMessageHandler() requestID=1, frameCount=1
// ⑦ 结果回调
[CHI] chxusecase.cpp: ProcessCaptureResult() requestId=1
// ========== 用户点击拍照按钮 ==========
// ⑧ 拍照请求进入
[CamX] [HAL] camxhal3entry.cpp: ProcessCaptureRequest() frame_number=50
// ⑨ 拍照请求通过 CHI
[CHI] chxusecase.cpp: SubmitChiRequest() frame_number=50
[CamX] [REQMAP] chiFrameNum: 100 <==> requestId: 50
// ⑩ Pipeline 0(RT,预览)和 Pipeline 1(Offline,JPEG)同时工作
[CamX] [CORE] camxpipeline.cpp: Pipeline::ProcessRequest() pipelineId=0 req=50
[CamX] [CORE] camxpipeline.cpp: Pipeline::ProcessRequest() pipelineId=1 req=50
// ⑪ Offline Pipeline 的 JPEG Node 开始编码
[CamX] [CORE] camxnode.cpp: ProcessRequestResult() node=JPEG req=50 processingTime=80ms
// ⑫ 拍照结果回调
[CHI] chxusecase.cpp: ProcessCaptureResult() requestId=50
日志断在 ① → App 没发起请求 / HAL3 入口有问题
日志断在 ③ → Session 映射失败
日志断在 ⑤ → Node 依赖一直不满足(死锁)
日志断在 ⑥ → HW 处理异常(requestID=0 → KMD 丢帧)
日志断在 ⑨ → CHI 层受理异常
日志断在 ⑩ → Offline Pipeline 没激活
日志断在 ⑪ → JPEG 编码异常(ProcessingTime 异常长或返回失败)
症状: 预览画面一卡一卡的,帧率不稳定
① 先看实际帧率
logcat 中搜 CSLMessageHandler,计算相邻帧的时间戳差
正常 30fps → 间隔 ~33ms
如果出现 66ms(15fps)或 99ms(10fps)→ 掉帧了
② 定位掉帧原因
开 dumpNodeProcessingInfo=1
看哪个 Node 的 processingTime 异常
如果 BPS 耗时突然从 3ms 跳到 15ms:
→ ISP 带宽不够 → 降低输出分辨率/减少 Stream
如果 Stats 耗时从 2ms 跳到 20ms:
→ Stats 处理过重 → 降低采样频率
③ 如果帧间隔稳定但用户觉得卡
→ 可能是 AE 在来回调整曝光(AE 振荡)
→ logcat 中搜 exposureTime,看是否在两个值之间反复跳
④ 如果暗光下卡,亮光下不卡
→ AE 曝光时间太长导致帧率下降
→ 检查 exposureTime 是否超过帧间隔
症状: 按了拍照按钮,拿到的 JPEG 是全黑的
排查:
① 先看 Raw Dump,确认 sensor 是否有输出
→ /data/vendor/camera/raw_*.raw
→ 如果 RAW 数据正常 → sensor 和 ISP 前端没问题
→ 如果 RAW 全黑 → sensor 没工作(查 power/MCLK/I2C)
② 再看 ISP Dump,看 ISP 处理后的 YUV
→ /data/vendor/camera/isp_*.yuv
→ 如果 YUV 正常 → JPEG 编码有问题
→ 如果 YUV 全黑 → ISP 配置有问题
③ 查 JPEG Node 的 processingTime
如果 processingTime=0 → JPEG Node 根本没执行
如果 processingTime 正常但输出全黑 → JPEG 编码参数问题
adb shell dumpsys media.camera > dump.txt
重点看三块:
Pipeline Info:
Status: STREAM_ON ← 正常
Status: STREAM_OFF ← Pipeline 意外关闭(检查 StreamOff 原因)
Node Info:
State: PROCESSING ← 正常
State: WAITING ← 在等依赖(看 waited 了多久)
ProcessingTime ← Node 处理耗时
Buffer Info:
Total: 4, InUse: 2, Free: 2 ← 正常
Total: 4, InUse: 4, Free: 0 ← Buffer 泄漏!
# Provider crash → 查 tombstone
adb shell ls /data/tombstones/
adb pull /data/tombstones/tombstone_XX
# App ANR → 查 traces
adb shell ls /data/anr/
adb pull /data/anr/traces.txt
# logcat 中搜
adb logcat -d | grep -E "CRASH|SIGSEGV|SIGABRT|tombstone|ANR"
# 完整的"案发现场"采集
adb logcat -v threadtime | grep -E "CamX|CHI|CSL|ERROR|FATAL" > camx_log.txt
adb shell dmesg > dmesg.txt
adb shell dumpsys media.camera > dumpsys.txt
adb shell ls /data/tombstones/
UMD 日志: adb logcat -s "[CamX]" ← 用户层
KMD 日志: dmesg | grep cam_sensor ← 内核层
UMD 控制: camxoverridesettings.txt + setprop
KMD 控制: /sys/module/cam_debug_util/parameters/debug_mdl
拍照流程 12 步日志链: 从入口到 JPEG 回调
预览卡顿排查: CSLMessageHandler 帧间隔 → Node ProcessingTime → AE exposureTime
黑屏排查: Raw Dump → ISP Dump → JPEG ProcessingTime
# 打开 CamX Core Info 日志,追踪一次拍照
adb shell setprop persist.vendor.camera.logInfoMask 0x1
adb logcat -c
# 拍一张照片
adb logcat -v threadtime | grep -E "CamX|CHI" > capture_trace.txt
# 在 capture_trace.txt 中找拍照流程的 12 步日志
adb shell setprop persist.vendor.camera.logInfoMask 0