导读:你在车机上用 Camera2 打开一路相机——背后就是高通的 CamX-CHI 吗?在车载上,**答案是"不一定"**。手机相机只有一条路,车载有两条:座舱应用相机走
Camera2 → CamX-CHI,而倒车 / 环视 / DMS 这些车规相机走的是另一套QCarCam / AIS。这一篇讲透 A 线的 HAL 实现 CamX-CHI(CHI 出图纸、core 造流水线),并把两条路的边界、以及"走 Camera2 ≠ 走 CamX-CHI"这个最容易搞错的点讲清——它也是整个系列的枢纽。
阅读前提
系列内:承接第4篇《CameraService 深入》——第4篇讲到 CameraService 把请求交给 Camera Provider、再往下就是"厂商各自的 HAL 实现"便停住了。本篇从这条 HAL 边界往下走,看高通怎么实现(CamX-CHI);同时,它是整个系列的枢纽——把前面几篇讲的"Android 相机栈"放回车载的正确位置,并引出车载真正的另一条路。 系列外:需要一点 HAL(硬件抽象层)、Camera2(Android 应用侧相机 API)、GMSL(车载长距离串行相机接口)、以及"进程内动态库 .so"的概念——不熟悉时按字面理解即可。
开篇:一个容易搞错的定位问题
你在车机上用 Android 的 Camera2 API 打开一路相机——它背后就是高通的 CamX-CHI 吗?
多数人会答"是"。但在车载上,**答案是"不一定"**。这个"不一定",正是本系列前几篇一直没讲清、而车载行业的人一眼就会质疑的地方。要讲清它,得先承认一件事:
手机相机只有一条路,车载相机有两条。
一、全局:高通平台上,相机有两条路
先看全局。在高通车载平台上,一路相机画面到达应用,可能走两条完全不同的软件栈:
路径 A —— Android 相机栈(座舱应用相机)
Android 应用(Camera2 / CameraX)
→ CameraService(第4篇)
→ Camera Provider(AIDL)
→ 厂商 HAL = CamX-CHI ← 本篇主体
→ 内核驱动 → Spectra ISP
这就是手机上的那一套,AAOS(车载版 Android)沿用并做了车载扩展。它面向座舱里"像手机一样"的相机应用——视频通话、乘客自拍、拍照录像、扫码。
路径 B —— 车载专用相机栈(安全 / 环视 / 监测相机)
应用 / 中间件(QCarCam API 或 EVS)
→ AIS(Automotive Imaging System:ais_server + ais_client)
→ 内核驱动 → ISP
这是高通(QCarCam/AIS)和 Google(EVS)专门为"车"做的一套,独立于 Android 应用框架。它服务的是 RVC 倒车、AVM 环视、DMS 驾驶员监测、OMS 乘员监测、ADAS 感知——这些安全、早启动、多路常开的车载核心相机。
车载多出 B 这条路的原因
Android 这套(A)无法满足车载相机的几个硬性需求,于是有了 B:
早启动:法规要求挂挡后极短时间内出倒车影像(AAOS 官方目标是开机 2 秒内),而车机从上电到 Android 完整框架起来、相机可用,动辄十几秒甚至更久,远够不上 2 秒——A 这条路来不及。B 必须能独立于、早于 Android 出图。 功能安全:倒车、ADAS 是安全件,不能只依赖"可能崩溃重启"的 Android 应用栈。 跨 OS / 双域:车载常是 QNX(安全域)+ Android(座舱) 双系统跑在 Hypervisor 上,安全相机要能跨域,不能受限于 Android。 GMSL 长线束、多路常开:车上摄像头分布全车、经 GMSL 串行解串长线束接入、多路同时开——需要专门的采集与资源仲裁框架( ais_server)。
关键纠偏:走 Camera2 ≠ 走 CamX-CHI
这是车载开发者最容易混淆的一处,也是本系列前几篇欠读者的一句话:
Camera2 只是 Android 应用能用的"标准 API 表面"。 在车载上,一个 app 调 Camera2,它背后可能是:
真 CamX-CHI——当相机是"手机式" MIPI 直连时; 一层"把 AIS 相机桥接成 Camera2"的 HAL 垫片——GMSL 相机的常见做法,app 用着 Camera2,后端其实是 AIS,不是 CamX-CHI。
所以判断一颗车载相机走哪条,**最准的维度不是"app 用了什么 API",而是"相机怎么接进来、要满足什么需求"**:
要早启动 / 功能安全 / GMSL 多路 → B(QCarCam/AIS/EVS) 座舱里像手机一样的应用相机 / MIPI 直连 → A(Camera2/CamX-CHI)

手机相机只有 A 这一条;车载 A、B 都有。本篇讲透 A 这条的 HAL 实现——CamX-CHI(也就是第4篇停下的那个"厂商 HAL");B 这条(QCarCam/AIS/EVS)是车载真正的主路径,留给后面几篇。
关于深度与依据:CamX-CHI 的核心(
camera.qcom.so/com.qti.chi.override.so)是闭源的,高通以预编译库交付,源码级实现拿不到。本篇讲它的架构与设计——依据高通公开文档、一份高通专利(US10613870B2)与 AOSP,落到接口/组件/数据流这一级;不涉及函数实现,也不碰任何厂商私有的 sensor 连法、tuning、自研节点。B 路径的结论则区分了官方/二手来源,链接见文末。
二、CamX-CHI 是什么:Google 定接口,高通做实现
顺着路径 A 往下走,过了 Camera Provider 这道 HAL 边界,就进了 CamX-CHI。先厘清一个常被搞错的定位——也回答"CamX-CHI 是不是 Google 的相机框架":不是。HAL 边界上的接口是 Google 定的,实现是各家厂商自己做的。
Google 定义 Camera HAL3 接口( camera3_device_ops:configure_streams、process_capture_request、process_capture_result等)——一份规范,规定 framework 怎么调 HAL、传什么、回什么,但不管 HAL 内部怎么实现。高通对这个接口的实现,就是 CamX-CHI。换个 SoC 厂商是另一套:联发科有 MTK 的实现,三星 Exynos 有自己的——它们都插在同一个 HAL3 插槽上。
一个反常识的细节:在高通平台上查看 cameraserver 加载的库,会发现相机 HAL 不是一个 .so,而是两个:camera.qcom.so(CamX core)与 com.qti.chi.override.so(CHI override)。而且 OEM 做相机定制时,往往只替换后面那个,前面那个原封不动。为什么拆两个、为什么只换一个——这正是下一节要讲的核心。先看 CamX-CHI 在路径 A 里的内部构成:

一个常见误解:Android 13 起 Camera HAL 接口 AIDL 化,容易让人以为"高通换了新 HAL 架构、CamX 被取代了"。其实 AIDL 化只发生在 Camera Provider 那一层(framework ↔ provider 的 IPC 由 HIDL 换成 AIDL);Provider 之下,高通实现的仍是传统 HAL3 device 接口,仍是 CamX-CHI。变的是外面那层 IPC 形态,没变的是里面这套实现。
CamX-CHI 是高通对 Google Camera HAL3 的实现,分 camera.qcom.so(CamX core)和 com.qti.chi.override.so(CHI override)两个库。它是路径 A 的最后一层。
三、CHI 与 core:设计与实现的切分
CamX-CHI 内部这两层,是理解它的钥匙。分工可以一句话概括:CHI 负责"设计",core 负责"实现"。
CHI override(策略层, com.qti.chi.override.so):决定这次用哪套 usecase、这条流水线由哪些处理单元(node)组成、怎么连(topology)——出图纸。CamX core(执行层, camera.qcom.so):提供 node/pipeline 的真实代码和执行引擎,按图纸把流水线构建起来、驱动运行、经驱动下到硬件——照图纸落地执行。
三方角色:Google、高通、OEM
这里有个极易混淆的点:CHI 和 core 都是高通写的,不是谁的定制。这套东西涉及三方:
camera3_device_ops | ||
| 高通(SoC 厂商) | ||
| OEM(车厂/手机厂) |
所以 core 和 CHI 都是高通交付的 HAL 实现;它俩的真正区别**不是"谁写的",而是"能不能被 OEM 覆写"**:
| CamX core | 否 | ||
| CHI override | 是 |
"OEM 定制只换 com.qti.chi.override.so、不动 camera.qcom.so"——就是这个意思:改可覆写的 CHI,不动稳定的 core。
这么切分带来的三个好处
Google 的 HAL3 接口是"隐式"的:应用提交一个请求,至于 HAL 内部把它拆成几条流、走哪个 ISP 引擎、要不要多帧合成——全由厂商在内部黑盒决定。高通做的事,是把这块黑盒里"怎么组 pipeline、选哪个引擎、多帧怎么控"的决策,从 core 里抽出来、显式化成一个可覆写的 CHI 层。高通官方对 CHI 的定位原文正是:CHI override 模块"supplements the Google HAL3 interface",提供"explicit image processing pipeline generation, explicit engine selection, and multiframe control"。
这么切分,带来三个实际的好处:
一套 core 适配所有芯片和客户:不同 OEM、不同产品要的成像效果千差万别,但底层的 node 执行引擎、调度、buffer 管理是通用的。core 稳定不动,差异全下沉到 CHI——高通不用为每个客户改 core。 OEM 不改动底层引擎就能定制:车厂想加一套自己的成像 usecase、调 topology,只需改 CHI override 或它读的 XML,无需改动、也无法改动闭源的 core。风险小、维护清晰。 core 能独立升级:高通升级 core(修 bug、加能力),不会影响 OEM 在 CHI 层的定制;反过来 OEM 换 CHI,也不动 core。两层解耦,各自演进。
工程上,这两层用"两个 .so 双向 dlopen + 操作跳转表"对接:HAL3 初始化时 core 调 chi_hal_override_entry(),CHI 把自己的函数接口指针交回给 core(官方原文"return function interface pointers");core 也把自身能力(造 node、建 pipeline 的接口)通过跳转表交给 CHI。换掉 override 那个 .so,就换掉整套策略,而 core 二进制不动。
那么"CHI 出图纸、core 造流水线"具体怎么发生?看这张创建流程:

CHI 出图纸(选 usecase、定 topology),core 按图纸用自己的零件把流水线构建、运行起来。core 稳定通用、CHI 可被 OEM 覆写——这道切分,就是 CamX-CHI 整个架构的核心设计。
四、一个请求的路径:从 Camera2 到硬件出帧
把路径 A 的一个具体场景走一遍:座舱里一个 Android 相机应用(比如车内视频通话)打开预览。看你写的每行 Camera2,对应 HAL 里发生了什么——用你熟悉的 Camera2 当锚点,最容易看懂 CamX-CHI。
先给对照表(app 侧是 Google 公开的 Camera2 API,HAL3 回调是 Google 定义,CHI 入口名来自高通官方时序图):
CameraManager.openCamera | initialize | camera.qcom.so,core 调 chi_hal_override_entry 与 CHI 握手 |
createCaptureRequest(TEMPLATE_PREVIEW) | construct_default_request_settings | |
createCaptureSession | configure_streams | core 请 CHI 选 usecase、建 pipeline/topologychi_initialize_override_session) |
setRepeatingRequest | process_capture_request | |
CaptureCallback.onCaptureCompleted | process_capture_result |
一句话映射:openCamera=握手 | createCaptureSession=选 usecase、建流水线 | setRepeatingRequest=执行出帧 | onCaptureCompleted=结果回传。
画成时序图(注意主从:framework 只和 CamX core 打交道,core 再去调 CHI):

一步步看:
** openCamera**:app 打开相机。请求经 framework、Provider 落到 CamX core(它实现 HAL3 入口),core 加载 CHI、通过chi_hal_override_entry与它握手,两个.so互取接口。createCaptureSession:app 声明"我要这路预览输出流"。这触发 HAL3 的configure_streams——关键一步在这里:core 请 CHI(chi_initialize_override_session),CHI 的 UsecaseSelector 选出预览 usecase、定好 topology(比如IFE → IPE这一条),再借 core 的能力把 Session/Pipeline/Node 建好。流水线在这一步就建好,不是每帧重建。** setRepeatingRequest**:app 提交重复请求(预览连续出帧)。之后每个显示周期,core 把请求送入已建好的 pipeline,调度各 Node,经 CSL submit 到内核。硬件出帧:内核驱动配置 sensor 与 ISP,硬件按 topology 流转(预览这类的 topology,硬件上就是 IFE → IPE这条通路)。结果回传:硬件完成经 fence 通知,core 逐级回收结果 → 通知 CHI → process_capture_result把结果帧和 metadata 交回 framework,app 的onCaptureCompleted被调用,预览显示出来。
如果想看接口级怎么落地(下面是按官方入口名 + 公开机制画的职责示意,不是 CamX 真实源码——core/CHI 闭源):
// —— 职责示意,非 CamX 真实源码 ——
// core 侧:configure_streams 落到 CamX core(core 实现 HAL3)
intconfigure_streams(camera3_stream_configuration* cfg){
// core 委托 CHI 决策,并把"自己的能力"交给它
return chi_initialize_override_session(cfg, &g_chiContextOps); // core → CHI
}
// CHI 侧:设计 topology,再借 core 的能力实例化
Session* chi_initialize_override_session(cfg, CoreOps* coreOps){
UsecaseId id = UsecaseSelector::select(cfg); // CHI 设计:选 usecase(预览)
Topology topo = buildTopology(id); // CHI 设计:要 IFE→IPE 两个 node、怎么连
Pipeline* p = coreOps->CreatePipeline(topo); // core 实现:造 node、组装 pipeline
return coreOps->CreateSession(p); // core 实现:建 session
}
这条链最关键的两跳都在 CHI:第 2 步"选哪套 usecase""建哪张 topology"——正是那道 override 缝被显式化的位置。core 只在其后忠实地调度执行。归纳一句:入口与执行在 core,决策在 CHI。
五、边界与对号入座
把两条路径的边界厘清。核心划分维度是"相机怎么接进来",不是"哪种相机"或"app 用了什么 API":
| A:Camera2 → CamX-CHI | |||
| B:QCarCam/AIS | |||
| B:QCarCam/AIS | |||
| B:QCarCam/AIS | |||
几个不能写成绝对、必须留余地的点:
不要说"车载相机不经 CamX":AIS 做 ISP 处理时可选复用 CamX/Spectra(有编译开关 USE_IMAGING_AIS/AIS_BUILD_CAMX为证)。准确说法是"车规相机不以 Camera2→CamX-CHI 这条 HAL3 链为主路径",但底层 ISP 硬件仍可能是那套。AIS 与 CamX 是"独立通路 + 可选复用"的关系,不是谁替代谁。
判断一颗车载相机走哪条,不要只看 app 用了 Camera2 还是 QCarCam——要看它怎么接进来、要满足什么需求:要早启动/功能安全/GMSL 多路的,走 B;座舱里 MIPI 直连、像手机一样的应用相机,走 A。
小结
两条路:手机相机只有 A(Android 栈);车载 A、B 都有——A 是座舱 Android 应用相机(Camera2→CamX-CHI),B 是车载专用相机栈(QCarCam/AIS/EVS,服务 RVC/AVM/DMS/ADAS)。 本篇是 A 的 HAL:CamX-CHI 是高通对 Google HAL3 的实现, camera.qcom.so(core)+com.qti.chi.override.so(CHI)两层。核心设计:CHI 出图纸(选 usecase/定 topology)、core 造流水线(实现/执行);core 稳定通用、CHI 可被 OEM 覆写——一套 core 适配所有芯片和客户,OEM 不改动引擎就能定制。 三方区分:core、CHI 都是高通写的;OEM 只在 CHI 层定制。 纠偏:走 Camera2 ≠ 走 CamX-CHI(后端可能是 AIS 桥接);判断走哪条看相机怎么接入。
一句判断:不要把手机的"一条路"套到车载。 车载相机是两条路并行——想清楚你面对的相机走哪条,是做车载相机开发的第一步。而这两条路里,车载真正的主角其实是 B。
至于 B 这条——QCarCam/AIS 到底怎么让倒车画面在 Android 起来之前就出图、怎么跨 QNX 与 Android 双域、怎么管理全车多路 GMSL 相机,下一篇正式打开。
参考资料
CamX architecture(129_CamX)— Qualcomm 官方:CamX = camx + chicdk 两层、软件分层图。 CHI(126_CHI)— Qualcomm 官方:CHI override 定位、"supplements the Google HAL3 interface"原文。 CHI architecture model(127)— Qualcomm 官方:CHI 初始化 UML 时序图与官方入口名( chi_hal_override_entry等)。Qualcomm Spectra 480(124)— Qualcomm 官方:IFE / IPE / BPS 数据通路。 Qualcomm 专利 US10613870B2:Node / Topology(DAG) / Session / Pipeline / Usecase 的一手定义。 Android Camera HAL3 / AIDL — source.android.com:HAL3 接口与 Android 13 起的 AIDL 化范围。 Vehicle Camera HAL / EVS — source.android.com:车载 EVS、早启动(开机 2 秒内出图)、倒车/环视用 EVS 的官方说明。 Camera2 API — developer.android.com: CameraManager/CameraDevice/CameraCaptureSession等 app 侧接口。路径 B(QCarCam/AIS)的具体划分依据多为二手/逆向来源,详见下一篇专篇梳理。
如果觉得有帮助,欢迎点赞、在看、转发三连。
这是《车载Camera·软件栈》系列第 5 篇。如果你在做车载摄像头、Android / QNX 相机开发,欢迎关注追更。
系列导航:《车载Camera·软件栈》讲应用层如何拿到摄像头画面、软件栈如何分层;另一个系列《车载Camera·技术全栈》讲一帧数据怎么流(硬件 → 驱动 → 框架 → 跨 VM 共享)。公众号点「合集」看全部。
夜雨聆风