欢迎来到Doc100.Net免费学习资源知识分享平台!
您的位置:首页 > 程序异常 >

android硬件抽象hardware库加载历程源码分析

更新时间: 2014-01-05 03:12:06 责任编辑: Author_N1

 

Android硬件抽象Hardware库加载过程源码分析

作为开放而非开源的Android系统,由于其基于Linux内核实现,在不违背Linux基于GPL许可前提下,为了隐藏各厂家自身特定硬件驱动实现细节,在用户空间定义了一套硬件抽象层,对硬件的操作细节从内核空间转移到用户空间。各厂商在Android的硬件抽象层实现特定硬件的操作细节,并编译成动态库,以库的形式提供给用户使用。因此Android就提供了一套访问硬件抽象层动态库的接口,各厂商只需要为他们的硬件实现软件操作细节。Android系统编译的硬件抽象库存放于/system/lib/hw目录下,如下图所示:


本文简单介绍Android系统提供的硬件抽象库访问接口。

hardware\libhardware\hardware.c

int hw_get_module(const char *id, const struct hw_module_t **module)
{
    return hw_get_module_by_class(id, NULL, module);
}
参数id为硬件抽象层模块ID,hw_module_t是硬件抽象层模块描述结构。

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"
};
static const int HAL_VARIANT_KEYS_COUNT =
    (sizeof(variant_keys)/sizeof(variant_keys[0]));
	
int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int status;
    int i;
    const struct hw_module_t *hmi = NULL;
    char prop[PATH_MAX];//属性
    char path[PATH_MAX];//路径
    char name[PATH_MAX];//名称
    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, PATH_MAX);
	//遍历数组variant_keys
	//HAL_VARIANT_KEYS_COUNT =(sizeof(variant_keys)/sizeof(variant_keys[0]));
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
        if (i < HAL_VARIANT_KEYS_COUNT) {
            if (property_get(variant_keys[i], prop, NULL) == 0) {
                continue;
            }
            snprintf(path, sizeof(path), "%s/%s.%s.so",HAL_LIBRARY_PATH2, name, prop);
            if (access(path, R_OK) == 0) break;
            snprintf(path, sizeof(path), "%s/%s.%s.so",HAL_LIBRARY_PATH1, name, prop);
            if (access(path, R_OK) == 0) break;
        } else {
            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);
    }
    return status;
}
函数首先遍历数组variant_keys,读取以数组元素为属性的值,即循环读取
"ro.hardware" 
"ro.product.board"
"ro.board.platform"
"ro.arch"
这四个属性,如果其中有一个属性设置了值的话,将硬件抽象层库的路径,名称,读取的属性值格式化到path字符串中。
path=/vendor/lib/hw/gralloc.[prop].so
然后判断该路径下的so库能否访问,如果不行,则判断/system/lib/hw目录下对应的模块so能否访问,
path=/system/lib/hw/gralloc.[prop].so
即函数hw_get_module依次在目录/system/lib/hw和/vendor/lib/hw中查找一个名称为"<MODULE_ID>.variant.so"的文件,其中,<MODULE_ID>是一个模块ID,而variant表示"ro.hardware"、"ro.product.board"、"ro.board.platform"和"ro.arch"四个系统属性值之一。只要其中的一个文件存在,  函数hw_get_module就会停止查找过程,如果在/system/lib/hw和/vendor/lib/hw中均不存这些文件,那么就会在目录/system/lib/hw中查找是否存在一个名称为<MODULE_ID>.default.so的文件,并调用load函数来加载so库,得到该硬件抽象层模块的模块描述符hw_module_t

static int load(const char *id,const char *path,const struct hw_module_t **pHmi)
{
    int status;
    void *handle;
    struct hw_module_t *hmi;
	//打开so动态库
    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;
    }
	//得到模块描述符的首地址,在模块注册时,将模块描述符命名为HAL_MODULE_INFO_SYM,其真实名称为HMI,
	//这里就是取得结构体HMI的首地址,#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"
    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;
    }
    /* 匹配模块ID */
    if (strcmp(id, hmi->id) != 0) {
        ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
        status = -EINVAL;
        goto done;
    }
	//将模块句柄保存到hw_module_t的成员变量dso中
    hmi->dso = handle;
    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;//返回模块描述符hw_module_t的地址
    return status;
}

硬件抽象层模块编写规范规定每一个硬件抽象层模块都必须导出一个符号名称为HAL_MODULE_INFO_SYM_AS_STR的符号,而且这个符号必须是用来描述一个类型为hw_module_t的结构体的。


上一篇:上一篇
下一篇:下一篇

 

随机推荐程序问答结果

 

 

如对文章有任何疑问请提交到问题反馈,或者您对内容不满意,请您反馈给我们DOC100.NET论坛发贴求解。
DOC100.NET资源网,机器学习分类整理更新日期::2014-01-05 03:12:06
如需转载,请注明文章出处和来源网址:http://www.doc100.net/bugs/t/19458/
本文WWW.DOC100.NET DOC100.NET版权所有。