1、前言
Android系统硬件抽象层(Hardware Abstraction Layer),简写为HAL,是连接Android Framework与Linux内核设备驱动的重要桥梁。HAL存在的意义有以下两个方面:
(1)HAL层屏蔽掉不同硬件设备的差异,为Android提供了统一的设备访问接口。不同的硬件厂商遵循HAL标准来实现自己的硬件控制逻辑,开发者不必关心硬件设备的差异,只需按照HAL提供的标准接口对硬件进行访问即可。
(2)HAL层帮助硬件厂商隐藏了设备的核心细节,HAL层位于用户空间,遵循Apache协议,允许硬件厂商不公开源码,将设备相关的实现放在HAL层中实现,并以共享库(.so)的形式进行提供。
下面的图描述了HAL层在Android系统中的位置:
使用HAL这种设计模式,使得上层服务与底层硬件之间的耦合度降低。
2、Stub HAL
Android系统中HAL具有两种实现方式:Legacy以及Stub HAL,初期使用的是Legacy HAL的方式,该方式为标准的Linux共享库,其它应用程序直接调用HAL层共享库导出的函数。Google后来提出了Stub HAL的方式,仍然以共享库(.so)的形式提供,它把所有供外部访问的的方法(函数)的入口指针保存在统一的数据结构,其它程序需要访问HAL中方法时,需要先获得Stub,然后通过具体的函数指针去读写底层设备。
3、HAL标准接口的定义
Android已经为常用的硬件设备定义了标准的HAL接口,这些组件有以下:
当我们需要为这些设备编写HAL层代码时,必须严格按照Google定义的标准接口去实现,否则将导致设备无法在Android Framework下正常工作。
关于HAL的源码在Android源码树的hardware目录,其中关于Stub方式的HAL实现在libhardware目录下:
# 常用设备HAL标准接口的头文件 AOSP/hardware/libhardware/include/hardware # 常用设备HAL标准接口实现 AOSP/hardware/libhardware/modules/
在目录AOSP/hardware/libhardware/include/hardware中包含了一个hardware.h的接口头文件,里面具有比较重要的结构体、变量和函数指针,在开发自己设备的HAL文件时,需要嵌入这些结构体,也就是继承它们的特性,接下来对这些标准接口做介绍。
首先是struct hw_module_t结构体,定义如下:
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函数指针的结构体,用于模块打开。
对于struct hw_module_t结构体的理解为,每个硬件通过hw_module_t结构体来描述,我们可以"继承"这个结构体,拓展自己的属性,但是需要注意的是,宿主结构的第一个成员必须是struct hw_module_t类型,硬件对象必须定义一个固定的名字:HMI(Hardware Module Information),每个硬件对象里面都包含了module指针,对应得结构体里面封装了open函数指针,用于打开硬件,并会返回硬件的操作方式。
接下来是struct hw_module_methods_t结构体的定义,如下所示:
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函数指针,该函数用于实现打开一个特定的设备,打开的设备通过device二级指针进行返回。
另外一个重要的结构体为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:函数指针,关闭该硬件设备的方法。
对于struct hw_device_t结构体的理解为,硬件设备的操作方法,通过struct module_methods_t结构内的open函数指针将返回hw_device_t结构体指针,从而获得了该硬件设备的操作方法,我们也可以"继承"该结构体,拓展实际硬件设备的操作方式,但是需要注意的是,在宿主结构中,第一个成员必须是struct hw_device_t类型。
在上面介绍的三个结构之间是紧密联系的,每个硬件模块都由一个struct hw_module_t结构体进行描述,当用户拿到了这个硬件模块,调用其封装的open函数,便返回了硬件设备的操作方法接口,从而便可以调用相关接口对硬件设备进行读写了。
在HAL标准中还有两个比较重要的宏定义和一个函数,如下:
/** * Name of the hal_module_info */ #define HAL_MODULE_INFO_SYM HMI /** * Name of the hal_module_info as a string */ #define HAL_MODULE_INFO_SYM_AS_STR "HMI" /** * Get the module info associated with a module by id. * * @return: 0 == success, <0 == error and *module == NULL */ int hw_get_module(const char *id, const struct hw_module_t **module);
在上面的代码中,HAL_MODULE_INFO_SYM为硬件模块固定的变量名,另外一个宏只是字符串的显示,当用户调用hw_get_module()函数时,将硬件的id名进行传入,那么函数将会从当前系统中注册的硬件模块里查找对应的硬件模块,并通过module二级指针进行返回。
4、小结
本篇文章对Android系统中HAL的基本概念做简单介绍,另外,对HAL提供的接口进行了简单的描述。