一、HAL架构
HAL(硬件抽象层,Hardware Abstraction Layer)是为了保护一些硬件提供商的知识产权而提出的,是为了避免Linux的GPL束缚。把控制硬件的动作都放到了HAL中。
新架构、调整为 HAL stub 的观念 主要包含以下一些模块:Gps、Vibrator、Wifi、Copybit、Audio、Camera、Lights、Ril、Overlay等。
HAL架构是当前Android源码中使用的思路,每一个硬件模块称为一个stub(代理人),并且借尸so的形式编译,所有的stub都要通过libhardware.so(由hardware.c)才能找到每一个stub,才能回调每一个stub中硬件抽象接口,当然stub在编写时需要按照HAL_MODULE_INFO_SYM的格式来写,通过libhardware.so找到stub时,就会将该stub加载到内存,返回该stub的模块指针。优点:采用HAL module和HAL stub结合形式,HAL stub不是共享库,上层只拥有访问stub的函数指针,并不需要stub,Runtime只需要根据module ID并通过HAL module提供的统一接口就能取得stub的操作函数,只会被映射到一个进程,不会浪费空间。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XymXBbdA-1635519984284)(https://i.imgur.com/qrtgvMc.jpg)]
二、编写一款支持HAL的Linux的驱动程序步骤
第1步:编写Linux驱动
为Linux驱动添加HAL, 尽量保护敏感数据,代码尽量简洁,将业务逻辑放到HAL Library中。
第2步:编写HAL Library
HAL Library就是普通的Linux Library(*.so)文件,这类库文件有一个接口,通过HAL_MODULE_INFO_SYM
变量实现。Service Library就是通过这个接口定义的ID来找到HAL Library的。
第3步:编写Service Library
新HAL架构要求我们必须编写。Service Library可以是Linux Library,也可以是JNI Library。还应该编写一个用JAVA写的服务管理类(ServiceManager).
ServiceManager会调用Service Library,而APK会调用ServiceManager来访问Service Library。
三、编写Linux驱动
以LED驱动为例
在之前实现的Linux驱动的基础上进行修改。去掉所有的与寄存器读写有关的代码,只保留创建设备文件及与寄存器交互的代码(只是简单的读写寄存器操作,不进行GPXDAT的具体操作)。
此环节实现在设备文件的read和write中读写指定的寄存器
编写HAL模块
struct led_module_t{
struct hw_module_t hw_module;//HAL规定不能直接使用此结构,必须在外面套上一层。
};
struct led_control_device_t{
struct hw_device_t hw_device;
int (*set_off)(...);
int(*set_on)(...);
};
#define LED_HARDWARE_MODULE_ID "led_hal"
第1步:定义结构体和宏
这两个结构体的第1个变量的数据类型必须是hw_module_t
和hw_device_t
,另外还需要为HAL模块定义一个ID。还有描述模块入口函数的hw_module_methods_t
。首先使用的是hw_module_t
,然后通过hw_module_methods_t
找到.open
函数,并且调用该函数,open函数相当于HAL模块的入口
第2步:编写HAL的open函数
- 初始化hw_device_t结构体。设置硬件操作函数(set_on和set_off)
- 打开设备文件
- 初始化寄存器
第3步:定义hw_module_methods_t结构体变量
指定open入口函数
第4步:定义HAL_MODULE_INFO_SYM变量
所有的HAL模块都必须有一个HAL_MODULE_INFO_SYM
变量,一般为hw_module_t的或者其子结构体,会初始化此结构体,其中id和methods最重要,id表示HAL模块在Android系统中的标识。
第5步:编写HAL模块的close函数
HAL模块被卸载后会调用close函数
第6步:编写控制LED的函数
编写调用HAL模块的Service
编写调用Service的JAVA库 ##
将Service程序库封装在JAR文件中。