Qcom Camx全栈开发

Android Camera 全栈课程(Qcom Camx):第 3 章:开发环境与调试基础

本章导读

前面两章讲了"相机怎么成像"和"系统怎么分层"。但从这章开始,你要动手了

做 Camera 开发和普通 App 开发最大的区别是:你不能只靠 logcat 活着。 你需要看懂源码目录结构、熟练使用 Source Insight 跳转(VS code也是不错的工具,看个人喜好)、会用 dumpsys 查看内部状态、懂得用 setprop 控制调试开关等。

这章就是你的工具箱——不要求一次记住所有命令,但要知道"遇到问题时去哪找答案"。


3.1 源码目录结构

3-camera结构.png

CamX-CHI 源码根目录下,你会看到 3 个顶层目录:

纯文本

camx_chi_root/
  ├── camx/               CamX 核心层(高通官方,OEM 一般不修改)
  ├── chi-cdk/            CHI 定制层(OEM 主要修改的地方)
  └── camera-devicetree/  设备树配置(dtsi 文件)

3.1.1 camx/ — 核心 HAL

这是 CamX 的主体代码。你需要重点掌握其中几个子目录:

纯文本

camx/src/
├── core/           ★★★★★ 你花时间最多的地方
│   ├── camxsession.h      Session 定义
│   ├── camxpipeline.h     Pipeline 定义 + 状态机
│   ├── camxnode.h         Node 定义 + DependencyUnit
│   ├── hal/               HAL3 接口适配层
│   │   ├── camxhal3entry.cpp     HAL3 入口函数
│   │   ├── camxhaldevice.cpp     camera3_device_t 实现
│   │   └── camxhal3module.cpp    HAL_MODULE_INFO_SYM
│   └── chi/               ChiContext(全局上下文)

├── hwl/            ★★★★ 硬件封装层
│   ├── ife/               IFE Node 实现
│   ├── bps/               BPS Node 实现
│   ├── ipe/               IPE Node 实现
│   └── titan17x/          Titan ISP 寄存器抽象

├── swl/            ★★★ 软件算法层
│   ├── eisv3/             EIS 电子防抖
│   ├── jpeg/              软件 JPEG 编码
│   └── stats/             3A 统计处理

├── csl/            ★★★ Camera Services Layer
│   └── common/            CSLSubmit / CSLFenceSignaled

└── settings/
    └── kona/              SM8250 平台配置(camxoverridesettings.txt)

最优先读的 3 个文件

文件

为什么优先读

camxsession.h

核心数据结构,理解 PipelineInfo/LinkInfo/PortInfo/NodeInfo

camxpipeline.h

Pipeline 状态机,8 个状态的枚举定义

camxnode.h

DependencyUnit,理解 Node 之间的依赖机制

3.1.2 chi-cdk/ — OEM 定制层

纯文本

chi-cdk/
├── core/
│   ├── chiframework/     ★★★★★  框架层
│   │   ├── chxusecase.h         Usecase 基类 + UsecaseSelector
│   │   ├── chxsession.h         CHI Session 封装
│   │   └── chxpipeline.h        CHI Pipeline 封装
│   ├── chifeature2/      ★★★★    Feature2 框架
│   │   └── chifeature2graph.h   Feature Graph 数据结构
│   └── chiusecase/       ★★★     Usecase 实现
│       └── chxusecasedefault.h   默认 Usecase
├── api/                 API 头文件(node/isp/sensor/stats)
├── configs/              XML 配置文件
└── oem/qcom/             OEM 定制示例

理解 camx/ 和 chi-cdk/ 的区别

纯文本

camx/     = 核心引擎 —— 高通维护,一般不修改
chi-cdk/  = 定制框架 —— OEM 在此做 customization

3.2 Source Insight 配置

读这类大型 C++ 源码,Source Insight 是最好的工具。它比 VS Code 在符号索引上快得多。

建立工程

纯文本

Project → New Project
  工程名: camx_chi_source
  源码路径: <你的 CamX-CHI 源码根目录>

添加文件

纯文本

Project → Add and Remove Project Files
  勾选:
    ✓ camx/src/**/*.h
    ✓ camx/src/**/*.cpp
    ✓ chi-cdk/core/**/*.h
    ✓ chi-cdk/core/**/*.cpp

需要记住的快捷键

操作

快捷键

什么时候用

搜索符号

Ctrl + /

找类/函数/变量的定义

跳转到定义

Ctrl + 点击

看到函数名 → 想看实现

查找引用

Ctrl + / → References

想看谁调了这个函数

向后/向前导航

Alt + , / .

跳转了之后想回去

搜索文件

Ctrl + O

想快速打开已知文件名的文件

核心搜索关键词

你在源码中搜索最多的词应该就是这些:

纯文本

Session::ProcessCaptureRequest     → 请求入口
Pipeline::ProcessRequest           → Pipeline 处理
Node::ProcessRequest               → Node 处理
DependencyUnit                     → 依赖机制
CSLMessageHandler                  → 硬件完成回调
UsecaseSelector::Select            → Usecase 选择
ChiFeature2GraphDesc               → Feature2 Graph 结构
InitializeStaticMetadataPool       → Static Metadata 构建

3.3 logcat — 你的第一诊断工具

CamX 日志标签

logcat 标签

来自哪

什么时候看

[CamX]

CamX 核心

任何时候——查看 Session/Pipeline/Node 状态

[CHI]

CHI 层

Usecase/Feature2 相关的问题

[CSL]

CSL 层

怀疑 HAL↔Kernel 通信有问题时

[EISV3]

EIS 算法

防抖效果不对时

[SWMCTF]

多帧融合

MFNR/HDR 处理异常时

常用过滤命令

纯文本

# 只看 CamX 核心日志
adb logcat | grep "\[CamX\]"

# 看 CamX + CHI
adb logcat -v threadtime | grep -E "\[CamX\]|CHI"

# 带完整信息保存到文件
adb logcat -v threadtime | grep -E "\[CamX\]|CHI|CSL|ERROR|FATAL" > camx_log.txt

# 实时监控帧率
adb logcat | grep "\[CamX\]" | grep "frameMessage:requestID"

三条最重要的日志

① 硬件完成回调

纯文本

[CamX] [CORE] camxpipeline.cpp: CSLMessageHandler()
    frameMessage:requestID=42, frameCount=37, timestamp=265793404062

这是最重要的日志——它告诉你硬件处理完成了一帧。requestID 关联回 App 的 Request,frameCount 是 Sensor 的物理帧序号,相邻两条日志的 timestamp 差就是帧间隔。

② Request 映射

纯文本

[CamX] [REQMAP] camxsession.cpp: ProcessRequest()
    chiFrameNum: 287 <==> requestId: 42

CHI 内部的帧号和 App 侧的 Request ID 的对应关系。调试时经常需要从 App 的 Request ID 反查 CHI 帧号。

③ Node 处理时间

纯文本

[CamX] [CORE] camxnode.cpp: ProcessRequestResult()
    node=IFE req=42 processingTime=2.1ms

如果帧率不稳,先看这个——看哪个 Node 耗时最长。


3.4 dumpsys — 查看相机内部状态

dumpsys media.camera 是最强大的运行时诊断工具。它告诉你 CameraService 当前知道什么。

纯文本

# 完整输出
adb shell dumpsys media.camera > camera_dump.txt

# 只看摄像头列表
adb shell dumpsys media.camera | grep -E "Camera ID|Facing|Orientation"

# 看当前 Activate 的 Session
adb shell dumpsys media.camera | grep -A 20 "Active Sessions"

# 看 Stream 配置
adb shell dumpsys media.camera | grep -A 10 "Stream"

从 dumpsys 中能读到什么

纯文本

Camera ID: 0
  Facing: BACK
  Orientation: 90°
  支持的输出大小:
    - 4032x3024 (12MP JPEG)
    - 1920x1080 (1080p YUV)
    - 1280x720  (720p PRIVATE)
  FPS 范围: [15, 30]
  是否支持 RAW: yes

什么时候用 dumpsys?

  • 怀疑 CameraService 没有正确识别摄像头 → 看 Camera ID 列表

  • 怀疑 facing/orientation 配错了 → 看 Facing/Orientation 字段

  • 想确认设备支持哪些分辨率 → 看输出大小列表

  • 想确认 Stream 有没有被正确配置 → 看 Stream 信息


3.5 setprop — 调试开关

大部分 CamX 的调试功能通过 setprop 控制。

纯文本

# === 日志等级 ===
# 设置 overrideLogLevels(0x1F=ERROR~VERBOSE)
adb shell setprop persist.vendor.camera.logs.override 0x1F

# === 数据 dump(通过 camxoverridesettings.txt 控制)===
# 图像 dump:在 camxoverridesettings.txt 中设置 dumpOutput 相关开关
# 具体由 CamX Node 中的 ImageDump::Dump() 实现

# EEPROM dump(OTP 校准数据)
adb shell setprop vendor.debug.camera.dumpSensorEEPROMData TRUE

# === 帧率 ===
# 开启实时帧率日志
adb shell setprop persist.vendor.camera.enableFPSLog 1

persist. vs vendor. 的区别

  • persist. 开头的属性重启后保留

  • vendor. 开头的属性重启后丢失

  • 部分属性需要 setenforce 0(关 SELinux)才生效


3.6 camxoverridesettings.txt

这是 CamX 的配置文件,修改后可以控制运行时行为。

位置:camx/src/settings/kona/ 或设备上 /vendor/etc/camera/

纯文本

# 常用配置项

# 日志等级(最常用)
overrideLogLevels=0x1F

# EIS 配置
EISV2Enable=1
EISV3Enable=2

# 帧率日志
enableFPSLog=1

# Node 处理时间
dumpNodeProcessingInfo=1

# 启动时 dump EEPROM
dumpSensorEEPROMData=1

推送并生效

纯文本

adb root
adb remount
adb push camxoverridesettings.txt /vendor/etc/camera/
adb shell chmod 644 /vendor/etc/camera/camxoverridesettings.txt
adb shell killall -9 vendor.camera-provider-2-4

3.7 实操:采集一次完整的调试信息

这应该是你接手一个 Camera 问题时的标准操作流程:

纯文本

# 第一步:清空 logcat 缓存
adb logcat -c

# 第二步:开启 CamX 详细日志
adb shell setprop persist.vendor.camera.logs.override 0x1F
adb shell setprop persist.vendor.camera.enableFPSLog 1

# 第三步:抓 logcat(同时操作相机)
adb logcat -v threadtime | grep -E "CamX|CHI|CSL|ERROR|FATAL" > camx_log.txt

# 第四步:操作完成后,跑 dumpsys
adb shell dumpsys media.camera > camera_dump.txt

# 第五步:查看系统日志
adb shell dmesg > dmesg.txt

有了这 3 个文件(camx_log.txtcamera_dump.txtdmesg.txt),大部分问题都能定位。


3.8 第 3 章总结

纯文本

工具清单
──────────────────────────────────
源码阅读:  Source Insight + Ctrl+/ 搜索
日志查看:  adb logcat | grep "\[CamX\]" 过滤
状态诊断:  adb shell dumpsys media.camera
调试开关:  adb shell setprop persist.vendor.camera.*
配置文件:  camxoverridesettings.txt
──────────────────────────────────

这些工具会贯穿整个课程。后续每一章在讲完原理后,都会用这些工具做实操验证


动手验证

目标:独立完成一次完整的"相机状态采集"操作。

  1. 在 Source Insight 中建立 CamX-CHI 源码工程,添加 camx/src/core/ 和 chi-cdk/core/ 目录。

  2. 搜索以下符号,确认你能找到它们的定义位置:

    • class Session

    • PipelineStatus

    • DependencyUnit

    • UsecaseSelector

  3. 连接设备,执行本章 3.7 节的"采集一次完整的调试信息"操作。把采集到的三个文件(logcat、dumpsys、dmesg)保存下来——后续章节的动手验证会反复用到。


篇末实战:采集完整的相机状态报告

目标:独立完成一次完整的相机信息采集,形成一份"相机状态报告"。

步骤 1:环境准备

纯文本

adb devices
adb logcat -c

步骤 2:采集相机静态信息

纯文本

adb shell dumpsys media.camera > camera_static_info.txt

从 camera_static_info.txt 中提取并记录:

  • 有几个摄像头?ID 分别是什么?

  • 后摄的 facing / orientation 是多少?

  • 后摄支持哪些输出格式?(JPEG / YUV / RAW / PRIVATE)

  • 后摄 JPEG 最大分辨率?YUV 最大分辨率?

  • 支持哪些 FPS 范围?

  • 最短和最长曝光时间?ISO 范围?

  • 是否支持 RAW 输出?

步骤 3:采集运行时信息

纯文本

adb shell setprop persist.vendor.camera.logs.override 0x1F
# 打开相机 App,等 5 秒,关闭
adb logcat -v threadtime -d | grep -E "CamX|CHI|CSL|ERROR" > camera_runtime_log.txt

步骤 4:分析日志

  • 第一条 ProcessCaptureRequest 日志(请求入口)

  • 第一条 CSLMessageHandler 日志(硬件完成第一帧)

  • 计算从入口到第一帧的时间差

  • 找两条相邻的 CSLMessageHandler,计算帧间隔 → 实际帧率

  • 有没有 ERROR 级别的日志?

步骤 5:写报告

整理一份"相机状态报告",包含:设备基本情况、启动延迟、当前帧率、发现的问题。

常见误解

  • "logcat 就能解决一切问题" — logcat 只能看到 HAL 及以上层。Kernel 驱动层的问题在 dmesg 里,ISP 硬件问题不在任何日志里(需要 Raw /YUV Dump)。

  • "setprop 改了立刻生效" — 大部分 setprop 需要在相机下一次打开时才生效。部分需要 setenforce 0

(课程相关内容,会陆续在下面专栏更新,感兴趣的同学可以扫码订阅)

图片

欢迎扫码关注「小驰行动派」公众号 10 年Camera开发 | Camera技术干货 | 行业洞察 | Camera实战分享
小驰行动派公众号 扫一扫关注
分享到: 复制链接
← 上一篇 纯小白教程 | 10分钟,在Vs Code中接入Claude Code,使用Deepseek API 下一篇 → Android Camera 全栈课程(Qcom Camx):第 2 章:Android Camera 系统全景

相关文章

推荐课程

想系统学习 Camera 开发?看看这些课程

评论 (0)

暂无评论,快来抢沙发吧