这次我们主要是介绍一下hardware/libhardware/hardware.c方法里面的hw_get_module函数的实现,通过这个我们了解到hardware.c是如何找到系统的库文件的.
static const char *variant_keys[] = { “ro.hardware”, “ro.product.board”, “ro.board.platform”, “ro.arch” };
struct constint HAL_VARIANT_KEYS_COUNT = (sizeof(variant_keys)/sizeof(variant_keys[0]));
由上面定义的字符串数组可知,HAL_VARIANT_KEYS_COUNT的值为4.
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; // 成功返回 }
itchq
浙公网安备 33010602011771号