Android HAL层hardware module的设计

来源:互联网 发布:博拉网络上市最新消息 编辑:程序博客网 时间:2024/05/01 04:55

Android为了屏蔽硬件的复杂性,设计了一个HAL层,HardwareAbstarct Layer,即硬件抽象层。HAL层位于驱动和framework之间,为各个硬件厂家提供的形形色色的驱动模块规定了统一的接口。在Android里面,这些接口是用c语言描述的,而在c语言中,接口都是用函数指针来描述的。所以我们在这些接口模块中看到大量函数指针,下面的驱动去实现这些接口,并挂载到这些接口模块上。

这些接口模块本质上就是一些so库,采用动态加载的形式被framework层调用。Framwork层会在使用到某个功能时去尝试dlopen对应的so库,若这个库存在,调用它,若不存在,就认为系统不支持这个功能。完成查找这个硬件模块是否存在,以及去dlopen,dlsym该模块的初始化函数的那些逻辑放在libhardware.so中。那么,framework和hal的关系可以形象的表示为这样的模型:


Audio_interfaces中定义了HAL层的Audio模块(一些so库),比如

static const char * constaudio_interfaces[] = {

   AUDIO_HARDWARE_MODULE_ID_PRIMARY,

    AUDIO_HARDWARE_MODULE_ID_A2DP,

AUDIO_HARDWARE_MODULE_ID_USB,

}

AudioFlinger使用loadHwModule_l来加载audioInterfaces。实际是去加载HAL层得一些so库。用函数hw_get_module_by_class拿到module,然后用audio_hw_device_open拿到device。所有的HAL层的硬件module都是这么干的。这俩函数定义在libhardware.so中,在编译audioflinger.so时, 这个库是作为动态共享库参加链接的。

我们来看看具体过程:

static intload_audio_interface(const char *if_name, audio_hw_device_t **dev){    const hw_module_t *mod;    int rc;     rc =hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);    ALOGE_IF(rc, "%s couldn't load audiohw module %s.%s (%s)", __func__,                 AUDIO_HARDWARE_MODULE_ID,if_name, strerror(-rc));    if (rc) {        goto out;    }    rc = audio_hw_device_open(mod, dev);    ALOGE_IF(rc, "%s couldn't open audiohw device in %s.%s (%s)", __func__,                 AUDIO_HARDWARE_MODULE_ID,if_name, strerror(-rc));    if (rc) {        goto out;    }    if ((*dev)->common.version <AUDIO_DEVICE_API_VERSION_MIN) {        ALOGE("%s wrong audio hw deviceversion %04x", __func__, (*dev)->common.version);        rc = BAD_VALUE;        goto out;    }    return 0; out:    *dev = NULL;    return rc;}

hw_get_module_by_class是在/hardware/libhardware/hardware.c中定义的,这个文件和libhardware/include/hardware/hardware.h一起定义了hal的接口。

有两个基本的结构体:

一个是hw_module_t,定义了模块的一些id,名称,作者等描述信息,

另一个是hw_device_t,没定义太多东西,但是它的继承结构体定义了一个模块对外需要暴露的接口

再看看继承这两个结构体的audio机子的结构体,定义在audio.h (hardware\libhardware\include\hardware),这里定义了:

struct audio_module {    struct hw_module_t common;}; struct audio_hw_device {struct hw_device_t common;。。。}struct audio_stream_out { };struct audio_stream {}; struct audio_stream_in {};


具体的HAL层模块通过继承这两个结构体来实现具体的业务功能。


然后调用dlopen打开so库,然后const char *sym =HAL_MODULE_INFO_SYM_AS_STR;

hmi = (struct hw_module_t *)dlsym(handle, sym);

而在hardware.h中

#defineHAL_MODULE_INFO_SYM_AS_STR "HMI"

所以是拿到名为HMI的符号

而在audio_hw.c的最后,定义了

struct audio_module HAL_MODULE_INFO_SYM= {    .common = {        .tag = HARDWARE_MODULE_TAG,        .module_api_version =AUDIO_MODULE_API_VERSION_0_1,        .hal_api_version =HARDWARE_HAL_API_VERSION,        .id = AUDIO_HARDWARE_MODULE_ID,        .name = "Default audio HWHAL",        .author = "The Android Open SourceProject",        .methods = &hal_module_methods,    },};

注意libhardware/include/hardware/audio.h中,定义了

struct audio_module {

    struct hw_module_t common;

};

可以认为audio_module是hw_module_t的子类。

回到load_audio_interface,这是通过hw_get_module_by_class拿到了hw_module_t

然后在调用audio_hw_device_open(mod,dev),本质上是调用module->methods->open拿到了hw_device_t的子类audio_hw_device_t。

typedef struct hw_device_t {    uint32_t tag;    uint32_t version;    struct hw_module_t* module;#ifdef __LP64__    uint64_t reserved[12];#else    uint32_t reserved[12];#endif    int (*close)(struct hw_device_t* device);} hw_device_t;typedef struct audio_hw_deviceaudio_hw_device_t

而structaudio_hw_device {

    struct hw_device_t common;

uint32_t (*get_supported_devices)(const structaudio_hw_device *dev);

。。。。

}

这时就拿到了audio_hw_device_t,这个结构体全是各种函数指针,这些指针都已经在调用module->methods->open时已经赋值过了。

所以此时进程拿到了so的接口。而且具有很好的灵活性

而在Load module之后,会调用module的open函数,我们看看这个module是怎么定义的

static_t struct hw_module_methods_t hal_module_methods ={    .open =adev_open,}; struct audio_module HAL_MODULE_INFO_SYM = {    .common = {        .tag =HARDWARE_MODULE_TAG,       .module_api_version = AUDIO_MODULE_API_VERSION_0_1,       .hal_api_version = HARDWARE_HAL_API_VERSION,        .id =AUDIO_HARDWARE_MODULE_ID,        .name ="Manta audio HW HAL",        .author ="The Android Open Source Project",        .methods =&hal_module_methods,    },};

而open就是为audio_hw_device 赋值,而且还会赋值一些环境相关的结构体和变量,他们一起组成了audio_device.我们可以认为,audio_hw_device里的接口都是暴露给外面的接口。

struct audio_device {

    structaudio_hw_device hw_device;

。。。

}

就是一个继承了hw_device_t的audio_hw_device。


0 0