3. HAL模块加载机制
HAL(Hardware Abstraction Layer)模块加载机制是Camera HAL层初始化的核心入口。Android系统通过标准化的结构体定义与回调函数接口,实现HAL模块的动态发现、加载与生命周期管理。理解这一机制,是掌握Camera HAL层开发的基础。
3.1 HAL module结构体定义
每个HAL模块都必须以hw_module_t结构体作为起始成员。该结构体定义在hardware/libhardware/include/hardware/hardware.h中,是HAL模块与Android框架之间的契约。
| 成员 | 类型 | 说明 |
|---|---|---|
| tag | uint32_t | 必须初始化为HARDWARE_MODULE_TAG,用于版本校验 |
| module_api_version | uint16_t | 模块API版本号,如HAL_MODULE_API_VERSION(1, 0) |
| hal_api_version | uint16_t | HAL框架层API版本号 |
| id | const char* | 模块唯一标识符,如"camera" |
| name | const char* | 模块可读名称,如"Camera HAL Module" |
| author | const char* | 模块作者或厂商信息 |
| methods | hw_module_methods_t* | 指向回调函数结构体的指针,核心接口 |
| dso | void* | 模块动态库句柄,由加载器填充 |
| reserved | uint32_t[32] | 保留字段,用于未来扩展 |
关键点:Camera HAL模块的
hw_module_t实例必须使用HAL_MODULE_INFO_SYM(即HMI)作为符号名导出,这是Android HAL加载器查找模块入口的约定。
3.2 hw_module_methods_t回调函数
hw_module_methods_t是HAL模块暴露给框架层的唯一回调结构体,目前只包含一个函数指针——open。该结构体定义如下:
typedef struct hw_module_methods_t {
int (*open)(const struct hw_module_t* module,
const char* id,
struct hw_device_t** device);
} hw_module_methods_t;
open回调的三个参数含义:
- module:指向当前HAL模块实例的指针
- id:要打开的设备标识符,如
"0"表示Camera ID 0 - device:输出参数,指向新创建的
hw_device_t结构体指针
框架层通过hw_get_module()加载HAL模块后,立即调用methods->open()来获取具体设备实例。这意味着open函数是HAL模块从“静态描述”进入“运行时设备”的桥梁。
3.3 open/close接口实现
open接口的实现通常包含以下步骤:
- 参数校验:检查module和device指针非空,id合法
- 内存分配:为Camera设备结构体(如
camera_device_t)分配内存 - 初始化:填充设备结构体的ops函数表、私有数据等
- 硬件准备:打开驱动节点、初始化传感器、分配内存池
- 返回设备:将设备结构体指针写入
*device
static int camera_device_open(const hw_module_t* module,
const char* id,
hw_device_t** device) {
if (module == NULL || device == NULL) {
return -EINVAL;
}
camera_device_t* cam_dev = (camera_device_t*)malloc(sizeof(camera_device_t));
if (cam_dev == NULL) {
return -ENOMEM;
}
memset(cam_dev, 0, sizeof(camera_device_t));
cam_dev->common.tag = HARDWARE_DEVICE_TAG;
cam_dev->common.version = CAMERA_DEVICE_API_VERSION_1_0;
cam_dev->common.module = (hw_module_t*)module;
cam_dev->common.close = camera_device_close;
// 填充ops函数表
cam_dev->ops = &camera_ops;
// 初始化私有数据(如驱动句柄、流状态等)
cam_dev->priv = init_camera_private_data(atoi(id));
*device = &cam_dev->common;
return 0;
}
close接口负责资源释放:
static int camera_device_close(hw_device_t* device) {
camera_device_t* cam_dev = (camera_device_t*)device;
if (cam_dev == NULL) {
return -EINVAL;
}
// 释放私有数据资源
if (cam_dev->priv) {
deinit_camera_private_data(cam_dev->priv);
}
free(cam_dev);
return 0;
}
注意:
open和close必须保证线程安全。在多Camera场景下,多个客户端可能同时调用open打开不同Camera ID,需要合理使用互斥锁保护共享资源。
3.4 HAL module ID注册
HAL模块的ID注册通过hw_module_t结构体的id字段实现。Camera HAL模块的ID固定为"camera"。完整的模块定义示例如下:
static struct hw_module_methods_t camera_module_methods = {
.open = camera_device_open
};
camera_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = CAMERA_MODULE_API_VERSION_1_0,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = "camera",
.name = "Camera HAL Module",
.author = "Your Company",
.methods = &camera_module_methods,
.dso = NULL,
.reserved = {0}
},
.get_number_of_cameras = get_number_of_cameras,
.get_camera_info = get_camera_info
};
Android HAL加载器通过以下流程定位模块:
- 根据
id(如"camera")在系统库路径中搜索camera.<variant>.so - 使用
dlopen()加载动态库 - 通过
dlsym()查找HAL_MODULE_INFO_SYM符号 - 验证
tag和版本号,返回hw_module_t指针
最佳实践:在
camera_module_t中扩展的get_number_of_cameras和get_camera_info是Camera HAL特有的接口,用于向框架层报告设备数量和能力。这些接口在open之前被调用,因此实现时不应依赖设备级别的资源。
3.5 模块加载机制总结
| 组件 | 职责 | 关键约定 |
|---|---|---|
| hw_module_t | 模块元数据描述,包含ID、版本、方法表 | 必须使用HAL_MODULE_INFO_SYM导出 |
| hw_module_methods_t | 提供open回调,创建设备实例 |
目前仅包含一个函数指针 |
| open接口 | 分配并初始化设备结构体,返回hw_device_t |
必须校验参数、保证线程安全 |
| close接口 | 释放设备资源,清理内存 | 与open成对出现,防止内存泄漏 |
| ID注册 | 通过id字段标识模块类型 |
Camera模块固定为"camera" |
核心要点:HAL模块加载机制的本质是“约定优于配置”——通过固定的结构体布局、固定的符号名、固定的回调接口,让框架层无需了解具体实现细节即可加载和操作任何HAL模块。这种设计模式在Android系统中被广泛使用,是HAL层可插拔架构的基石。