背景
hi,粉丝朋友们: 大家好!今天来一个经典hal的实现,首先说一下哈,经典hal在正常在Treble计划后就不再建议使用了,高版本一般都是hidl,aidl。目前新版本一般都是强制使用aidl,那为啥还需要讲解这个经典hal呢?
1、虽然采用了treble计划后,system/vendor隔离后,但是因为经典hal是个so,而且代码一般不需要强依赖so,具有一个非常好的移植性,导致虽然变成了google要求的hidl,其实内部依然实现是经典hal的so
2、经典hal so在trable计划以前已经经历了很多个版本,业务执行的稳定性很好,基本上厂商没啥动力推倒重来,基于新的hidl,aidl再写一遍hal业务
总结:treble计划虽然系统已经大部分都是hidl,aidl实现方式,但是这个只是一个对外接口层面的,内部实现的话其实完全可以继续调用以前写好的经典hal,这个方式保证了稳定性,修改量小
所以基于以上背景,掌握经典hal的相关知识完全是有必要的,不然就可能会导致你根本看不懂很多hal实现
HAL module的架构分析
注意这里只进行依赖libhardware库这种方式实现,不讲解legacy方式
HAL module架构主要分为以下3个结构体:
struct hw_module_t struct hw_module_methods_t struct hw_device_t
3个结构体是写这个标准方式hal的最关键部分,它们定义是在 hardware/libhardware/include/hardware/hardware.h
下面3个进行详细介绍其功能和作用
hw_module_t部分
相关的定义代码如下:
代码很少,注释很多,不过都是英文的,这里给大家总结一下,即常用的成员变量:
1、每一个hardware硬件抽象模块必须定义有一个模块结构体,名字是HAL_MODULE_INFO_SYM,即HMI,这个模块结构体第一个成员变量类型必须是hw_module_t
2、hw_module_t的tag的值必须为HARDWARE_MODULE_TAG,这个就是来标识是硬件抽象的结构体
3、id这个属性代表这个module的唯一性,即每个硬件抽象模块都会有自己的id
4、methods这个代表每个硬件抽象模块对应的方法结构体,类型hw_module_methods_t
常见定义和实现方式如下:
定义结构体:
实例化HAL_MODULE_INFO_SYM:
hw_module_methods_t部分
在结构体 hw_module_methods_t 中只有一个成员,它是一个函数指针,名字是open,它主要作用就是用来打开硬件抽象层中给的硬件设备。因为一个硬件抽象模块module可以包含多个设备device,所以这里需要指定id。
moudlue:代表打开硬件设备设备所属模块 id:代表打开设备的id device:这个双重指针,一般是输出内容到这个参数里面,即返回值,用来描述一个打开的硬件设备
hw_device_t部分
其实这个和前面的hw_module_t高度相识,只不过一个代表整个模块一个代表模块的设备 同样总结一下hw_device_t:
1、每个硬件设备都必须自定义一个硬件设备的结构体,第一个成员变量为hw_device_t
2、tag必须为所在的硬件模块HARDWARE_DEVICE_TAG,代表他是个硬件设备结构体
3、会有一个close的函数指针,主要是关闭一个硬件设备
4、自定义设备结构体,除了第一个成员hw_device_t外,最重要就是会定义其他成员方法指针,这些方法就是用来对外提供操作硬件设备的
常见自定义的hw_device_t如下:
构造结构过程:
上面最重要就是把hw_device_t构造出,而且给成员变量test赋值了具体方法,后面获取了这个hw_device_t就可以调用真正的hal实现方法了
HAL module的使用步骤
上面只是一个个的定义好硬件抽象模块的步骤,接下来是要要怎么使用上面的hardware接口进行调用到相关的hal方法呢? 1、通过hw_get_module(char* id, struct hw_module_t ** module) 方法获取一个硬件抽象模块的指针
2、通过模块调用module->common.methods->open()方法获取一个硬件抽象即hw_device_t的指针
3、使用硬件抽象设备的hw_device_t指针调用具体的hal实现方法,比如上面 mytest_dev->addTest
相关调用hal的代码如下:
hardware.c源码分析
上面使用的hw_get_module这些方法到底在哪里实现的呢? 其实这些代码的实现都是在hardware.c文件中 下面从hw_get_module方法作为切入点全面展开分析一下相关的 hardware/libhardware/hardware.c
hw_module_exists会根据传递进来的name,subname,然后去拼出一个so的文件名字,看看这个so文件是否存在,存在这返回找到
上面可以看出hw_module_exists会去几个路径找,优先级是oem > vendor> system
如果prop指定的都没有找到最后只能用最后的default看看是否存在,如果这个default so都没有,那么就会报错了,即无法获取到对于的硬件抽象模块,说明硬件抽象这部分功能就无法使用了。
一般情况下都最少可以找到一个default的so,那么找到后会执行上面的load方法,把这个so进行相关load
这个load方法是最关键的,来看看系统到底是怎么实现的:
补充介绍一下两个函数: dlopen()是一个强大的库函数。该函数将打开一个新库,并把它装入内存。该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的。 dlsym是一个计算机函数,功能是根据动态链接库操作句柄与符号,返回符号对应的地址,不但可以获取函数地址,也可以获取变量地址。
上面的load方法就是我们说的hardware动态性的关键,它是在运行时候才真正依赖具体硬件抽象so,编译期间只需要依赖公共的hardware相关公共类既可以,不需要so,所以这里就给硬件抽象提供商带来很大灵活性,哪怕硬件厂商不提供也一般会有一个default的so保证不会产生什么严重的崩溃和强依赖问题,大大减低了aosp的代码对于硬件抽象的各个厂商的耦合性。
这里看看手机上的相关hal so:
这里在看看哪个prop是ms8998
本文章对应视频手把手教你学framework:
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
私聊作者+v(androidframework007)
点击这里 https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw
视频:https://www.bilibili.com/video/BV1Jg4y1C7fw/
本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕,E-mail:xinmeigg88@163.com
本文链接:http://www.xrbh.cn/tnews/11622.html