Android平台的 hw_get_module 函数的学习

通过hw_get_module_t来找到注册的硬件对象。
@hardware/libhardware/hardware.c

static const char *variant_keys[] = {
    
    
	“ro.hardware”,
	“ro.product.board”,
	“ro.board.platform”,
	“ro.arch”
};
// 由上面定义的字符串数组可知,HAL_VARIANT_KEYS_COUNT的值为4
struct constint HAL_VARIANT_KEYS_COUNT = 
                    (sizeof(variant_keys)/sizeof(variant_keys[0]));
 
int hw_get_module(const char *id, const struct hw_module_t **module)
{
    
    
	// 调用3个参数的hw_get_module_by_class函数
return hw_get_module_by_class(id, NULL, module);
}
 
int hw_get_module_by_class(const char *class_id, const char *inst,
const struct hw_module_t **module){
    
    
	int status;
	int i;
	// 声明一个hw_module_t指针变量hmi
	const struct hw_module_t *hmi = NULL;
	char prop[PATH_MAX};
	char path[PATH_MAX];
	char name[PATH_MAX];
	// 由前面调用函数可知,inst = NULL,执行else部分,
	//  将硬件id名拷贝到name数组里
	if(inst)
		snprintf(name, PATH_MAX,%s.%s”, class_id, inst);
	else
		strlcpy(name, class_id, PATH_MAX);
	// i 循环5次
	for(i=0; i<HAL_VARIANT_KEYS_COUNT+1; i++){
    
    
		if(i<HAL_VARIANT_KEYS_COUNT){
    
    
			/* 
			从系统属性里依次查找前面定义的4个属性的值,找其中一个后,
			执行后面代码,找不到,进入else部分执行
			*/
			if(property_get(variant_keys[i], prop, NULL) == 0){
    
    
				continue;
			}
			/* 
			找到一个属性值prop后,拼写path的值为:
			/vendor/lib/hw/硬件id名.prop.so 
			*/
			snprintf(path, sizeof(path),%s/%s.%s.so”,
				HAL_LIBRARY_PATH2, name, prop);
			if(access(path, R_OK) ==0) break;	
			/* 如果path指向有效的库文件,退出for循环,
			   如果vendor/lib/hw目录下没有库文件,
			   查找/system/lib/hw目录下有没有:硬件id名.prop.so的库文件,
			   */
			 snprintf(path, sizeof(path),%s/%s.%s.so”,
				HAL_LIBRARY_PATH1, name, prop);
			 if(access(path, R_OK) == 0) break;
		} else {
    
    
			/* 如果4个系统属性都没有定义,则使用默认的库名:
			   /system/lib/hw/硬件id名.default.so
			*/
			snprintf(path, sizeof(path),%s/%s.default.so”,
				HAL_LIBRARY_PATH1, name);
			If(access(path, R_OK) == 0) break;
		}
	}
	status = -ENOENT;
	if(i<HAL_VARIANT_KEYS_COUNT+1){
    
    
		status = load(class_id, path, module);	
		/* 
			加载前面查找到的so库。。
		*/
	}
	return status;
}
 
static int load(const char *id, counst char *path, 
                const struct hw_module_t **pHmi){
    
    
	void *handle;
	struct hw_module_t * hmi;
	// 通过dlopen打开so库
	handle = dlopen(path, RTLD_NOW);
	// sym的值为”HMI”,这个名字还有印象吗?
	const char * sym = HAL_MODULE_INFO_SYM_AS_STR;
	/* 通过dlsym从打开的库里查找”HMI”这个符号,如果在so代码里有定义的函数名
	   或变量名为HMI,dlsym返回其地址hmi,将该地址转化成hw_module_t类型,
	   即,硬件对象,这招够狠,“杀鸡取卵”
	   */
	hmi = (struct hw_module_t *)dlsym(handle, sym);	
	/* 
	   判断找到的硬件对象的id是否和要查找的id名一致,不一致出错退出
    */
	if(strcmp(id, hmi->) != 0){
    
    
		// 出错退出处理
	}
	/* 将库的句柄保存到hmi硬件对象的dso成员里  */
	hmi->dso = handle;
	/* 
	   将硬件对象地址送给 load 函数者,
	   最终将硬件对象返回到了 hw_get_module 的调用者
	   */
	*pHmi = hmi;
	// 成功返回
}

通过上面代码的注释分析可知,硬件对象声明的结构体代码被编译成了so库,由于该结构体声明为const类型,被so库包含在其静态代码段里。
要找到硬件对象,首先要找到其对应的so库,再通过 dlopen,dlsym 这种“杀鸡取卵”的方式找到硬件对象。

在声明结构体led_module_t时,其名字统一定义为了HMI,而这么做的目的就是为了通过dlsym来查找led HAL Stub源码生成的so库里的”HMI”符号。现在很明显了,我们写的HAL Stub代码最终要编译so库文件,并且库文件名为:led.default.so(当然可以设置四个系统属性之一来指定名字为:led.属性值.so),并且库的所在目录为:/system/lib/hw/。

参考大神博客,按照自己理解习惯整理,参考链接如下:
https://outfox.blog.csdn.net/article/details/8074549

猜你喜欢

转载自blog.csdn.net/weixin_38387929/article/details/111145668