Android的硬件抽象層,簡單來講,就是對Linux內核驅動程序的封裝,向上提供接口,向下屏蔽了具體的實現細節。也就是將Linux內核對硬件的支持分紅了兩層,一層放在用戶空間(User Space),一層放在內核空間(Kernel Space),其中,硬件抽象層運行在用戶空間,對應具體的驅動實現細節,而Linux內核驅動程序運行在內核空間,只提供簡單的數據訪問邏輯。html
那爲何要將驅動的具體實現細節封裝到硬件抽象層呢?android
Android系統使用的是Linux內核,Linux內核是基於GPL許可(GNU License),即對源碼的修改都必須開源,若是將驅動的實現細節放在Linux內核層,那麼就意味着須要公開驅動程序的源代碼,這樣顯然是違背了硬件廠商的自身利益。git
那爲何將其抽象到硬件抽象層就能夠規避這個問題呢?github
除Linux內核外的Android源碼使用的是ASL許可(Apache License),而ASL許可無須發佈源代碼,這樣Android就能夠對該部分的代碼不開源。api
另外,HAL也能夠屏蔽不一樣硬件設備的差別,爲Android提供了統一的訪問硬件設備的接口。不一樣的硬件廠商遵循HAL標準來實現本身的硬件控制邏輯,這樣開發者沒必要關心不一樣硬件設備的差別,只須要按照HAL提供的標準接口訪問硬件就能夠了。bash
Android 系統的 HAL 層其實並不複雜,只要你能理解清楚下面這 3 個結構體的含義:函數
/**
* 每一個硬件模塊中都要定義一個名字叫作 HAL_MODULE_INFO_SYM 結構體變量,
* 而這結構體變量中的第一個成員必須是 hw_module_t 類型。
*/
typedef struct hw_module_t {
/** 必須設置爲 HARDWARE_MODULE_TAG */
uint32_t tag;
/** 表示硬件模塊,用來區別於其餘硬件模塊 */
const char *id;
/** Name of this module */
const char *name;
/** Author/owner/implementor of the module */
const char *author;
/** methods給出了一個硬件抽象模塊的操做方法列表 */
struct hw_module_methods_t* methods;
/**
*用來保存加載硬件抽象模塊後獲得的句柄值
*每個硬件抽象模塊都對應一個動態連接庫文件
*dlopen函數打開對應的動態連接庫文件得到這個句柄
*/
void* dso;
} hw_module_t;
複製代碼
從上面的註釋能夠看到,對於具體的硬件模塊,必須從新定義一個結構體變量,這個結構體變量的名字爲HAL_MODULE_INFO_SYM,而且結構體的第一個成員變量必須爲hw_module_t。
ui
/**
* 該結構體只有一個名爲open的函數指針變量
* 用來打開硬件模塊所管理的硬件設備id值爲 id 的硬件設備,並將打開的硬件設備經過 device 返回
*/
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;
複製代碼
/**
* 每一個 HAL 層中硬件設備對應的結構體中的第一個成員必須是 hw_device_t
* 而後接着的就是對應的方法和屬性
*/
typedef struct hw_device_t {
/** 必須初始化爲 HARDWARE_DEVICE_TAG */
uint32_t tag;
uint32_t version;
/** 表示該硬件設備屬於哪一個硬件模塊 */
struct hw_module_t* module;
/** 關閉硬件設備 */
int (*close)(struct hw_device_t* device);
} hw_device_t;
複製代碼
對於具體的硬件設備,必須從新定義一個結構體變量,而且結構體的第一個成員變量必須爲hw_device_t。
this
Step 1:定義 struct audio_module 模塊
spa
具體的硬件模塊要定義一個新的結構體而且這個結構體的第一個成員必須是 hw_module_t 類型
struct audio_module {
struct hw_module_t common;
};
複製代碼
step 2:定義 struct audio_module 類型的
從新定義一個結構體變量,這個結構體變量的名字爲HAL_MODULE_INFO_SYM,而且結構體的第一個成員變量必須爲hw_module_t。
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 = "Generic audio HW HAL",
.author = "The Android Open Source Project",
.methods = &hal_module_methods,
}
};
複製代碼
step 3:定義 struct audio_hw_device 硬件設備結構體
struct audio_hw_device {
// 第一個成員變量對應的是hw_module_t 類型
struct hw_device_t common;
......
// 後面對應的就是設備操做方法
size_t (*get_input_buffer_size)(const struct audio_hw_device *dev,
const struct audio_config *config);
int (*open_output_stream)(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
audio_output_flags_t flags,
struct audio_config *config,
struct audio_stream_out **stream_out,
const char *address);
void (*close_output_stream)(struct audio_hw_device *dev,
struct audio_stream_out* stream_out);
int (*open_input_stream)(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
struct audio_config *config,
struct audio_stream_in **stream_in,
audio_input_flags_t flags,
const char *address,
audio_source_t source);
void (*close_input_stream)(struct audio_hw_device *dev,
struct audio_stream_in *stream_in);
......
};
複製代碼
struct generic_audio_device {
struct audio_hw_device device;
pthread_mutex_t lock;
struct audio_stream_out *output;
struct audio_stream_in *input;
int fd;
bool mic_mute;
};
複製代碼
step 4:定義 struct hw_module_methods_t 函數列表變量
static struct hw_module_methods_t hal_module_methods = {
.open = adev_open,
};
複製代碼
打開硬件模塊的硬件設備
step 5:adev_open 函數的實現
static int adev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
struct generic_audio_device *adev;
int fd;
if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
return -EINVAL;
fd = open(AUDIO_DEVICE_NAME, O_RDWR);
if (fd < 0)
return -ENOSYS;
adev = calloc(1, sizeof(struct generic_audio_device));
adev->fd = fd;
adev->device.common.tag = HARDWARE_DEVICE_TAG;
adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
adev->device.common.module = (struct hw_module_t *) module;
adev->device.common.close = adev_close;
adev->device.init_check = adev_init_check;
adev->device.set_voice_volume = adev_set_voice_volume;
adev->device.set_master_volume = adev_set_master_volume;
adev->device.get_master_volume = adev_get_master_volume;
adev->device.set_master_mute = adev_set_master_mute;
adev->device.get_master_mute = adev_get_master_mute;
adev->device.set_mode = adev_set_mode;
adev->device.set_mic_mute = adev_set_mic_mute;
adev->device.get_mic_mute = adev_get_mic_mute;
adev->device.set_parameters = adev_set_parameters;
adev->device.get_parameters = adev_get_parameters;
adev->device.get_input_buffer_size = adev_get_input_buffer_size;
adev->device.open_output_stream = adev_open_output_stream;
adev->device.close_output_stream = adev_close_output_stream;
adev->device.open_input_stream = adev_open_input_stream;
adev->device.close_input_stream = adev_close_input_stream;
adev->device.dump = adev_dump;
*device = &adev->device.common;
return 0;
}
複製代碼
咱們能夠從 adev_open 函數中的實現中看到,它裏面的主要工做就是作一些對 struct audio_hw_device 對象的初始化,將其定義的函數指針指向對應的已經實現好的函數中。 例如,這裏將struct audio_hw_device中定義的 open_output_stream 函數指針成員指向了 adev_open_output_stream 函數。這樣在 Framework 層調用的 struct audio_hw_device 對象的 open_output_stream 函數,其實最終調用的是 adev_open_output_stream函數。
參考文章:
https://blog.csdn.net/Luoshengyang/article/details/6567257
https://woshijpf.github.io/android/2017/03/25/Android-HAL%E5%B1%82%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90.html
https://www.jianshu.com/p/21a6cc575ed3