3. Camera HAL 基础数据结构:核心结构体解析
Camera HAL 层是 Android 相机框架中连接 Framework 与硬件驱动的关键桥梁。理解其核心数据结构,是进行驱动调试与性能优化的第一步。本章将深入解析 camera_module_t、camera_device_t 和 camera3_device_t 三个最基础的结构体,阐明它们在 HAL 架构中的角色、成员含义及初始化流程。
3.1 结构体总览与层级关系
在 Android Camera HAL 中,这三个结构体构成了从模块加载到设备操作的完整链路:
- camera_module_t:HAL 模块的入口,负责枚举相机设备并创建实例。
- camera_device_t:HAL v1 接口的设备抽象,代表一个物理或逻辑相机。
- camera3_device_t:HAL v3 接口的设备抽象,支持更复杂的 pipeline 和 metadata 流。
调试要点: 在调试过程中,首先需要确认 HAL 库导出的
HAL_MODULE_INFO_SYM 符号是否正确初始化了 camera_module_t,这是 Framework 加载 HAL 的第一步。
3.2 camera_module_t:HAL 模块入口
camera_module_t 定义在 hardware/libhardware/include/hardware/camera_common.h 中,是 HAL 模块的标准接口。它继承自 hw_module_t,并扩展了相机特有的方法。
| 成员 | 类型 | 说明 |
|---|---|---|
common |
hw_module_t |
标准 HAL 模块头,包含 tag、module_api_version、hal_api_version、id、name、author、methods 等。 |
get_number_of_cameras |
函数指针 | 返回系统中可用的相机设备数量。 |
get_camera_info |
函数指针 | 获取指定 ID 相机的静态信息(camera_info),包括朝向、是否支持闪光灯等。 |
set_callbacks |
函数指针 | 注册 HAL 回调函数(如相机热插拔通知),仅 HAL v3 及以上版本使用。 |
get_vendor_tag_ops |
函数指针 | 获取厂商自定义 metadata tag 的操作接口。 |
open_legacy |
函数指针 | 以指定 HAL 版本打开相机设备(用于兼容旧版)。 |
set_torch_mode |
函数指针 | 设置闪光灯 torch 模式,独立于相机打开状态。 |
init |
函数指针 | HAL 模块初始化函数,在模块加载时调用。 |
关键调试点: 在
get_camera_info 中返回的 camera_info.device_version 字段决定了 Framework 使用 HAL v1 还是 v3 接口。如果该值设置错误,会导致设备无法打开或功能异常。
3.3 camera_device_t:HAL v1 设备抽象
camera_device_t 是 Android Camera HAL v1 接口的核心,定义在 hardware/libhardware/include/hardware/camera.h 中。它封装了相机设备的操作句柄和所有控制方法。
typedef struct camera_device {
hw_device_t common; // 标准设备头
camera_device_ops_t *ops; // 操作函数表
void *priv; // 私有数据指针,指向驱动上下文
} camera_device_t;
核心成员解析:
- common:继承自
hw_device_t,包含设备打开/关闭、版本号等基础信息。 - ops:指向
camera_device_ops_t结构体,该结构体包含约 30 个函数指针,如set_preview_window、start_preview、take_picture等。 - priv:通常指向驱动自定义的上下文结构体,用于保存设备状态、流信息等。
常见陷阱: 在 HAL v1 实现中,
ops 中的函数指针必须全部正确赋值,否则 Framework 调用未初始化的函数指针会导致空指针崩溃。建议在初始化时使用 memset 清零后逐一赋值。
3.4 camera3_device_t:HAL v3 设备抽象
camera3_device_t 是 HAL v3 接口的设备抽象,定义在 hardware/libhardware/include/hardware/camera3.h 中。相比 v1,v3 接口更加灵活,支持复杂的 capture session 和 metadata 流控制。
typedef struct camera3_device {
hw_device_t common; // 标准设备头
camera3_device_ops_t *ops; // v3 操作函数表
void *priv; // 私有数据指针
} camera3_device_t;
与 v1 的关键差异:
| 对比维度 | camera_device_t (v1) | camera3_device_t (v3) |
|---|---|---|
| 操作模型 | 基于预览/拍照/录像的固定流程 | 基于 request/result 的 pipeline 模型 |
| 数据传递 | 直接操作 buffer 地址 | 通过 camera3_stream_buffer 和 metadata |
| 同步机制 | 简单回调 | 支持 fence 和 release fence 同步 |
| 核心函数 | start_preview、take_picture |
process_capture_request、flush |
| 设备打开函数 | camera_device_open |
camera3_device_open |
3.5 结构体初始化与生命周期
在 HAL 实现中,这三个结构体的初始化遵循严格的顺序:
- 模块加载阶段:
HAL_MODULE_INFO_SYM静态初始化camera_module_t,填充common.methods指向hw_module_methods_t。 - 设备打开阶段:Framework 调用
camera_module_t.common.methods->open(),HAL 内部创建并初始化camera_device_t或camera3_device_t。 - 设备使用阶段:通过
ops中的函数指针进行预览、拍照、录像等操作。 - 设备关闭阶段:调用
close()释放资源,销毁设备结构体。
优化建议: 在
open() 函数中,建议使用 calloc 分配设备结构体内存,确保所有字段初始化为零,避免未初始化字段导致的不确定行为。同时,priv 指针指向的上下文结构体应包含互斥锁,以保护多线程访问。
3.6 调试实战:验证结构体正确性
在调试 Camera HAL 时,可以通过以下方法验证结构体的正确性:
- 检查模块符号:使用
dlopen和dlsym加载 HAL 库,验证HAL_MODULE_INFO_SYM是否指向有效的camera_module_t。 - 验证函数指针:在
open()返回前,打印ops中关键函数指针的地址,确保不为 NULL。 - 检查版本号:确认
common.module_api_version和common.hal_api_version与预期匹配。 - 使用 log 追踪:在
get_camera_info、open、close等关键函数中添加 ALOGV/ALOGD 日志,追踪调用流程。
常见错误: 如果
camera_module_t 中的 get_number_of_cameras 返回 0,Framework 将认为系统没有相机设备,导致相机应用无法启动。请确保该函数返回正确的相机数量。