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。