第二章 开发环境搭建与调试工具链

做高通ISP调试,说白了就是两件事:把环境搭对,把工具用熟。我见过太多工程师,问题定位到一半发现log没开、raw图没dump、工具链版本不匹配——白白浪费一整天。这一章,我把这些年踩过的坑和积累的习惯一次性讲清楚。

2.1 高通QPST/QXDM:芯片调试的“听诊器”

QPST(Qualcomm Product Support Tool)和QXDM(Qualcomm eXtensible Diagnostic Monitor)是高通平台最底层的调试工具。我个人习惯把QPST比作“手术刀”,QXDM比作“听诊器”——一个用来改,一个用来听。

2.1.1 QPST核心功能

功能模块 用途 我常用的场景
EFS Explorer 浏览/修改手机文件系统 替换ISP tuning参数、校准文件
Software Download 烧录固件、分区镜像 刷不同版本的camera驱动
NV Browser 读写NV(Non-Volatile)项 修改sensor ID、EEPROM配置
Memory Debug 内存转储、寄存器读写 定位ISP pipeline hang死问题
⚠️ 避坑指南:我曾经在量产阶段用QPST的EFS Explorer直接修改了sensor校准文件,结果导致产线烧录后整批手机黑屏。后来才意识到——QPST操作的是运行时文件系统,重启后可能被覆盖。正确的做法是先dump出来,改完再通过fastboot刷回去。

2.1.2 QXDM日志抓取

QXDM是抓取高通芯片内部消息的利器。它不依赖Android系统,哪怕系统卡死在boot阶段,QXDM照样能抓到modem和DSP的log。

我一般这样配置:

  1. 手机进入Diag模式(通常拨号盘输入 *#*#717717#*#*)
  2. USB连接电脑,设备管理器出现“Qualcomm HS-USB Diagnostics”端口
  3. QXDM选择对应COM口,波特率设为921600(默认115200太慢,高帧率场景会丢log)
  4. 在View → Log窗口勾选 ISP、CAMERA、SENSOR 相关log mask
// QXDM常用过滤关键字(我自己的收藏)
ISP_ERR
CAMIF_ERROR
SENSOR_I2C_FAIL
CPP_HANG
IPE_TIMEOUT
💡 小技巧:QXDM的log可以实时导出为 .isf 文件。我习惯在复现问题前按一下“Clear”,问题复现后立刻“Save”——这样log文件小,定位快。别从头录到尾,否则一个4K视频流能生成几个GB的log。

2.2 CamX/Chi架构:理解ISP的“骨架”

CamX是高通从Android 9开始推的camera HAL架构,Chi(Camera Hardware Interface)是它的插件化扩展层。说白了,CamX是框架,Chi是积木。

2.2.1 架构分层

CamX/Chi 架构分层图 Android Camera App / Framework CamX HAL (Camera HAL3 实现) Chi (Camera Hardware Interface) 插件层 UMD (User Mode Driver) KMD (Kernel Mode Driver) ISP 硬件 (IFE / BPS / IPE / VPU / CPAS) CamX 负责流程调度,Chi 负责厂商自定义算法插件,UMD/KMD 负责硬件交互

2.2.2 关键文件与路径

调试时最常打交道的几个文件:

文件/路径 说明 调试价值
camxhal3.cpp CamX HAL3入口 看request流转、session创建
chi*.cpp Chi节点实现 定位vendor算法挂死
camxnode.cpp pipeline node基类 查node状态机异常
camxstats.cpp 3A统计信息 AE/AF/AWB异常排查
chi_oem.xml OEM定制配置文件 sensor/ISP tuning参数
🔑 核心理解:CamX的pipeline是异步流水线。每个node有自己的线程池,node之间通过buffer queue传递数据。如果你看到log里出现 Node::WaitForDependency 超时,八成是某个node处理太慢,堵住了下游。

2.3 ADB调试:最常用的“瑞士军刀”

ADB(Android Debug Bridge)大家都会用,但ISP调试有它特殊的用法。我总结了一套“三板斧”:

2.3.1 三板斧之一:dumpsys camera

# 查看camera服务状态
adb shell dumpsys camera

# 只看某个cameraId的session信息
adb shell dumpsys camera | grep -A 50 "Camera 0"

# 查看stream配置
adb shell dumpsys camera | grep -E "Stream|Format|Size|Usage"

这个命令能告诉你:当前有几个session、每个session的stream配置、buffer状态、pending request数量。我遇到“拍照黑屏”问题时,第一件事就是跑这个命令,看stream有没有成功创建。

2.3.2 三板斧之二:setprop 控制开关

# 开启CamX详细log(我调试必开)
adb shell setprop persist.vendor.camera.logs 0x1F

# 开启Chi log
adb shell setprop persist.vendor.camera.chi.logs 0x1F

# 强制dump每一帧的raw图(调试HDR合成时用过)
adb shell setprop persist.vendor.camera.rawDump 1

# 关闭3A,固定曝光(测sensor线性度)
adb shell setprop persist.vendor.camera.3A.disable 1
⚠️ 注意:persist. 开头的属性重启后仍然生效。我曾经在客户现场开了rawDump忘记关,结果手机用半天就提示存储空间不足——raw图一张几十MB,拍4K视频每秒就写几百MB。调试完记得 adb shell setprop persist.vendor.camera.rawDump 0。

2.3.3 三板斧之三:tombstone 与 crash 分析

# 抓取camera service crash的tombstone
adb pull /data/tombstones/

# 查看camera provider的crash log
adb logcat -b crash | grep -i camera

# 查看native crash的backtrace
adb shell dmesg | grep -i "camera\|ISP"

我遇到过一种情况:camera app闪退,但logcat里没有任何error。后来查tombstone才发现是Chi node里一个空指针——vendor算法传了个null buffer进来。这种问题,光看logcat是看不出来的。

2.4 dump raw图:ISP调试的“X光片”

raw图是sensor输出的原始数据,没经过ISP任何处理。看raw图就像医生看X光片——能直接看到sensor本身的问题,还是ISP处理的问题。

2.4.1 如何dump raw图

方法一:通过ADB命令(最常用)

# 开启raw dump
adb shell setprop persist.vendor.camera.rawDump 1

# 拍照或录像,raw图会保存在 /data/vendor/camera/raw/
adb shell ls /data/vendor/camera/raw/

# 拉取到电脑
adb pull /data/vendor/camera/raw/ ./raw_dump/

方法二:通过QXDM的Memory Debug窗口,直接读取ISP寄存器中的raw buffer地址。这个方法适合抓某一帧的raw,不影响正常流程。

2.4.2 raw图分析工具

工具 用途 我的评价
RAW2RGB(高通官方) 将raw转为可预览的RGB图 简单快速,但只能看个大概
dcraw / libraw 命令行raw解析 适合批量处理,脚本化分析
Python + numpy 自定义分析(坏点、噪声、线性度) 我最常用的方式,灵活
MATLAB Image Toolbox 专业图像质量分析 做IQ报告时用,太重
💡 经验之谈:看raw图时,我习惯先看暗场(镜头盖住拍一张)和亮场(对着均匀光源拍一张)。暗场能看出sensor的暗电流和固定噪声,亮场能看出bayer pattern是否正常、有没有坏列。这两个看完了,再分析具体场景。

2.5 logcat抓取ISP日志:定位问题的“第一现场”

logcat是Android最直接的日志输出通道。但ISP相关的log默认是关闭的——因为太频繁了,一秒钟几百条,开了手机会卡。

2.5.1 开启ISP log的正确姿势

# 1. 开启所有camera相关log(级别从低到高)
adb shell setprop persist.vendor.camera.logs 0x1F

# 2. 重启camera provider(不用重启手机)
adb shell killall cameraserver

# 3. 抓取过滤后的log
adb logcat -v threadtime | grep -E "camx|chi|ISP|Sensor" > isp_log.txt

log级别定义(0x1F = 全部开启):

Bit位 级别 内容
Bit 0 Error 致命错误,必须看
Bit 1 Warning 潜在问题,建议看
Bit 2 Info 关键流程信息
Bit 3 Verbose 详细调试信息(慎开)
Bit 4 Perf 性能统计

2.5.2 常见log模式与解读

我总结了几种典型的log模式,看到就能猜个八九不离十:

  • 反复出现 Flush / Abort → 大概率是app端反复打开关闭camera,检查app逻辑
  • Node::WaitForDependency 超时 → 某个node处理太慢,查对应node的算法耗时
  • Buffer underrun → ISP的输入buffer不够,检查sensor输出帧率
  • I2C transfer failed → sensor寄存器读写失败,查硬件连接或sensor驱动
  • HAL: configureStreams failed → stream配置不合法,查分辨率/格式组合
🔑 我的习惯:每次开始调试前,先开一个终端专门跑 adb logcat -v threadtime | grep -E "camx|chi" > camx_$(date +%Y%m%d_%H%M%S).log,然后才去复现问题。这样log文件带时间戳,方便回溯。调试完立刻关掉,别让log一直写——我吃过手机存储写满的亏。

2.6 本章小结

工具链这东西,光看文档是学不会的。你得亲手搭一遍环境,亲手抓一次log,亲手看一张raw图,才能理解每个工具在什么场景下用。我建议你:

  • 找一台高通平台的手机,按本章步骤把QPST/QXDM连上
  • 在CamX代码里加几行自己的log,编译烧录,看能不能抓到
  • 拍一张raw图,用Python读出来,看看bayer pattern长什么样