Learning the hw_get_module function of the Android platform

Find the registered hardware object through 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;
	// 成功返回
}

Through the comment analysis of the above code, it can be seen that the structure code declared by the hardware object is compiled into the so library. Since the structure is declared as a const type, it is included in the static code segment by the so library.
To find a hardware object, you must first find its corresponding so library, and then find the hardware object through dlopen and dlsym.

When declaring the structure led_module_t, its name is uniformly defined as HMI, and the purpose of this is to find the "HMI" symbol in the so library generated by the led HAL Stub source code through dlsym. Now it is obvious that the HAL Stub code we wrote will eventually compile the so library file, and the library file name is: led.default.so (Of course, you can set one of the four system properties to specify the name: led.attribute value.so ), and the directory where the library is located is: /system/lib/hw/.

Refer to the Great God blog and organize it according to your own understanding habits. The reference link is as follows:
https://outfox.blog.csdn.net/article/details/8074549

Guess you like

Origin blog.csdn.net/weixin_38387929/article/details/111145668