HAL层实例完成后知识点总结。
手动写完hal实例这里总结几个知识点。
源码:(开始同步github啦,希望有人支持)
https://github.com/cshang983255766/MyAndroidOpenTest/tree/master/myfake
1.驱动属于内核空间,调用驱动的client属于用户空间。hal就是这两个空间的链接。了解过binder之后,觉得binder和hal的关系很密切。后面写向上层调用服务接口时会涉及到。
这里总结一下个人理解:1、硬件抽象层的动态库会在系统启动时自动加载,加载时会自动调用hw_module_methods_t 结构体中的open方法,
与驱动绑定。
2、硬件抽象层是通过jni供给服务层用的,client进程是通过binder和servicemanager来找到服务的。系统启动时会在systemserver中
把服务add到servicemanager中。加载的时候会加一个服务独有的句柄。client进程想调服务时,
在进程中通过xxx = xxx.Stub.asInterface(ServiceManager.getService(句柄))来获取到服务,此时xxx就拥有了在
服务接口(xxx.aidl)中定义的方法。这些方法通过服务-->jni-->hal-->driver(kernel space)索引到驱动层的函数。
2、知道hal是链接内核空间和用户空间之后,那具体是怎么链接的呢?接口通过什么规则定义呢?
硬件抽象层有两个重要的数据结构:硬件模块结构体 hw_module_t 和 硬件接口结构体 hw_device_t。
Android HAL 将各类硬件设备抽象为硬件模块,使用 hw_module_t 来描述这一模块,每个硬件抽象模块都对应一个动态链接库,这一般是由厂商提供的。
而每一类硬件抽象模块又包含多个独立的硬件设备,使用 hw_device_t 结构体描述硬件模块中的独立硬件设备。
HAL 规定每个硬件模块必须包含一个 HAL_MODULE_INFO_SYM 的结构体,这个结构体的第一个元素必须为 hw_module_t,然后后面可以增加模块相关的其他信息。其中,tag属性也必须为 HARDWARE_MODULE_TAG 常量。
以上几行是网上看得到别人总结的。可供参考。
自己总结如下:
1>文件树:
android4.2.2\hardware\libhardware
----include
----hardware
----myfake.h
----modules
----myfake
----myfake.cpp
----Android.mk
2>两个重要的结构体
hw_module_t和hw_device_t 。
hw_module_t用来描述某个模块,hw_device_t用于描述模块下的设备,
//硬件模块结构体
struct myfake_module_t
{
struct hw_module_t common;
};
//硬件接口结构体
struct myfake_device_t
{
struct hw_device_t common;
int fd;
int (*set_val)(struct myfake_device_t* dev, int val);
int (*get_val)(struct myfake_device_t* dev, int* val);
};
hal注册的时候会首先注册module:
//定义模块结构体变量
struct myfake_module_t HAL_MODULE_INFO_SYM = { //此处必须是HAL_MODULE_INFO_SYM。否则系统索引不到。
common :
{
tag : HARDWARE_MODULE_TAG,
version_major : 1,
version_minor : 0,
id : MYFAKE_HARDWARE_MODULE_ID,
name : MODULE_NAME,
author : MODULE_AUTHOR,
methods : &myfake_module_methods, //模块中的方法一般是open方法,用途打开module中的device。
},
};
通过结构体中的id来索引hal中的设备和方法。其中dev->common.tag必须为HARDWARE_DEVICE_TAG。
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (hw_module_t*)module;
dev->common.close = myfake_device_close;
dev->set_val = myfake_set_val;
dev->get_val = myfake_get_val;
至此就打通了经脉。其他写法规则可以查hardware/libhardware/include/hardware/hardware.h
3、hal是以动态库的形式加载到系统中,放在/system/lib/hw 目录下。当client调用module->methods->open(module, MYFAKE_HARDWARE_MODULE_ID, (struct hw_device_t **)device);方法时,系统会通过MYFAKE_HARDWARE_MODULE_ID找到对应的.so文件。
并且对编译生成的文件名也有要求必须为<MYFAKE_HARDWARE_MODULE_ID>.default.so。其中default也可以为其他ro.hardware、ro.product.board、ro.board.platform和ro.arch其中之一。
另外:(其中myfake是我的驱动名称)
我们将硬件抽象层模块myfake对应的文件名称定义为myfake.default,编译成功后,系统就会自动在后面加后缀.so,于是就得到了一个myfake.default.so文件。根据硬件抽象层模块文件的命名规范,当我们要加载硬件抽象层模块myfake时,只需要指定它的名字,即“myfake‖,系统就会根据一定的规则成功地找到要加载的myfake.default.so文件。
这里顺便说一下硬件抽象层模块的命名规范以及加载顺序。硬件抽象层模块文件的命名规范为“<MODULE_ID>.variant.so‖,其中,MODULE_ID表示模块的ID,variant表示四个系统属性ro.hardware、ro.product.board、ro.board.platform和ro.arch之一。系统在加载硬件抽象层模块时,依次按照ro.hardware、ro.product.board、ro.board.platform和ro.arch的顺序来取它们的属性值。如果其中的一个系统属性存在,那么就把它的值作为variant的值,然后再检查对应的文件是否存在,如果存在,那么就找到要加载的硬件抽象层模块文件了;否则,就继续查找下一个系统属性。如果这四个系统属性都不存在,或者对应于这四个系统属性的硬件抽象层模块文件都不存在,那么就使用“<MODULE_ID>.default.so‖来作为要加载的硬件抽象层模块文件的名称。