3. 初始化流程:open()接口实现、initialize()接口实现、设备能力查询
Camera HAL3 的初始化流程是上层框架与底层硬件驱动建立通信通道的关键阶段。该流程涉及三个核心步骤:设备节点打开(open())、会话初始化(initialize())以及设备静态能力查询(getCameraCharacteristics())。本章将逐一剖析每个接口的实现要点、数据流走向以及常见适配陷阱。
3.1 open() 接口实现
open() 是 HAL3 模块中第一个被调用的接口,其职责是打开指定 cameraId 对应的硬件设备,并返回一个 camera3_device_t 结构体指针,供后续操作使用。
3.1.1 接口原型与调用时机
int (*open)(const struct hw_module_t* module, const char* id,
struct hw_device_t** device);
调用时机:CameraService 启动后,通过 hw_get_module() 加载 HAL 模块,随即遍历可用 cameraId,对每个逻辑摄像头调用一次 open()。
3.1.2 实现要点
| 实现步骤 | 说明 | 常见错误 |
|---|---|---|
| 1. 参数校验 | 检查 module、id、device 指针非空;验证 cameraId 是否在支持范围内 | 未校验空指针导致空引用崩溃 |
| 2. 设备上下文分配 | malloc 或 new 一个私有设备结构体(如 camera3_device_t 的包装类),包含打开的文件描述符、同步锁、状态机等 |
内存泄漏或未初始化成员变量 |
| 3. 硬件驱动打开 | 通过 V4L2、MIPI CSI 或私有驱动接口打开物理摄像头设备节点 | 驱动节点权限不足或设备忙 |
| 4. 回调函数注册 | 将 HAL3 定义的 camera3_device_ops_t 函数表赋值给设备结构体 |
函数表未完全填充导致调用空函数指针 |
| 5. 返回设备句柄 | 将 camera3_device_t* 转型为 hw_device_t* 返回 |
类型转换错误或返回野指针 |
关键提示:
open() 调用可能发生在不同线程上下文中,建议在设备上下文内使用 std::mutex 或 pthread_mutex_t 保护共享状态,防止竞态条件。
3.2 initialize() 接口实现
initialize() 是 camera3_device_ops_t 中的第一个操作接口,用于建立 HAL 与 CameraService 之间的回调通道,并完成流配置前的准备工作。
3.2.1 接口原型
int (*initialize)(const struct camera3_device *device,
const camera3_callback_ops_t *callback_ops);
3.2.2 核心职责
- 保存回调函数表: 将
callback_ops指针保存到设备上下文中,后续通过该指针上报事件(如notify()、process_capture_result())。 - 初始化流管理模块: 清空或重置流列表,准备接收
configure_streams()调用。 - 启动传感器预览(可选): 部分硬件需要在 initialize 阶段启动传感器时钟或 MIPI 链路,以缩短后续配置延迟。
- 资源预分配: 分配 buffer 管理池、请求队列、统计信息缓冲区等。
3.2.3 实现流程图
最佳实践: 在
initialize() 中不要执行耗时超过 100ms 的操作,否则可能导致 CameraService 触发 ANR。建议将传感器预热等操作异步化。
3.3 设备能力查询
设备能力查询通过 getCameraCharacteristics() 接口实现,返回一个包含摄像头所有静态元数据的 camera_metadata_t 结构体。该查询在 open() 之后、configure_streams() 之前被调用,用于指导上层应用选择合理的配置参数。
3.3.1 关键元数据项
| Tag 名称 | 类型 | 说明 | 适配要求 |
|---|---|---|---|
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL |
byte | 硬件支持级别(LIMITED/FULL/LEVEL_3) | 必须正确声明,影响框架行为 |
ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE |
int32[2] | 有效像素阵列宽高 | 与实际 sensor 输出一致 |
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS |
int32[] | 支持的输出/输入流格式与分辨率组合 | 必须包含至少一组 YUV_420_888 和 JPEG |
ANDROID_REQUEST_AVAILABLE_CAPABILITIES |
int64[] | 设备支持的能力(如 RAW、BURST_CAPTURE、MANUAL_SENSOR) | 按实际硬件能力声明 |
ANDROID_SYNC_MAX_LATENCY |
int32 | 最大帧同步延迟(PER_FRAME_CONTROL / UNKNOWN) | 影响 3A 策略选择 |
3.3.2 能力查询实现步骤
- 创建元数据构建器: 使用
allocate_camera_metadata()或camera_metadata_t辅助类分配初始缓冲区。 - 填充静态元数据: 从硬件驱动读取 sensor 特性、ISP 能力、闪光灯信息等,逐项写入元数据。
- 校验必填项: 确保所有
android.*.info和android.*.available*标签已正确设置。 - 返回元数据指针: 将构建完成的
camera_metadata_t*返回给框架,框架负责释放。
3.3.3 能力查询数据流
常见适配陷阱:
- 元数据不一致:
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS中声明的分辨率,必须在configure_streams()时实际支持,否则会导致流配置失败。 - 硬件级别误报: 将 LIMITED 级别设备声明为 FULL,会导致框架下发 MANUAL_SENSOR 请求,而硬件无法处理,引发崩溃。
- 内存泄漏: 每次
getCameraCharacteristics()调用都应返回新分配的元数据,框架负责释放;HAL 侧不应缓存同一指针重复返回。
3.4 初始化流程总结
| 阶段 | 接口 | 核心产出 | 耗时要求 |
|---|---|---|---|
| 设备打开 | open() |
camera3_device_t 设备句柄 |
< 500ms |
| 会话初始化 | initialize() |
回调通道建立、资源预分配 | < 100ms |
| 能力查询 | getCameraCharacteristics() |
camera_metadata_t 静态元数据 |
< 50ms |
三个接口按序执行,构成完整的初始化链路。任何一个环节的异常都会导致 Camera HAL 无法正常提供服务。在适配过程中,建议为每个接口添加详细的日志输出(使用 ALOGD 或 ALOGE),便于定位初始化失败的具体原因。