4. HAL3 接口实现:ICameraDevice、ICameraDeviceSession、ICameraDeviceCallback
在 Android Camera HAL3 架构中,HIDL(HAL Interface Definition Language)接口是 Framework 与 HAL 实现之间的核心契约。正确实现 ICameraDevice、ICameraDeviceSession 和 ICameraDeviceCallback 三个接口,是保证相机功能正常、性能达标以及通过 CTS 测试的基础。本章将深入剖析每个接口的职责、关键方法以及实现时的性能与兼容性要点。
4.1 接口总览与职责划分
三个 HIDL 接口构成了 HAL 层的“设备-会话-回调”三角模型,其职责分工如下表所示:
| 接口名称 | 核心职责 | 生命周期 | 关键方法数 |
|---|---|---|---|
| ICameraDevice | 设备级管理:打开/关闭相机、创建会话、查询静态信息 | 从 HAL 加载到设备关闭 | ~5 个 |
| ICameraDeviceSession | 会话级控制:配置流、提交请求、捕获结果回调 | 从 open() 到 close() 或 flush() | ~10 个 |
| ICameraDeviceCallback | 异步通知:结果返回、错误上报、缓冲区释放 | 由 Framework 实现,HAL 调用 | ~4 个 |
实现要点:三个接口必须严格遵循 HIDL 定义的 oneway 和同步调用语义。ICameraDevice 和 ICameraDeviceSession 的方法通常由 Framework 同步调用,而 ICameraDeviceCallback 的方法均为 oneway(异步),HAL 实现不得在回调中执行耗时操作。
4.2 ICameraDevice 接口实现
ICameraDevice 是 HAL 暴露给 Framework 的第一个入口点。其核心方法包括:
- getCameraCharacteristics():返回相机静态元数据(如传感器尺寸、AE/AWB 能力、支持的分辨率列表)。
性能要点:此方法在相机打开时被频繁调用,建议将元数据预编译为二进制 buffer,避免每次动态构造。 - open():创建并返回一个 ICameraDeviceSession 实例。这是性能关键路径,必须在 500ms 内完成(CTS 要求)。
实现要点:延迟初始化硬件资源(如 ISP、Sensor),仅在首次提交请求时真正启动。 - close():释放所有硬件和内存资源。必须保证幂等性,多次调用不崩溃。
- setTorchMode():控制闪光灯常亮模式。需注意与 session 内闪光灯控制的互斥逻辑。
CTS 避坑:getCameraCharacteristics() 返回的 android.scaler.availableStreamConfigurations 必须与 session 实际支持的流完全一致。任何不一致都会导致 CTS 测试项
android.hardware.camera2.cts.CameraCharacteristicsTest 失败。
4.3 ICameraDeviceSession 接口实现
ICameraDeviceSession 是 HAL3 最核心的接口,负责处理所有捕获请求和结果返回。其关键方法按功能分组如下:
4.3.1 流配置与管道控制
- configureStreams():配置输出流(如预览、拍照、录像)和输入流(如 reprocess)。
性能要点:此方法调用时,HAL 应重新计算 ISP 管线带宽,避免不必要的硬件复位。CTS 要求配置时间 < 100ms。 - processCaptureRequest():提交单个捕获请求。这是性能调优的核心战场。
实现要点:请求入队后应立即返回,实际处理在后台线程进行。使用 lock-free 队列减少 Framework 侧等待时间。 - flush():清空所有待处理请求,并等待正在处理的请求完成。CTS 要求 flush 在 1000ms 内返回。
4.3.2 结果与错误通知
- processCaptureRequest() 的结果返回:通过 ICameraDeviceCallback 的
processCaptureResult()方法异步返回。每个请求必须返回至少一个 partial result 和一个 final result。 - notify():通过 ICameraDeviceCallback 上报错误(如请求超时、缓冲区错误)。
性能优化技巧:对于预览流,建议在 processCaptureRequest() 中直接复用上一次的 metadata buffer,仅更新时间戳和 3A 状态,减少内存分配开销。对于拍照流,则需保证完整的 metadata 填充。
4.4 ICameraDeviceCallback 接口实现
ICameraDeviceCallback 由 Framework 实现,HAL 通过它向 Framework 传递结果和事件。HAL 实现者需要正确调用以下方法:
| 回调方法 | 调用时机 | 实现要求 |
|---|---|---|
| processCaptureResult() | 每个捕获请求完成时(可多次调用,用于 partial result) | 必须按请求顺序返回;partial result 的 metadata 必须包含 android.sensor.timestamp |
| notify() | 发生错误或事件时(如请求超时、缓冲区错误) | 必须填充正确的 ErrorCode;不得在回调中阻塞 |
| requestStreamBuffers() | HAL 需要 Framework 分配缓冲区时(可选) | 仅当 HAL 支持 buffer management 模式时使用 |
| returnStreamBuffers() | HAL 使用完缓冲区后归还 | 必须与 requestStreamBuffers 配对调用 |
关键约束:所有回调方法都是 oneway(异步),HAL 实现不得在回调中等待 Framework 响应。如果 HAL 在回调中执行同步 IPC 调用,会导致死锁(Framework 侧可能持有锁等待回调返回)。
4.5 接口交互流程与性能关键路径
下图展示了从打开相机到提交请求的完整交互流程,并标注了性能关键路径:
4.6 实现要点总结与 CTS 验证对照
下表将接口实现要点与对应的 CTS 测试项关联,便于开发者在实现时进行自检:
| 接口 | 实现要点 | 对应 CTS 测试项 |
|---|---|---|
| ICameraDevice | getCameraCharacteristics() 返回的静态信息必须与硬件能力一致 | CameraCharacteristicsTest |
| ICameraDeviceSession | configureStreams() 必须支持所有声明的流组合;processCaptureRequest() 必须按序返回结果 | CameraExtensionSessionTest、CaptureRequestTest |
| ICameraDeviceCallback | processCaptureResult() 必须包含 android.sensor.timestamp;notify() 必须正确上报错误码 | CameraDeviceTest、ResultTest |
| 跨接口 | flush() 后所有待处理请求必须通过 notify() 上报 ERROR_REQUEST | FlushTest |
调试建议:在实现初期,建议在 HAL 侧增加详细的日志输出,记录每个接口方法的调用时间、参数和返回值。使用
adb shell dumpsys media.camera 可以查看 Framework 侧收集的 HAL 性能数据,帮助定位接口实现中的性能瓶颈。