这次我们主要是介绍一下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;
    // 成功返回
}

 

posted on 2016-06-24 01:12  ip小子  阅读(249)  评论(0)    收藏  举报