1. 程式人生 > >Android HAL層hardware module的設計

Android HAL層hardware module的設計

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。