Android Q MTK Camera HAL3 Search Sensor机制与实战排查

发布时间:2026/10/14 18:55:11
Android Q MTK Camera HAL3 Search Sensor机制与实战排查
做 Camera 的老司机都清楚一个道理预览虚、曝光乱、对焦飘最后多半能在 Sensor 这一层找到蛛丝马迹。Android Q 的 MTK Camera Hal3 Search Sensor就是这条请求链路的最前端。之前我跟着调一个模拟项目里的前摄点亮任务发现不少同学把精力全放在 3A tuning 和 stream 参数上结果 Sensor 列表为空还在那里怼 pipeline纯属白忙。所以这一篇想把 Search Sensor 讲透它发生在哪个阶段、底层到底在搜什么、搜不到怎么定位以及我自己踩过的几个真实存在的坑。说明一下以下分析以 Android Q 分支的 MTK Camera HAL3 代码组织方式为例不同版本、不同项目在文件命名和调用层级上会有差异但设计思路是通用的。1. 为什么 Camera 请求链路要把 Sensor 搜索放在最前面1.1 Camera 打开瞬间系统在等一个“答案”用 Camera 应用打开预览看起来只是一次 startPreview但底层是 CameraService 通过 HIDL 接口找到 CameraProvider再让 HAL 打开对应 cameraId。这个过程中HAL 必须向 Framework 保证一件事这颗 Sensor 存在并且它的能力参数是完整可用的。只有在拿到这个保证之后Framework 才会继续下发 configureStreams、processCaptureRequest 这些后续动作。你可以把 Search Sensor 理解为一次“点名签到”。HAL3 架构里的 pipeline、node、stream 都建立在 Sensor 这个物理实体之上。如果点名失败后面所有环节都无法构造。很多现场日志里看似是 HAL 打不开或者 getCameraIdList 返回空根因其实都埋在更早的 Sensor 搜索阶段。所以排查 Camera 问题第一件事不是翻上层代码而是先在日志里确认 Search Sensor 到底成功了没有。1.2 Search Sensor 不是“找摄像头”而是建立物理器件和软件配置的契约有人会误解“搜索 Sensor”就是把设备列表遍历一遍看看系统里插了几个摄像头。实际不是。Search Sensor 要做的是把三样东西对齐内核驱动里真实探测到的物理 Sensor、HAL 侧静态配置表里登记的 Sensor 信息、以及最终要返回给 Framework 的 Camera 静态 metadata。物理 Sensor 不是凭空出现的它靠 I2C 挂在主板上有上电时序有厂商 ID有分辨率有色温、镜头朝向等物理属性。软件眼里这些都不是自动知道的必须通过一次真实的硬件交互把 chip ID 读回来。读完 ID 再去静态配置表里反查才能确定这颗 Sensor 是哪一颗、该怎么建 pipeline、该把哪些能力写进 characteristics。这正是 Search Sensor 存在的意义用硬件探针去校验软件配置而不是单纯相信配置文件。2. Search Sensor 在 MTK HAL3 代码中的调用时机和典型走向2.1 从 HAL open 到 Sensor 节点的调用链在 Android Q 的 MTK HAL3 实现里整体架构已经从早期 legacy 相机 HAL 切到了 HIDL CameraProvider 那套体系。CameraProvider 加载 HAL3 的 .so 之后调用路径大致是这样的CameraProviderHIDL 服务 - hal3_module-open() - CamDeviceManager::openDevice() - CamDevice 构造 - PipelineModel / PipelineModelCallback 创建 - 各个 Node 初始化包括 SensorNode - SensorHal 接口调用 - Search Sensor这里最关键的转折在 PipelineModel 创建之后。PipelineModel 编译 camera pipeline 时需要先把 Sensor 节点的输入输出确认下来否则后续的 ISP 节点、P1 节点、raw 流全都无从谈起。所以在 MTK 代码里SensorNode 第一次初始化时通常就会触发 SensorHal 的 Search Sensor。需要注意Android Q 时代已经有多摄、逻辑摄像头、物理摄像头这些概念Search Sensor 往往不是只做一次而是要对每个物理 Sensor 都执行一遍。表现为日志里可能连续出现多次 sensor index、chip ID 相关信息最后汇总成一份 Sensor 能力列表。2.2 为什么每次 open 都要重新搜索而不是缓存一次有人会问出厂时 Sensor 又不会变为什么每次打开相机都要重新搜索一遍直接用一次保存下来的结果不行吗从平台稳定性角度讲重新搜索是更稳妥的做法。Sensor 驱动在 probe 阶段可能依赖上电时序上一轮的 power off 是否彻底会直接影响下一轮 power on 之后读芯片 ID 的结果。如果 HAL 长期缓存上一次的结果一旦发生异常下电、系统休眠唤醒、摄像头模组方向改动就会出现缓存数据和实际硬件不一致给问题排查添乱。MTK 代码里虽然会有静态信息缓存比如 sensor list 的配置、SensorStaticInfo 的部分参数但 pipeline 真正建立之前仍会对 Sensor 做一次 ID 确认。你可以把这次确认类比成每次开机都要重新握手而不是相信历史连接状态的 TCP Keepalive。3. Sensor 枚举的核心机制设备节点、驱动 ID 与静态信息表的三方对齐3.1 内核侧Sensor 是 v4l2 subdev不是普通 I2C 设备在 Android 的相机架构里内核 sensor 驱动通常以 V4L2 subdev 形式注册用户空间看到的可能是/dev/videoX或者/dev/v4l-subdevX节点。HAL 通过 open 节点、调用VIDIOC_SUBDEV_G_FMT这类 ioctl和内核驱动打交道。Search Sensor 要拿到最可靠的信息不是看文件名字也不是猜节点号而是直接读 Sensor 寄存器里的 chip ID。这个动作在驱动层通过 I2C 完成HAL 层再通过自定义 ioctl 或者能力查询接口拿到返回值。换句话说Search Sensor 是一个真实发生的硬件访问过程先给 Sensor 上电再拉 MCLK然后往某个 I2C 地址写读寄存器指令最后把返回的 ID 和预期值比较。3.2 一个可以反复对照的 Search Sensor 伪代码流程MTK 不同分支的具体实现差异很大但核心逻辑殊途同归。下面这段伪代码可以帮你理解搜索的大致节奏// 伪代码展示核心搜索思路具体实现因分支而异 int searchSensor() { for (int i 0; i sensor_table.size(); i) { SensorInfo info sensor_table[i]; // 配置文件里可以单独关闭某个 Sensor 的搜索 if (!info.enable) { continue; } // 三步走上电 - 读ID - 下电 sensorHal-powerOn(info); // 供AVDD/DOVDD/DVDD拉MCLK释放Reset int chipId sensorHal-readChipId(info); // I2C读寄存器 sensorHal-powerOff(info); // 必须下电避免影响下一颗Sensor if (chipId info.chipId) { matchedSensorIndex i; return OK; } } return -ENODEV; }这段伪代码里最容易被忽视的就是最后那个powerOff。有些人调试时为了省事把下电步骤注释掉结果第二颗 Sensor 读取的时候返回了一个莫名其妙的 ID。多摄模组共用电源轨时尤其明显一颗 Sensor 还上着电另一颗去读 ID回读的数据可能来自没被搜索的那一颗。所以搜索循环里的上下电配对不是可有可无的规范而是保证结果正确的先决条件。3.3 静态信息表“通缉名单”由谁维护HAL 侧不可能无限遍历所有 Sensor它搜索的依据是一张静态信息表。在 MTK 平台里这类配置通常来自sensorlist、cam_cal或者 vendor 目录下的 sensor 配置模块。面向项目集成时这张表就是“通缉名单”里面登记了系统支持哪些 Sensor、每颗 Sensor 的 I2C 地址是多少、芯片 ID 是多少、用哪路电源、分辨率多大。典型字段如下字段作用常见错误sensor_idSensor 在 HAL 里的逻辑编号与驱动侧编号不一致sensor_name模组厂商型号如某型号前摄型号写错导致匹配失败i2c_bus / i2c_addrSensor 挂在哪条 I2C 总线、设备地址地址与原理图不符chip_id / chip_id_mask读取后的 ID 和掩码比对值掩码写错导致误判avdd / dovdd / dvdd电源域配置用错 regulator 导致上电失败mclk主时钟频率频率不对导致 PLL 不稳orientation / facing画面朝向和前后摄属性前摄写成后摄旋转不对这张表不归内核驱动管而是平台集成者根据模组规格书维护的。新项目点 Sensor第一步就是往表里加一条记录否则 HAL 根本不会去探测这颗 Sensor。很多“新 Sensor 搜不到”的反馈最后查下来只是这行配置没有加。3.4 搜索结果的两个分支找到与找不到如果循环结束都没有匹配到预期的 chip IDSearch Sensor 返回失败。此时 CamDevice 的构造流程会中断HAL 向上返回 open 失败或者 getCameraIdList 返回的列表里干脆没有这颗摄像头。Framework 层看到的可能是openCamera fail、camera id not available误导很多人去查上层 service其实根源在 Sensor 搜索这一步。如果搜索成功HAL 就拿到了一组 Sensor 身份信息包括 sensor_idx、chip ID、名称等。接下来它会结合静态配置表生成一颗 Sensor 的能力集再交给上层使用。这个“能力集”本质上是 Camera characteristics 的基础素材。4. 搜索结果如何变成 HAL3 的“户口本”Metadata 映射与多摄归类4.1 从 Sensor 结果到 Camera Characteristics 的字段映射Search Sensor 本身不负责生成所有 metadata它只是把 Sensor 的第一手身份信息拿到手后续再和 HAL 的其他模块一起拼出完整的静态能力。你可以理解成 Search Sensor 负责“验明正身”而能力组装负责“填写简历”。常见映射关系如下Search Sensor 结果字段Android Camera Metadata Keysensor_nameANDROID_SENSOR_INFO_NAMEactive array width / heightANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZEorientationANDROID_SENSOR_ORIENTATIONfacingANDROID_LENS_FACING分辨率、帧率能力ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGESraw 格式支持ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS所以如果 Search Sensor 失败不只影响打开相机而是整个静态 metadata 都无法正确生成。表现为部分第三方 App 直接拿不到相机系统相机也可能闪退。4.2 Android Q 多摄逻辑物理 Sensor 要先搜出来再归并Android Q 一个比较大的变化是逻辑摄像头和物理摄像头的关系。逻辑 cameraId 可以对应多个物理 cameraId比如后置广角加长焦在 Framework 看来是一个逻辑摄像头实际由两颗独立 Sensor 组成。这种情况下的 Search Sensor 流程往往先逐颗物理 Sensor 做搜索拿到所有物理 sensor 的 ID 和静态信息再根据平台的 topology 配置把几个物理 Sensor 归并成一个逻辑 cameraId。如果这个归并表配置错误也会出现“物理 Sensor 能搜到但逻辑摄像头打不开”的诡异现象。实战中遇到双摄或三摄项目时不要一看到 Search Sensor 失败就只盯 Sensor 驱动还要确认多摄拓扑表里物理 ID 的映射顺序是不是和硬件排布一致。顺序错乱造成的失败日志里几乎看不出 Sensor 本身的问题很容易被误判为驱动 bug。5. 一次 Search Sensor 失败的完整排查链路从 log 到 root cause5.1 现象与第一条日志假设场景某项目升级系统后前摄完全黑屏后摄正常。logcat 里能看到类似这样的关键字:[CamDeviceManager] openDevice 0 fail, searchSensor not found [CameraService] connectDevice error: -EINVAL这种日志已经把问题指向了 Search Sensor。接下来要做的不是去改 App 的 GL 渲染也不是去查 surface buffer而是沿着 Sensor 搜索链路一层层往下压。5.2 内核层、HAL层、配置表三步定位我通常按三层来过滤日志检查层常用命令/日志重点看什么内核驱动层dmesg | grep -iE imgsensor|i2c|mclksensor driver probe 是否成功、I2C 传输是否报错HAL 搜索层logcat | grep -iE searchSensor|sensorHal搜索到哪个 sensor index、power on/off 是否成对出现静态配置层查看 vendor 下的 sensorlist / cam_calchip_id、I2C 地址、电源域是否和实际硬件一致排查时先确认内核 probe 是否成功。如果 dmesg 里连 imgsensor probe 成功的记录都没有说明问题在更底层的 device tree 或者电源配置HAL 再怎么写都是白搭。如果 probe 成功但 HAL 搜索失败重点对比 sensorlist 里的 chip ID 和驱动实际读到的 chip ID。5.3 两个典型 root cause我遇到过两次比较有代表性的失败可以给各位参考。第一次是 I2C 地址不匹配。项目的硬件改版把前摄模组换成了另一家供应商Sensor 的 I2C 地址从 0x20 改成了 0x10但 sensorlist 里还是旧地址。Search Sensor 读出来的 ID 自然是错的比对不过搜索失败。这种问题看日志只会看到“chip ID mismatch”不看硬件原理图很难定位。第二次是 Sensor 电源配置问题。某颗 Sensor 的 AVDD 和 DOVDD 电源域在 device tree 里挂反了导致上电顺序不对冷启动时搜索偶发失败但热启动又正常。这种“偶发搜不到”最折磨人因为整机重启十次可能有九次正常只有一次黑屏。后来通过不断抓 dmesg对比读 ID 阶段的时序才发现是电源域配置问题。5.4 下手改代码之前的前置检查清单排查 Search Sensor 失败我建议先按下面这个清单过一遍再考虑改代码确认 CameraProvider 服务确实重启过而不是只 force-stop 了相机 App。HAL 侧缓存没清掉有时会掩盖真实结果。确认内核 device tree 中 Sensor 节点 probe 成功相关 regulator 和 GPIO 都被正确申请。确认 sensorlist 里新增的 Sensor 记录与模组规格书一致尤其是 chip ID 和掩码。确认多摄拓扑表里物理 Sensor 顺序和硬件排布一致。确认平台加载的 dtbo/board revision 与实际硬件版本一致不同版本板子的 I2C 地址可能不同。这些前置检查看起来很基础但绝大多数搜不到的问题都出在这里而不是在 HAL 的算法逻辑里。6. Search Sensor 不能只靠软件上电时序、I2C 地址和节点映射是隐性依赖6.1 上电时序Sensor 也有自己的起床流程Sensor 从断电到能读 ID并不是一蹴而就。典型流程是先拉 MCLK再依次给 AVDD、DOVDD、DVDD 上电然后拉高 Reset等待一段时间稳定最后才能通过 I2C 读寄存器。这段时序里任何一个 delay 不够都可能导致 chip ID 读取失败或读到错误值。尤其是 Reset 释放后的稳定时间很多工程师为了赶进度会拍脑袋设置一个比较短的值结果 Read ID 偶发失败。排查时可以用一个简单方法验证把 Reset 释放后的等待时间临时加长到规格书建议值的两倍再看搜索是否变稳定。如果变稳定了基本就是时序余量不足。6.2 共电源双摄下电不彻底会串出错误的 chip_id双摄模组共用一路主电源非常常见。Search Sensor 在遍历时如果上一颗 Sensor 没有彻底下电下一颗 Sensor 上电后总线状态可能没达到理想状态读回的 ID 不一定来自目标 Sensor。这也是为什么很多规范的代码会在搜索循环里强制执行powerOff甚至会在每次搜索前先做一次全局下电复位。Android Q 的多摄场景越来越多这条要求已经不是“建议”而是必需品。自己写搜索逻辑时千万别图快省略这步。6.3 /dev/videoN 的节点号不是永远可信V4L2 的/dev/videoN节点编号由内核驱动 probe 顺序决定不是一个稳定不变的物理地址。今天启动顺序是 video0 对应后摄明天某个驱动 probe 快了一点video0 就可能对应前摄或者干脆多占一个 video 节点。Search Sensor 如果硬编码节点号很容易被这种动态变化坑到。更稳的方案是通过 media controller 查询实体名称或者遍历/dev/v4l-subdevX后用实体名字匹配目标 Sensor。日志里看到 “open /dev/video2 fail” 时不要急着判断是硬件问题先确认这个节点到底对应哪颗传感器。6.4 搜索顺序为什么不能随意调整部分 Sensor 驱动的s_power回调依赖一个隐式顺序先 A 后 B 能正常 probe反过来就会因为电源轨竞争失败。HAL 的搜索顺序如果被随意调整读 ID 阶段的成功率和稳定性都会受影响。所以这类代码看起来只是简单循环实际排列顺序往往经过平台验证。调试时如果发现顺序和你想象的不同先保留原状优先怀疑其他环节。真要调顺序必须把每一条上下电日志都打开确认没有任何一个节点出现电源冲突。7. 写在最后我给自己定的三条 Sensor 调试纪律7.1 先谈 Search再谈 TuningSensor 搜不到后面 3A、ISP、raw 全部是空转。现在我把 Search Sensor 的日志提前到了刚开始调试时的第一道检查项任何相机问题都先确认这一步过了再往下走。这一步省掉的时间远比来回翻上层日志要多。7.2 把搜索路径上的每一步都留下日志我会在每次 powerOn、readChipId、powerOff 前后各打一条日志记录 sensor index、chip ID 和操作结果。刚开始觉得冗余后来发现排查硬件时序问题全靠这些点。某次偶发失败就是把日志时间戳和 dmesg 时间戳对照后才发现 Reset 释放后稳定时间不足。7.3 偶发搜不到先怀疑时序与电源而不是急着改代码遇到“十次有九次正常、一次黑屏”先别在 HAL 里加 sleep。优先抓 dmesg对比成功和失败两次流程的差异。很多时候是电源纹波、Reset 保持时间、I2C 上拉电阻这些问题。软件可以临时加长时序做对照实验但真正的修法是回到硬件或者 device tree 配置里解决。Search Sensor 虽然只是 Camera HAL3 里的一段早期逻辑但它把硬件、内核、配置表、HIDL 服务串在了一起。如果你能把这段逻辑彻底吃透后面再遇到 Camera 打不开、黑屏、枚举异常定位速度会快上不止一个量级。