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