3、Camera HAL 核心数据结构解析
Camera HAL 的移植与稳定性优化,本质上是围绕一组核心数据结构进行实例化、回调注册与状态管理的过程。本章深入解析 camera_module_t、camera_device_t 和 camera3_device_ops_t 三个关键结构体,理解它们的职责、成员布局与生命周期,是编写可移植、高性能 HAL 的基础。
3.1 camera_module_t:HAL 模块的入口
camera_module_t 是 HAL 层暴露给 Camera Service 的第一个结构体,定义在 hardware/libhardware/include/hardware/camera_common.h 中。它继承自 hw_module_t,并扩展了摄像头枚举与打开接口。
| 成员 | 类型 | 说明 |
|---|---|---|
| common | hw_module_t | 标准 HAL 模块头,包含 tag、module_api_version、hal_api_version、id、name、author、methods 等 |
| get_number_of_cameras | int (*)(void) | 返回设备上可用的摄像头总数(包括前后摄、深度、ToF 等) |
| get_camera_info | int (*)(int camera_id, struct camera_info *info) | 填充指定 camera_id 的静态信息:设备方向、 facing、orientation、device_version 等 |
| set_callbacks | int (*)(const camera_module_callbacks_t *callbacks) | 注册 Camera Service 的回调,用于热插拔通知、Torch 模式变化等 |
| get_vendor_tag_ops | void (*)(vendor_tag_ops_t* ops) | (可选)提供厂商自定义 metadata tag 的查询操作 |
| open_legacy | int (*)(const struct hw_module_t* module, const char* id, uint32_t halVersion, struct hw_device_t** device) | (可选)打开旧版本 HAL 设备,用于兼容 legacy 模式 |
| set_torch_mode | int (*)(const char* camera_id, bool enabled) | (可选)独立控制闪光灯 torch 模式,不依赖打开 camera device |
| init | int (*)(void) | (可选)模块级一次性初始化,在 get_number_of_cameras 之前调用 |
移植要点: 在实现
get_camera_info 时,device_version 必须正确设置为 CAMERA_DEVICE_API_VERSION_3_0 或更高,否则 Camera Service 不会以 Camera3 模式打开设备。同时,set_callbacks 中注册的回调指针需要保存为全局变量,用于后续热插拔事件上报。
3.2 camera_device_t:设备实例的抽象
camera_device_t 继承自 hw_device_t,代表一个已打开的摄像头设备实例。它本身是一个轻量级包装,真正的操作接口通过 ops 指针指向 camera3_device_ops_t。
typedef struct camera_device {
hw_device_t common; // 标准设备头,包含 close 函数指针
camera3_device_ops_t *ops; // Camera3 操作接口表
void *priv; // 私有数据指针,通常指向自定义的设备上下文
} camera_device_t;
三个关键字段的职责:
- common.close:关闭设备时调用,负责释放所有资源、停止流、销毁 pipeline。
- ops:指向
camera3_device_ops_t结构体,所有请求处理、流配置、metadata 交互都通过此表完成。 - priv:HAL 实现者自定义的上下文结构体,通常包含 sensor 驱动句柄、ISP 实例、stream 列表、buffer 管理器等。
常见错误: 在
open() 函数中,必须将 camera_device_t 的 ops 指针指向一个静态或持久化的 camera3_device_ops_t 实例,不能是栈变量。同时 priv 指针应在 open 时分配内存,在 close 时释放,避免内存泄漏或野指针。
3.3 camera3_device_ops_t:Camera3 操作接口表
这是 Camera HAL 中最核心的函数指针集合,Camera Service 通过它向 HAL 下发配置、请求和 buffer。结构体定义在 hardware/libhardware/include/hardware/camera3.h 中,包含约 20 个函数指针。
| 函数指针 | 调用时机 | 核心职责 |
|---|---|---|
| initialize | open 之后立即调用 | 传入 camera3_callback_ops_t,HAL 保存回调用于上报结果、事件、buffer |
| configure_streams | 每次配置流时 | 接收 camera3_stream_configuration_t,HAL 根据 stream 格式/尺寸/usage 配置 ISP 和 sensor |
| register_stream_buffers | (已废弃,可置 NULL) | 早期版本用于预注册 buffer,Camera3 已改为 request 时传递 |
| process_capture_request | 每帧请求 | 接收 camera3_capture_request_t,包含 settings、input/output buffer、物理 camera id 等 |
| flush | 快速停止所有请求 | 丢弃所有未处理的请求,已处理的正常返回,未处理的返回错误状态 |
| dump | dumpsys 时 | 输出 HAL 内部状态、buffer 队列、pipeline 延迟等信息用于调试 |
| construct_default_request_settings | 创建默认 settings | 根据模板类型(PREVIEW/STILL_CAPTURE/VIDEO_RECORD 等)返回默认 metadata |
| is_reconfiguration_required | (可选)物理 camera 切换时 | 判断是否需要重新 configure_streams |
性能关键路径:
process_capture_request 是每一帧的入口,必须做到无锁或低锁设计,避免在回调中做 IO 等待。建议使用异步 pipeline + 预分配的 request 池来降低延迟抖动。
3.4 核心结构体关系图
下图展示了 Camera Service、HAL Module、Device 与 ops 之间的层级调用关系:
3.5 生命周期与初始化顺序
理解三个结构体的初始化顺序,对移植调试至关重要:
- HAL 加载阶段: Camera Service 通过
hw_get_module()加载camera_module_t,调用get_number_of_cameras()和get_camera_info()枚举设备。 - 设备打开阶段: Service 调用
camera_module_t.open(),HAL 分配camera_device_t并填充ops指针。 - 初始化阶段: Service 调用
ops->initialize(),传入回调函数指针,HAL 保存回调并完成内部 pipeline 初始化。 - 配置与运行阶段:
configure_streams()配置流,process_capture_request()处理每一帧请求。 - 关闭阶段: Service 调用
common.close(),HAL 释放所有资源。
调试建议: 在
initialize 和 configure_streams 入口处添加 ALOGV 日志,记录传入的参数(如 stream 数量、格式、分辨率),便于定位配置不匹配问题。同时,在 process_capture_request 中记录 frame_number,用于追踪丢帧或超时。
3.6 稳定性优化关键点
| 结构体 | 常见稳定性问题 | 优化策略 |
|---|---|---|
| camera_module_t | get_camera_info 返回错误信息导致枚举失败 | 静态验证 camera_info 字段合法性;init 中做硬件探测 |
| camera_device_t | priv 指针未初始化或重复释放 | 使用 RAII 思想管理 priv 生命周期;close 后置 NULL |
| camera3_device_ops_t | process_capture_request 中死锁或长时间阻塞 | 使用无锁队列 + 工作线程;设置超时 watchdog |
| configure_streams | 流配置变化时未正确处理已有 buffer | 先 flush 再重新配置;保留 stream 状态机 |
| flush | flush 未及时返回导致 ANR | 设置 flush 超时;异步取消所有待处理请求 |