Android Camera HAL从零到项目落地 - 第3节
3.1 HIDL 与 AIDL:Camera HAL 接口定义语言的选择
在 Android 系统中,Camera HAL 与 Framework 之间的通信依赖接口定义语言(IDL)。从 Android 8.0 到 Android 14+,Google 先后推广了 HIDL(HAL Interface Definition Language)和 AIDL(Android Interface Definition Language)两种方案。理解两者的差异,是设计稳定、可维护的 Camera HAL 的第一步。
3.1.1 核心差异对比
| 对比维度 | HIDL(Android 8~10 主流) | AIDL(Android 11+ 推荐) |
|---|---|---|
| 设计目标 | 为 HAL 层独立设计,与 Framework 解耦 | 统一 Framework 与 HAL 的 IPC 语言 |
| 稳定性 | 使用 @1.0、@2.0 版本化接口 |
使用 @VendorNdk 注解,版本化更简洁 |
| 后端 | 仅支持 C++(hidl-gen) | 支持 Java / C++ / NDK 后端 |
| 包名风格 | android.hardware.camera.provider@2.4 |
android.hardware.camera.provider |
| 服务注册 | hwservicemanager |
servicemanager(与 Framework 统一) |
| 迁移成本 | 需维护两套 .hal 文件 | 复用 .aidl 语法,学习成本低 |
关键结论: 新项目(Android 12+)应优先选择 AIDL 方式。HIDL 在 Android 14 中已被标记为 deprecated,Google 要求所有新 HAL 实现使用 AIDL。
3.1.2 接口定义示例对比
HIDL 定义(ICameraProvider.hal):
package android.hardware.camera.provider@2.4;
interface ICameraProvider {
getCameraIdList() generates (Status status, vec<string> cameraIds);
getCameraDeviceInterface(
string cameraId
) generates (Status status, ICameraDevice device);
};
AIDL 定义(ICameraProvider.aidl):
package android.hardware.camera.provider;
interface ICameraProvider {
String[] getCameraIdList();
ICameraDevice getCameraDeviceInterface(in String cameraId);
}
迁移提示: AIDL 支持
in / out / inout 方向标记,而 HIDL 使用 generates 关键字。AIDL 的异常处理通过 SecurityException 或 IllegalArgumentException 传递,HIDL 则依赖 Status 枚举。
3.1.3 架构演进 SVG 图
3.2 ICameraProvider 接口详解
ICameraProvider 是 Camera HAL 的入口接口,负责枚举相机设备、管理设备生命周期。它是 Framework 与 HAL 建立连接的第一个接触点。
3.2.1 核心方法
| 方法 | 功能描述 | 返回值 |
|---|---|---|
getCameraIdList() |
返回所有可用相机 ID 列表 | String[](AIDL)/vec<string>(HIDL) |
getCameraDeviceInterface(cameraId) |
根据 ID 获取对应的 ICameraDevice 接口 |
ICameraDevice |
setCallback(providerCallback) |
注册回调,用于通知 Framework 设备热插拔事件 | void |
3.2.2 典型实现流程
- 服务注册: HAL 实现启动时,通过
servicemanager注册ICameraProvider实例。 - 设备枚举:
getCameraIdList()遍历底层传感器驱动(如 V4L2、MIPI CSI),返回物理 ID。 - 接口分发:
getCameraDeviceInterface()根据 ID 创建或返回已有的ICameraDevice实例。 - 热插拔通知: 通过
ICameraProviderCallback上报设备插入/移除事件。
常见陷阱: 某些 SoC 平台(如 MTK、Qualcomm)会在
getCameraIdList() 中返回逻辑 ID(如 "0"、"1"),但底层实际对应多个物理传感器。务必在 HAL 层做好 ID 映射表,避免 Framework 层出现 ID 不匹配。
3.2.3 ICameraProvider 架构 SVG 图
3.3 ICameraDevice 接口详解
ICameraDevice 代表一个具体的相机设备实例。它负责配置会话、创建数据流,并暴露设备的静态信息与能力。
3.3.1 核心方法
| 方法 | 功能描述 | 关键参数 |
|---|---|---|
getCameraCharacteristics() |
返回相机静态元数据(如传感器尺寸、AE/AWB 能力) | 无 |
open() |
打开相机设备,准备硬件资源 | 无 |
close() |
关闭相机设备,释放硬件资源 | 无 |
createCaptureSession() |
创建捕获会话,绑定输出 Surface | outputConfiguration、sessionCallback |
3.3.2 设备状态机
每个 ICameraDevice 实例内部维护一个状态机,确保操作顺序合法:
- CLOSED: 初始状态,设备未打开。
- OPENED: 调用
open()后进入,可查询特性。 - CONFIGURED: 调用
createCaptureSession()成功后进入,可提交请求。 - ERROR: 硬件异常或驱动崩溃时进入,需重新打开。
最佳实践: 在
1. 初始化传感器驱动(如 V4L2 打开设备节点)。
2. 分配 ISP 流水线资源。
3. 读取并缓存静态元数据。
4. 注册设备错误监听(如 watchdog 超时)。
open() 实现中,应完成以下操作:1. 初始化传感器驱动(如 V4L2 打开设备节点)。
2. 分配 ISP 流水线资源。
3. 读取并缓存静态元数据。
4. 注册设备错误监听(如 watchdog 超时)。
3.3.3 ICameraDevice 状态机 SVG 图
3.4 ICameraDeviceSession 接口详解
ICameraDeviceSession 是实际处理图像捕获请求的接口。它负责接收 Framework 下发的 CaptureRequest,驱动 ISP 流水线,并返回 CaptureResult 和图像缓冲区。
3.4.1 核心方法
| 方法 | 功能描述 | 调用时机 |
|---|---|---|
processCaptureRequest() |
处理单个捕获请求,触发一次拍照或预览帧 | 每次应用请求帧时 |
flush() |
清空所有待处理的请求队列 | 会话关闭或切换配置时 |
close() |
销毁会话,释放所有流水线资源 | 会话生命周期结束 |
configureStreams() |
配置输出流(分辨率、格式、Surface) | 会话创建或重新配置时 |
3.4.2 请求处理流水线
- 接收请求: Framework 调用
processCaptureRequest(),传入CaptureRequest对象。 - 解析元数据: 提取 AE/AWB/AF 设置、3A 模式、裁剪区域等。
- 驱动 ISP: 将元数据转换为硬件寄存器配置,触发传感器曝光。
- 接收 RAW/YUV/JPEG: 从 ISP 输出缓冲区获取图像数据。
- 返回结果: 通过回调返回
CaptureResult和填充后的输出缓冲区。
性能关键点:
processCaptureRequest() 必须在 1 帧时间内返回(通常 16.67ms @60fps)。如果 HAL 实现中涉及复杂后处理(如 HDR 合成、多帧降噪),建议使用异步线程池,避免阻塞 IPC 调用。
3.4.3 请求处理流水线 SVG 图
3.5 接口关系总览
三个接口在 Camera HAL 中形成清晰的层级关系:
- ICameraProvider: 全局单例,负责设备发现与生命周期管理。
- ICameraDevice: 每个物理/逻辑相机一个实例,负责会话创建与特性查询。
- ICameraDeviceSession: 每个活跃会话一个实例,负责实际的图像捕获流水线。
项目落地建议: 在实现 HAL 时,建议将三个接口的实现类分别放在独立的文件中:
每个类内部维护自己的状态机与资源池,避免跨类直接访问内部数据结构。通过回调接口(如
CameraProvider.cpp / CameraDevice.cpp / CameraDeviceSession.cpp。每个类内部维护自己的状态机与资源池,避免跨类直接访问内部数据结构。通过回调接口(如
ICameraProviderCallback)实现层级间通信。
3.5.1 接口层级关系 SVG 图
3.6 本章小结
| 接口 | 职责 | 关键方法 | 生命周期 |
|---|---|---|---|
| ICameraProvider | 设备枚举、热插拔 | getCameraIdList()、getCameraDeviceInterface() |
进程级单 |