随笔录:Android—HAL层(二)

对于HAL怎么捕获到上接所说的上传数据

参考前面的 https://blog.csdn.net/qq_42856778/article/details/89374880

一问

我们在下层写好的每一个模块结构的名字都是HAL_MODULE_INFO_SYM,怎么精准调用到 此时需要的模块?靠什么标志来识别(id? name? addr?)

二问、

在前面我们将向上提供的接口做成一个动态库,那么这个动态库怎么被调用?
这个动态库应该放在什么地方?

在 android/hardware/libhardware/include/hardware/hardware.h里面还出现了两个函数,根据他们的函数
名字很明显得出他们的作用。其实就是两个对外的接口

1、/**int hw_get_module() **/

int hw_get_module(const char *id, const struct hw_module_t **module) {
return hw_get_module_by_class(id, NULL, module);
}

单看这个函数的名字,是获取模块的一个函数。
可以看到hw_get_module直接调用hw_get_module_by_class,在之前我们自定义模块结构(Test_module_t)
有着两个要求,名字必须是HAL_MODULE_INFO_SYM和第一个成员必须是 hw_module_t ,可以看得出都是共同的接口,
这样就出现前面的一问?
答案:在 struct hw_module_t 结构体里面有一个成员叫做id通过其备注可以知道。通过共同接口进来之后,
查找对应的模块就是通过ID查找(必须是独一无二的)。其实就是通过ID精准地查找到定义的模块。
那么hw_get_module()的第二个形参猜得到了,它就是一个篮子,将我们下层定义的模块装上来。
总结:就是通过ID找到模块,在将整个模块都获取上来。

现在当我们的id传给hw_get_module_by_class()函数时会怎么操作呢?一个ID怎么辗转才能对应的模块。

2、

int hw_get_module_by_class (class_id,inst,module) 函数原型和里边具体操作:

int hw_get_module_by_class(const char *class_id, const char *inst,                       
						    const struct hw_module_t **module){                       
  
 int i = 0;		 
 char path[PATH_MAX] = {0};
 char name[PATH_MAX] = {0};
 char prop_name[PATH_MAX] = {0};

 if (inst)
 		snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
 else 
      trlcpy(name, class_id, PATH_MAX);
 
snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);

if (property_get(prop_name, prop, NULL) > 0) {		
  		   if (hw_module_exists(path, sizeof(path), name, prop) == 0) { goto found;}	 
 	}

 for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
        	if (property_get(variant_keys[i], prop, NULL) == 0) {   continue;   }
  	  		if (hw_module_exists(path, sizeof(path), name, prop) == 0) {   goto found;  }
 	}
 /* Nothing found, try the default */
 if (hw_module_exists(path, sizeof(path), name, "default") == 0) {  goto found;	}
 
 return -ENOENT;
 found:
 return load(class_id, path, module);
}

当inst参数为空的时候传进来的id,就会被拷贝,然后被 snprintf()封装[ro.hardware.name},
封装成只读属性(属性详细①),通过property_get()查找这个属性,判断是否配置项定义了对应的HAL层,

对应的HAL层存在,则通过hw_module_exists(path,path_len,name,subname)去共享库目录下查找对应的so库。
并且获取到库的路径。找到了跳去执行load(class_id, path, module);

3、*

解析上面的hw_module_exists()
函数揭露了,有id就去HAL层生成的库。这个函数其实里面主要的三个判断处理,
每一个判断代表一个路径,即是在三个路径判断库是否存在.(hardware.c标明)

#if defined(__LP64__)
#define HAL_LIBRARY_PATH1 "/system/lib64/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib64/hw"
#else
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib/hw"
#endif
int hw_module_exists(char *path, size_t path_len, const char *name, const char *subname) {
	
		snprintf(path, path_len, "%s/%s.%s.so",HAL_LIBRARY_PATH3, name, subname);
	if (access(path, R_OK) == 0){return 0;}
	
		// /vendor/lib/hw/name.subname.so或者/vendor/lib64/hw/name.subname.so
		snprintf(path, path_len, "%s/%s.%s.so",HAL_LIBRARY_PATH2, name, subname);
		if(access(path, R_OK) == 0){ return 0; }
		
		// /system/lib/hw/name.subname.so或者/system/lib64/hw/name.subname.so
		snprintf(path, path_len, "%s/%s.%s.so",HAL_LIBRARY_PATH1, name, subname);
		if(access(path, R_OK) == 0) { return 0; }
		
		return -ENOENT;
}

在 hw_get_module_by_class (class_id,inst,module)里面还这么一段代码,
当其实里面讲的是在配置变量中查找,属性值是否存在,存在还是通过

hw_module_exists()

去共享库目录下查找对应的so库。并且获取到库的路径。获取到就回去执行

load(class_id, path, module);

如果经过查找之后都没有属性值,返回一个错误值-ENOENT结束退出。

	  for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
			if (property_get(variant_keys[i], prop, NULL) == 0) { continue; }
			if (hw_module_exists(path, sizeof(path), name, prop) == 0) { goto found;}
		   }
	配置变量:
		static const char *variant_keys[] = {
			"ro.hardware",  /* This goes first so that it can pick up a different
							   file on the emulator. */
			"ro.product.board",
			"ro.board.platform",
			"ro.arch"
		};

在上面配置变量查找到属性值的时候都会跳到 load(class_id, path, module)函数里面,分析这个函数
load(id,path,pHmi)。
在hw_get_module_by_class()函数里面看到,它三个形参对应的分别是,传进来的ID
获取到的库路径、module(在hw_get_module()所说的篮子)结构指针。下面分析下该函数

static int load(const char *id,const char *path,const struct hw_module_t **pHmi) {
    int status = -EINVAL;
    void *handle = NULL;
    struct hw_module_t *hmi = NULL;
    /*
     * 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) {
        char const *err_str = dlerror();
        ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
        status = -EINVAL;
        goto done;
    }
    /* Get the address of the struct hal_module_info. */
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
    hmi = (struct hw_module_t *)dlsym(handle, sym);
    if (hmi == NULL) {
        ALOGE("load: couldn't find symbol %s", sym);
        status = -EINVAL;
        goto done;
    }
 
    /* Check that the id matches */
    if (strcmp(id, hmi->id) != 0) {
        ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
        status = -EINVAL;
        goto done;
    }
    hmi->dso = handle;
    /* success */
    status = 0;
    done:
    if (status != 0) {
        hmi = NULL;
        if (handle != NULL) {
            dlclose(handle);
            handle = NULL;
        }
    } else {
        ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
                id, path, *pHmi, handle);
    }
    *pHmi = hmi;
    return status;
}

在整个函数里面我们会发现只有两个函数在里面工作,其他都是做一些出错判断。

	dlopen(path, RTLD_NOW);
	dlsym(handle, sym);

函数解析
dlopen的()函数以指定模式打开指定的动态连接库文件,并返回一个操作句柄给调用进程

参数:
	path	 :动态库对应路径名字
	RTLD_NOW :立即决定,返回前解除所有未决定的符号
	返回值: 操作句柄	

dlsym()函数 根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的地址。
使用这个函数不但可以获取函数地址,也可以获取变量地址。

参数
	handle:由dlopen打开动态链接库后返回的指针;
	symbol:要求获取的函数或全局变量的名称。
	返回值:指向函数或全局变量的名称

那么整一个load(id,path,pHmi)函数做的事情就是,通过传进来的ID和path,查找到对应的动态
库文件,调用dlopen()将它打开,返回一个操作句柄,dlsym()拿到操作句柄,获取到变量的地址
也就是我们在下层定义好的 hw_module_t 模块的地址。然后赋值给hw_get_module()函数的module变量地址。
换句话说,我们所要做的任务就已经完成了。同时以上答案也会回答了第二个问题。

最后一问:
如果hw_get_module_by_class()的第二个函数不为空的情况下会是怎么样的呢?

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

跟着代码走得到 name = class_id.inst 一个这样的结构,那么对于我们来说作用或者说
新的特点在哪里呢,我看了网上很多关于HAL这方便的博客资料。都未能找出一个相对满意的答案。解答的只有不断学习和使用才能解析心中更大的疑问。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值