博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android的Framework分析---4硬件抽象HAL
阅读量:6147 次
发布时间:2019-06-21

本文共 5779 字,大约阅读时间需要 19 分钟。

hot3.png

大家都知道android是基于linux的kernel上的。android可以 运行在intel,高通,nvidia等硬件平台。但是涉及到一些GPU,显卡和一些设备的驱动问题,因为这些驱动都不是开源的,google位了兼容这些设备厂商的驱动源码,提出了硬件抽象层HAL的概念。HAL层对上为framework和native开发提供统一的API接口,为下层驱动的代码提供统一的调用接口。本文主要讲解HAL是如何实现的。

1.HAL的数据结构

 HAL的通用写法里面有两个重要的结构体:

1.1 hw_module_t 硬件模块结构体

typedef struct hw_module_t {    /** tag must be initialized to HARDWARE_MODULE_TAG */    uint32_t tag;      uint16_t module_api_version;#define version_major module_api_version    /**     * version_major/version_minor defines are supplied here for temporary     * source code compatibility. They will be removed in the next version.     * ALL clients must convert to the new version format.     */    /**     * The API version of the HAL module interface. This is meant to     * version the hw_module_t, hw_module_methods_t, and hw_device_t     * structures and definitions.     *     * The HAL interface owns this field. Module users/implementations     * must NOT rely on this value for version information.     *     * Presently, 0 is the only valid value.     */    uint16_t hal_api_version;#define version_minor hal_api_version    /** Identifier of module */    const char *id;    /** Name of this module */    const char *name;    /** Author/owner/implementor of the module */    const char *author;    /** Modules methods */    struct hw_module_methods_t* methods;    /** module's dso */    void* dso;    /** padding to 128 bytes, reserved for future use */    uint32_t reserved[32-7];} hw_module_t;
该结构体表示 抽象的硬件模块,包含硬件模块的一些基本信息。里面内嵌了一个
typedef struct hw_module_methods_t {    /** Open a specific device */    int (*open)(const struct hw_module_t* module, const char* id,            struct hw_device_t** device);} hw_module_methods_t;
模块方法的结构体,open的函数指针,用于打开一个硬件设备hw_device_t。开发者需要实现这个open函数。

1.2硬件设备结构体

typedef struct hw_device_t {    /** tag must be initialized to HARDWARE_DEVICE_TAG */    uint32_t tag;    uint32_t version;    /** reference to the module this device belongs to */    struct hw_module_t* module;    /** padding reserved for future use */    uint32_t reserved[12];    /** Close this device */    int (*close)(struct hw_device_t* device);} hw_device_t;
表示一个硬件抽象设备。这是通用的结构体,开发者可以继承这个结构体添加自己需要的接口。

1.3 获取一个hw_model_t模块

HAL层提供一个方法用户获取一个model,进而同过open方法打开设备device

/** * Get the module info associated with a module by id. * * @return: 0 == success, <0 == error and *module == NULL */int hw_get_module(const char *id, const struct hw_module_t **module);
定义一个全局变量

const struct hw_module_t   HAL_MODULE_INFO_SYM={ ...};

用于在hw_get_modules通过解析so时,得到该全局变量。

2.硬件模块库的装载于解析

装载和解析有hw_get_module 完成,它会安按照一定的规则去查找so库,然后解析出全局变量名,得到硬件设备的open函数,最后通过参数返回一个device的指针给调用者。

2.1搜索so的规则;

 

/** Base path of the hal modules */#define HAL_LIBRARY_PATH1 "/system/lib/hw"#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"/** * There are a set of variant filename for modules. The form of the filename * is "
.variant.so" so for the led module the Dream variants * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be: * * led.trout.so * led.msm7k.so * led.ARMV6.so * led.default.so */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"};
搜索规则就是按照上面的说明进行。

2.2函数加载解析的过程

(1)调用hw_get_module,通过传给他一个module_id 字符串例如“camera”等。调用hw_get_module_by_class(id, NULL, module);

 (2)搜索对应的so并调用load去解析so

int hw_get_module_by_class(const char *class_id, const char *inst,                           const struct hw_module_t **module){    int status = -EINVAL;    int i = 0;    char prop[PATH_MAX] = {0};    char path[PATH_MAX] = {0};    char name[PATH_MAX] = {0};    if (inst)        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);    else        strlcpy(name, class_id, PATH_MAX);    /*     * Here we rely on the fact that calling dlopen multiple times on     * the same .so will simply increment a refcount (and not load     * a new copy of the library).     * We also assume that dlopen() is thread-safe.     */    /* Loop through the configuration variants looking for a module */    for (i=0 ; i
(3)load函数解析so,得到hw_module_t的hw_device_t的函数指针。

/** * Load the file defined by the variant and if successful * return the dlopen handle and the hmi. * @return 0 = success, !0 = failure. */static int load(const char *id,        const char *path,        const struct hw_module_t **pHmi){    int status = -EINVAL;    void *handle = NULL;    struct hw_module_t *hmi = NULL;    /*     * load the symbols resolving undefined symbols before     * dlopen returns. Since RTLD_GLOBAL is not or'd in with     * RTLD_NOW the external symbols will not be global     */    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;    }    /* Get the address of the struct hal_module_info. */    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;    }    /* Check that the id matches */    if (strcmp(id, hmi->id) != 0) {        ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);        status = -EINVAL;        goto done;    }    hmi->dso = handle;    /* success */    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;    return status;}

版权声明:本文为博主原创文章,未经博主允许不得转载。

转载于:https://my.oschina.net/xcy2011sky/blog/492654

你可能感兴趣的文章
【转】百度地图api,根据多点注标坐标范围计算地图缩放级别zoom自适应地图
查看>>
用户调研(补)
查看>>
ExtJS之开篇:我来了
查看>>
☆1018
查看>>
oracle 去掉空格
查看>>
6.13心得
查看>>
Runtime类
查看>>
eclipse decompiler
查看>>
记一个搜索网盘资源的网站
查看>>
jdk1.7和jdk1.8的String的getByte方法的差异
查看>>
java父子进程通信
查看>>
Android ADB server didn't ACK * failed to start daemon * 简单有效的解决方案
查看>>
Olap学习笔记
查看>>
Codeforces Round #431 (Div. 1)
查看>>
如何进行数组去重
查看>>
将标题空格替换为 '_' , 并自动复制到剪切板上
查看>>
List Collections sort
查看>>
Mysql -- You can't specify target table 'address' for update in FROM clause
查看>>
使用局部标准差实现图像的局部对比度增强算法。
查看>>
2017-2018-1 20165313 《信息安全系统设计基础》第八周学习总结
查看>>