对Android HAL架构的认识

1.HAL的本质

HAL是将驱动的部分操作上移到用户空间,提供了基本的驱动操作(读写数据),这样做的目的是减少用户空间对kernel的依赖。用户空间将对驱动的操作交给HAL来完成。

2.基础数据结构

<1> struct hw_module_t 代表硬件设备所属的模块

<2> struct hw_module_methos_t代表模块中的方法

<3> struct hw_device_t 代表硬件设备的操作

3.数据结构之间的关系


hw_module_t 持有hw_module_methods_t指针

hw_device_t 持有hw_module_t指针

4.HAL的调用方式。

Android4.2中,HAL将各个模块的动态库,隐藏起来。編譯的時候只是给需要调用HAL库的进程提供模块库的地址。執行的時候,再将库加载到内存,所以HAL的各个库文件在内存中始终只有一份拷贝,可以这么理解,HAL向其他进程提供库的代理,进程调用这些库的时候,讓代理完成具體的工作。在具体的調用過程中,這個代理就是庫的函數指針或者模块指针或者设备指针。

在获取模块的过程中,其他进程获取的是模块指针(hw_module_t)

在打开设备的过程中,其他进程获取的是设备指针(hw_device_t)

在向设备读写数据的过程中,操作的就是设备指针

5.自定义HAL

如果需要自定义HAL,正如上图所示的self_module_t,self_device_t

<1>

struct self_module_t{

hw_module_t common;

…..//自定义数据,与模块相关的函数指针

}

struct self_device_t{

hw_device_t common;

….//自定义数据,与设备驱动相关的函数指针

void (*f1)();

void (*f2)();

}

<2> 初始化self_module_tself_module_methods_t,并在open方法中初始化self_device_t

static struct self_module_methods_tself_module_methods={

open: self_device_open

};

struct self_module_tHAL_MODULE_INFO_SYM={

.common:

{

tag: HARDWARE_MODULE_TAG,

version_major:1,

version_minor:0,

id:SELF_HARDWARE_MODULE_ID,

name:"Default SELF HW HAL",

author:"The Android Open SourceProject",

methods:&self_module_methods

},

};

static int self_device_open(conststruct hw_module_t * module,const char* name,hw_device_t** device){

struct self_device_t* dev;

dev=(structled_device_t*)malloc(sizeof(struct self_device_t));

if(!dev){

ALOGE("there is no enoughspace!");

return -EFAULT;

}

memset(dev,0,sizeof(structself_device_t));

dev->common.tag=HARDWARE_DEVICE_TAG;

dev->common.version=0;

dev->common.module=(hw_module_t*)module;

dev->common.close=self_device_close;

dev->f1=...//自己实现

dev->f2=...//自己实现

if((dev->fd=open(DEVICE_NAME,O_RDWR))==-1){

ALOGE("open failed");

return -EFAULT;

}

*device=&(dev->common);// 返回的是self_device_t中的hw_device_t的地址,也就是//self_device_t的首地址

return 0;

}

static int self_device_close(structhw_module_t* device){

struct self_device_t* self_device=(struct self_device_t)device;

if(led_device){

close(self_device->fd);

free(self_device);

}

return 0;

}

<3> JNI或者原生程序中调用 (通过hw_get_module方法获取自定义的模块部分的库的函数指针

6.HAL的调用初始化过程

调用的初始化分为两部分,一是找到模块,二是打开模块的设备

hw_get_module分析,它最终会将对应的库加载到内存,然后再通过调用open方法打开设备。

<1>调用hw_get_module的最终目的是为了活得模块的地址,以便打开模块中的设备。

<2>自己定义的modle变量名称必须是HAL_MODULE_INFO_SYM

<3>打开设备的过程的本质就是初始化一个self_device_t.

<4>初始化self_device_t,干了两件事,一是初始化hw_device_t,而是初始化self_device_t自己定义的函数指针。

// id是模块ID

inthw_get_module(constchar*id,conststructhw_module_t **module)

{

returnhw_get_module_by_class(id, NULL, module);

}

inthw_get_module_by_class(constchar*class_id,constchar*inst,

conststructhw_module_t **module)

{

intstatus;

inti;

conststructhw_module_t *hmi = NULL;

charprop[PATH_MAX];

charpath[PATH_MAX];

charname[PATH_MAX];


if(inst)

snprintf(name, PATH_MAX,"%s.%s",class_id, inst);

else

strlcpy(name, class_id,PATH_MAX);


/*

*Here we rely on the fact that callingdlopen multiple times on

*the same .so will simply increment arefcount (and not load

*a new copy of the library).

*We also assume thatdlopen() is thread-safe.

*/


/*Loop through the configuration variants looking for a module */

for(i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {

if(i < HAL_VARIANT_KEYS_COUNT) {

if(property_get(variant_keys[i], prop, NULL) == 0) {

continue;

}

snprintf(path,sizeof(path),"%s/%s.%s.so",

HAL_LIBRARY_PATH2,name, prop);//根据模块ID,生成库的名称

if(access(path, R_OK) == 0)break;


snprintf(path,sizeof(path),"%s/%s.%s.so",

HAL_LIBRARY_PATH1,name, prop);

if(access(path, R_OK) == 0)break;

}else{

snprintf(path,sizeof(path),"%s/%s.default.so",

HAL_LIBRARY_PATH1,name);

if(access(path, R_OK) == 0)break;

}

}

staticintload(constchar*id,

constchar*path,

conststructhw_module_t **pHmi)

{

intstatus;

void*handle;

structhw_module_t *hmi;


/*

*load the symbols resolving undefined symbols before

*dlopen returns. Since RTLD_GLOBAL is not or'd in with

*RTLD_NOW the external symbols will not be global

*/

handle = dlopen(path, RTLD_NOW);

if(handle == NULL) {

charconst*err_str = dlerror();

ALOGE("load:module=%s\n%s", path,err_str?err_str:"unknown");

status = -EINVAL;

gotodone;

}


/*Get the address of thestructhal_module_info. */

//

//这里是最关键的部分,HAL_MODULE_INFO_SYM_AS_STRHMI,在库的二进制文件中可以找到这个///符号,对应的是hw_module_t的地址

//为了得到HMI,自己的modle的名称必须是HAL_MODULE_INFO_SYM

constchar*sym = HAL_MODULE_INFO_SYM_AS_STR;

hmi = (structhw_module_t *)dlsym(handle, sym);

if(hmi == NULL) {

ALOGE("load:couldn't find symbol %s", sym);

status = -EINVAL;

gotodone;

}


/*Check that the id matches */

if(strcmp(id, hmi->id)!= 0) {

ALOGE("load:id=%s !=hmi->id=%s",id, hmi->id);

status = -EINVAL;

gotodone;

}


hmi->dso= handle;


/*success */

status = 0;


done:

if(status != 0) {

hmi = NULL;

if(handle != NULL) {

dlclose(handle);

handle = NULL;

}

}else{

ALOGV("loadedHAL id=%s path=%shmi=%phandle=%p",

id, path, *pHmi,handle);

}


*pHmi = hmi;//模块的地址就可以通过指针返回了


returnstatus;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值