3. 传统HAL(libhardware)架构:hw_module_t与hw_device_t结构体详解,动态库加载机制
传统HAL(libhardware)是Android早期(至Android 8.0之前)的标准硬件抽象层实现。其核心设计围绕两个关键结构体——hw_module_t和hw_device_t展开,并通过动态库加载机制实现Framework与底层驱动的解耦。本章将深入剖析这两个结构体的内存布局、字段含义,以及HAL模块的加载与初始化流程。
3.1 hw_module_t:硬件模块的“身份证”
hw_module_t是每个HAL模块必须暴露的第一个结构体,它描述了模块的基本信息,并提供了打开设备实例的入口。该结构体定义在hardware/libhardware/include/hardware/hardware.h中。
核心要点:每个HAL共享库必须导出一个名为
HAL_MODULE_INFO_SYM(即HMI)的hw_module_t实例,这是Framework加载器识别模块的唯一入口。
typedef struct hw_module_t {
/** 标签,必须设置为 HARDWARE_MODULE_TAG */
uint32_t tag;
/** 模块主版本号 */
uint16_t version_major;
/** 模块次版本号 */
uint16_t version_minor;
/** 模块ID,用于标识模块类型,如 "audio"、"gps"、"lights" */
const char *id;
/** 模块名称(可读字符串) */
const char *name;
/** 模块作者/厂商信息 */
const char *author;
/** 模块自定义数据指针,通常用于扩展 */
struct hw_module_methods_t* methods;
/** 模块的dso句柄,由加载器填充,指向动态库的句柄 */
void* dso;
/** 预留字段,用于未来扩展,必须初始化为0 */
uint32_t reserved[32-7];
} hw_module_t;
| 字段 | 类型 | 说明 |
|---|---|---|
tag |
uint32_t |
必须为HARDWARE_MODULE_TAG(0x484D4F44),用于校验结构体有效性 |
version_major |
uint16_t |
主版本号,不兼容的API变更时递增 |
version_minor |
uint16_t |
次版本号,向后兼容的扩展时递增 |
id |
const char* |
模块标识字符串,如"audio"、"gps",用于匹配加载 |
methods |
struct hw_module_methods_t* |
指向模块方法表,目前仅包含open函数指针 |
dso |
void* |
动态库句柄,由hw_get_module自动填充,模块自身不应修改 |
3.2 hw_device_t:硬件设备的“操作手柄”
hw_device_t代表一个具体的硬件设备实例。当调用hw_module_methods_t::open成功后,Framework会获得一个指向hw_device_t的指针,通过它来操作硬件。
typedef struct hw_device_t {
/** 标签,必须设置为 HARDWARE_DEVICE_TAG */
uint32_t tag;
/** 设备版本号 */
uint32_t version;
/** 指向所属模块的指针 */
struct hw_module_t* module;
/** 预留字段,必须初始化为0 */
uint32_t reserved[12];
/** 关闭设备的函数指针 */
int (*close)(struct hw_device_t* device);
} hw_device_t;
设计模式:
hw_device_t采用“公共基类+私有扩展”的模式。每个具体的HAL(如Camera、Audio)都会在hw_device_t的基础上,通过结构体嵌套或指针转换,扩展出自己特有的操作函数和属性。
3.3 hw_module_methods_t:打开设备的唯一入口
hw_module_methods_t结构体目前只包含一个函数指针——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;
- 参数
module:指向当前模块的指针,由Framework传入。 - 参数
id:设备标识符,用于区分同一模块下的不同设备(如主摄像头与副摄像头)。 - 参数
device:输出参数,指向新创建的hw_device_t实例。 - 返回值:0表示成功,负数表示错误码。
3.4 动态库加载机制:hw_get_module 流程
Framework通过hw_get_module函数加载HAL模块。该函数封装了动态库的查找、打开和符号解析过程。其核心流程如下:
- 确定模块路径:根据模块ID,在预定义的搜索路径列表中查找对应的
.so文件。默认路径包括/vendor/lib/hw/、/system/lib/hw/等。 - 调用
dlopen:使用dlopen打开共享库,获取句柄。 - 查找符号
HMI:通过dlsym查找HAL_MODULE_INFO_SYM符号,即hw_module_t实例。 - 校验
tag字段:验证hw_module_t的tag是否为HARDWARE_MODULE_TAG,防止加载错误模块。 - 填充
dso字段:将dlopen返回的句柄赋值给hw_module_t::dso。 - 返回模块指针:将校验通过的
hw_module_t指针返回给调用者。
兼容性注意:传统HAL的
hw_get_module依赖固定的文件路径和命名规则(如audio.primary.<board>.so)。在Treble架构中,这一机制被HIDL服务注册和dlopen替代,但底层思想仍然延续。
3.5 结构体关系与加载流程SVG图
下图展示了hw_module_t、hw_device_t、hw_module_methods_t三者之间的关系,以及hw_get_module的加载流程:
3.6 典型HAL模块实现示例
以下是一个虚拟“LED”HAL模块的简化实现,展示了hw_module_t和hw_device_t的典型用法:
/* led_hal.c - 虚拟LED HAL模块实现 */
/* 定义LED设备特有的结构体,继承自hw_device_t */
struct led_device_t {
struct hw_device_t common; /* 基类必须放在第一个字段 */
/* LED特有操作 */
int (*set_on)(struct led_device_t* dev, int on);
int (*set_brightness)(struct led_device_t* dev, int level);
};
/* 打开设备函数 */
static int led_open(const struct hw_module_t* module, const char* id,
struct hw_device_t** device) {
struct led_device_t* dev = malloc(sizeof(struct led_device_t));
memset(dev, 0, sizeof(*dev));
/* 填充基类 */
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 1;
dev->common.module = (struct hw_module_t*)module;
dev->common.close = led_close;
/* 填充特有操作 */
dev->set_on = led_set_on_impl;
dev->set_brightness = led_set_brightness_impl;
*device = (struct hw_device_t*)dev;
return 0;
}
/* 模块方法表 */
static struct hw_module_methods_t led_methods = {
.open = led_open,
};
/* 模块实例 - 必须导出为 HMI 符号 */
struct hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = "led",
.name = "Virtual LED HAL",
.author = "Embedded Expert",
.methods = &led_methods,
.dso = NULL, /* 由加载器填充 */
};
关键点回顾:
hw_module_t是模块的静态描述,每个共享库只有一个实例。hw_device_t是设备实例,每次open调用可能创建多个实例(如多个摄像头)。- 动态库加载通过
dlopen/dlsym实现,hw_get_module封装了查找和校验逻辑。 - 具体HAL通过结构体嵌套扩展
hw_device_t,实现多态效果。