多平台与多厂商调试:Camera HAL兼容性工程案例 - 第1节

1.1 Camera HAL 在 Android 系统中的位置与作用

Camera HAL(硬件抽象层)是 Android 相机子系统中连接 Framework 与底层硬件驱动的关键中间层。它位于 Android 系统的 用户空间,向上为 Framework 提供统一的相机操作接口,向下屏蔽不同 SoC 平台和传感器厂商的硬件差异。

核心定位:HAL 是 Android 相机架构的“战略分界线”——Framework 侧不感知具体硬件实现,HAL 侧不依赖 Framework 的进程模型。这一设计使得 OEM 厂商可以在不修改上层框架的前提下,独立适配不同平台的 ISP、传感器和算法库。

1.1.1 系统层级中的位置

从 Android 系统分层来看,Camera HAL 处于以下位置:

Camera HAL 在 Android 系统中的层级位置 应用层(Camera App / 第三方应用) Framework 层(CameraService / Camera2 API) Camera HAL 层(HAL 3.x / HAL 1.0) 内核层(V4L2 / ISP 驱动 / Sensor 驱动) 硬件层(Camera Sensor / ISP 芯片 / MIPI 接口) HAL 接口边界 (hardware/libhardware)

1.1.2 HAL 的核心作用

作用维度 具体说明 工程意义
接口标准化 定义统一的 camera_device_t / camera3_device_t 结构体 Framework 无需关心底层是 Qualcomm、MTK 还是展锐平台
硬件抽象 封装 ISP 参数调优、MIPI 配置、Sensor 初始化等硬件细节 OEM 可独立升级 HAL 库而不影响 Framework 稳定性
性能隔离 通过 buffer 管理、stream 配置、request 队列隔离不同模块 多摄像头并发时避免资源竞争和死锁
兼容性桥接 适配不同 Android 版本(如 Treble / VINTF 要求) 保证 CTS / VTS 测试通过,满足 Google 兼容性要求
工程经验:在多平台调试中,HAL 层是问题最集中的区域。约 70% 的相机兼容性问题(如预览黑屏、拍照卡顿、HDR 失效)最终定位在 HAL 实现与 Framework 预期行为不一致上。

1.2 HAL 接口定义

Android Camera HAL 主要分为两个版本:HAL 1.0(旧版,Android 4.x~6.x)和 HAL 3.x(新版,Android 7.0+ 强制要求)。当前主流平台均使用 HAL 3.x 架构。

1.2.1 HAL 3.x 核心接口结构

HAL 3.x 的核心定义位于 hardware/libhardware/include/hardware/camera3.h,主要包含以下关键结构体:

// camera3_device_t —— HAL 设备句柄
typedef struct camera3_device {
    hw_device_t common;
    camera3_device_ops_t *ops;   // 操作函数指针表
    void *priv;                  // HAL 私有数据
} camera3_device_t;

// camera3_device_ops_t —— 操作函数表
typedef struct camera3_device_ops {
    int (*initialize)(const struct camera3_device *, 
                      const camera3_callback_ops_t *callback_ops);
    int (*configure_streams)(const struct camera3_device *,
                             camera3_stream_configuration_t *stream_list);
    int (*process_capture_request)(const struct camera3_device *,
                                   camera3_capture_request_t *request);
    void (*dump)(const struct camera3_device *, int fd);
    int (*flush)(const struct camera3_device *);
    void (*signal_stream_flush)(const struct camera3_device *,
                                uint32_t num_streams,
                                const camera3_stream_t *const *streams);
    // ... 其他函数指针
} camera3_device_ops_t;

1.2.2 关键接口函数说明

接口函数 触发时机 典型实现复杂度 常见调试问题
initialize CameraService 打开设备时 中 回调注册失败导致无数据返回
configure_streams 应用设置预览/拍照/录像尺寸时 高 Stream 组合不合法、分辨率不支持
process_capture_request 每次拍照或预览帧请求 极高 Request 超时、Buffer 未填满、Metadata 缺失
flush 应用关闭相机或切换模式时 中 死锁、pending request 未正确清理
dump dumpsys media.camera 时 低 信息不全、无法定位问题

1.2.3 Metadata 接口

HAL 3.x 使用 Camera Metadata(基于 camera_metadata_t)作为控制参数和结果数据的载体。Framework 通过 capture_request.settings 下发控制参数,HAL 通过 camera3_callback_ops_t.process_capture_result 返回结果 metadata。

// 典型的 metadata 控制项(部分)
ANDROID_SENSOR_EXPOSURE_TIME      // 曝光时间(纳秒)
ANDROID_SENSOR_SENSITIVITY        // ISO 感光度
ANDROID_CONTROL_AE_MODE           // 自动曝光模式
ANDROID_CONTROL_AF_MODE           // 自动对焦模式
ANDROID_CONTROL_AWB_MODE          // 自动白平衡模式
ANDROID_STATISTICS_FACE_RECTANGLES // 人脸检测结果
ANDROID_JPEG_QUALITY              // JPEG 压缩质量
常见陷阱:Metadata 的 tag 值必须在 system/media/camera/docs/metadata_definitions.xml 中定义,HAL 实现时不能随意新增私有 tag。如果需要在 HAL 内部传递私有参数,应使用 vendor 扩展 tag 区域(0x80000000 ~ 0xFFFFFFFF)。

1.3 HAL 与 Framework 的交互流程

从应用发起相机请求到最终收到图像数据,HAL 与 Framework 之间经历了一个完整的 Request-Result 循环。理解这一流程是调试兼容性问题的前提。

1.3.1 核心交互流程

Camera HAL 与 Framework 交互流程(HAL 3.x) Camera App CameraService Camera HAL ① open() ② initialize() 设置预览/拍照尺寸 ③ 配置 Stream 解析 Stream 配置 ④ configure_streams() 配置 ISP / Sensor 发送 Capture Request ⑤ 下发 Request 封装 Metadata + Buffer ⑥ process_capture_request() 硬件捕获 + 3A 处理 返回 Result + Buffer ⑦ process_capture_result() 解析 Result Metadata ⑧ 回调图像数据 渲染预览帧 / 保存照片 循环:每秒 30 帧(预览)或单次(拍照) 关键时序约束: • process_capture_request() 必须在 5ms 内返回(否则 ANR) • 预览帧必须在 33ms(30fps)内完成从 request 到 result 的全流程

1.3.2 交互流程关键步骤说明

  1. 设备打开与初始化:CameraService 通过 HAL 的 open() 打开设备,然后调用 initialize() 注册回调函数指针表 camera3_callback_ops_t。
  2. Stream 配置:应用设置预览/拍照/录像尺寸后,Framework 调用 configure_streams() 通知 HAL 配置数据流。HAL 需要返回支持的 stream 组合和 buffer 格式。
  3. Request 下发:每次捕获(预览帧或拍照)由 process_capture_request() 触发。HAL 收到 request 后,需要填充 output buffers 并调用回调返回结果。
  4. Result 回调:HAL 通过 process_capture_result() 回调返回 metadata 和图像 buffer。Framework 将结果分发给应用层。
  5. Flush 与关闭:应用退出时,Framework 调用 flush() 清空所有 pending request,然后关闭设备。

1.3.3 Buffer 管理交互

HAL 3.x 使用 Gralloc Buffer 进行图像数据传输。Framework 负责分配 buffer 并注册到 HAL,HAL 在捕获完成后将填满数据的 buffer 返回给 Framework。

Buffer 角色 分配方 使用方 典型格式
Preview Stream Framework(SurfaceFlinger) HAL 写入 → SurfaceFlinger 消费 NV12 / YV12 / RGBA_8888
Capture Stream Framework(CameraService) HAL 写入 → JPEG 编码器消费 NV12 / JPEG(HAL 内编码)
RAW Stream Framework 或 HAL(取决于实现) HAL 写入 → 第三方算法库消费 RAW10 / RAW16 / RAW_OPAQUE
多平台调试要点:不同平台对 buffer 格式和 alignment 的要求差异巨大。例如 Qualcomm 平台要求 NV12 的 stride 为 128 字节对齐,而 MTK 平台可能要求 64 字节对齐。在 configure_streams() 阶段未正确对齐 stride 会导致预览花屏或拍照绿图。

1.3.4 同步与超时机制

HAL 与 Framework 之间的交互必须遵守严格的同步契约:

  • Request 超时:Framework 会为每个 request 设置超时(通常 3~5 秒)。如果 HAL 未在超时前返回 result,Framework 会触发 ANR(应用无响应)并 dump HAL 状态。
  • Buffer 生命周期:HAL 必须在 process_capture_result() 回调中释放所有 output buffer 的引用。如果 HAL 持有 buffer 不释放,会导致 Framework 侧的 buffer 池耗尽。
  • Flush 语义:flush() 调用后,HAL 必须立即返回所有 pending request 的 result(可以标记为 error),不能有 request 残留。
工程案例:某项目中,HAL 在 process_capture_request() 中因为 ISP 调参耗时超过 100ms,导致预览帧率从 30fps 骤降到 8fps。最终通过将 ISP 参数预计算移到 configure_streams() 阶段解决。这个案例说明:HAL 实现必须严格区分“配置时”和“运行时”的操作边界。