HAL框架
当我们需要为这些设备编写HAL层代码时,必须严格按照Google定义的标准接口去实现,否则将导致设备无法在Android Framework下正常工作。
1、321架构 (包含了三个结构体和两个常量,和一个函数。)
HAL的模块接口在android\hardware\libhardware\include\hardware\hardware.h中
android\hardware\libhardware\hardware.c
模块与驱动
#define HARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', 'T')
#define HARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', 'T')
(1)三个结构体
/提供了非常多的模块信息需要在初始化的时候去填充,最为关键的是hw_module_methods_t里的open函数/
/主要参数id,name ,这个是唯一的,一般id与name是相同/
对于struct hw_module_t结构体的理解为,每个硬件通过hw_module_t结构体来描述,我们可以"继承"这个结构体,拓展自己的属性,但是需要注意的是,宿主结构的第一个成员必须是struct hw_module_t类型,硬件对象必须定义一个固定的名字:HMI(Hardware Module Information),每个硬件对象里面都包含了module指针,对应得结构体里面封装了open函数指针,用于打开硬件,并会返回硬件的操作方式。
typedef struct hw_module_t {
uint32_t tag;
uint16_t module_api_version;
uint16_t hal_api_version;
const char *id;
const char *name;
const char *author;
struct hw_module_methods_t* module;
void* dso;
uint32_t reserved[32-7];
} hw_module_t;
tag:该值为module的tag,必须定义为HARDWARE_MODULE_TAG;
module_api_version:模块中API函数接口的版本号;
hal_api_version:HAL模块接口的API版本号;
id:硬件的id号,唯一标识模块;
name:该模块的名称;
author:模块的作者;
module:指向封装有open函数指针的结构体,用于模块打开
该结构体里面封装了一个open函数指针,该函数用于实现打开一个特定的设备,打开的设备通过device二级指针进行返回。
typedef struct hw_module_methods_t { /使用在hw_module里,提供了一个open方法需要具体去实现/
/** Open a specific device */
int (*open)(const struct hw_module_t* module, const char* id,
struct hw_device_t** device);
} hw_module_methods_t;
对于struct hw_device_t结构体的理解为,硬件设备的操作方法,通过struct module_methods_t结构内的open函数指针将返回hw_device_t结构体指针,从而获得了该硬件设备的操作方法,我们也可以"继承"该结构体,拓展实际硬件设备的操作方式,但是需要注意的是,在宿主结构中,第一个成员必须是struct hw_device_t类型。
typedef struct hw_device_t {
uint32_t tag;
uint32_t version;
struct hw_module_t* module;
uint32_t reserved[12];
int (*close)(struct hw_device_t* device);
} hw_device_t;
tag:设备的tag,必须定义为HARDWARE_DEVICE_TAG;
version:设备操作方式的版本号;
module:hw_module_t结构体指针,指向设备所属的硬件模块,设备操作接口与硬件模块的联系;
close:函数指针,关闭该硬件设备的方法。
(2)两个常量
#define HAL_MODULE_INFO_SYM HMI
#define HAL_MODULE_INFO_SYM_AS_STR "HMI"
这两个常量与HAL模块的入口相关,在上层调用hw_get_module时,通过模块ID和对应的HMI结构体找到模块入口,
然后通过之前的open函数接口,就可以获得设备的操作接口(hw_device_t),之后就可以通过module访问模块实现的相关函数。
(3)一个函数(新版本有两个)
/通过ID获取模块相关联的信息/
int hw_get_module(const char *id, const struct hw_module_t **module);
/通过类"class_id"和实例"inst"获取与模块实例相关的模块信息/
int hw_get_module_by_class(const char *class_id, const char *inst, const struct hw_module_t **module);
当用户调用hw_get_module()函数时,将硬件的id名进行传入,那么函数将会从当前系统中注册的硬件模块里查找对应的硬件模块,并通过module二级指针进行返回。
2、hal实现方法
(1)定义一个 struct xx_hw_module_t 结构体,必须在第一个,定义一个 hw_module_t结构体的变量,还可以定义其他功能函数
(2)定义一个 struct xx_hw_module_methods_t 结构体,实现open函数
(3)定义一个 struct xx_hw_device_t 结构体,必须在第一个,定义一个 hw_device_t结构体的变量,还可以定义其他功能函数
如在hardware\libhardware\include\hardware\fd.h中framebuffer(显示器驱动)
typedef struct framebuffer_device_t {
struct hw_device_t common; //第一个就定义了一个hw_device_t
。。。。。。
}
(4)定义 xx_HARDWARE_MODULE_ID 字符串变量,每个模块唯一的一个变量
(5)创建一个名字为 HAL_MODULE_INFO_SYM 的xx_hw_module_t对象
3、获取,释放Module和Device结构对象的方法(获取HAL的流程)
(1)使用hw_get_module 传入目标HAL的id
(2)根据id,拼装成路径,去寻找对应的.so文件
(3)使用dlopen加载打开对应的so文件。
(4)使用dlsyn加载符号表中的 HAL_MODULE_INFO_SYM 即对应的 xx_hw_module_t变量转换成hw_module_t指针返回。
上面四步在代码中的体现
hw_get_module 调用->hw_get_module_by_class -> 通过hw_module_exists找到对应的模块 -> 调用load-> 调用dlopen,打开这个动态链接库 -> 再调用 dlsym 通过HAL_MODULE_INFO_SYM_AS_STR 去寻找 链接库里的 HAL_MODULE_INFO_SYM-> 然后返回 hw_module_t指针
(5)根据获取到的module指针,获取 xx_hw_module_methods_t 调用 open 函数获取 hw_device_t结构体
(6)使用 hw_device_t指针调用定义的功能函数