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。