基于Android P版本分析
HAL 概述
硬件抽象层(HAL) 是介于android framework 和Linux 内核之间抽象出来的一种结构,它是对Linux 驱动的一种封装,对上层提供统一的 接口,上层应用不需要知道下层硬件是如何实现的,屏蔽了底层实现的细节。
通过HAL 层,android 分两层来支持硬件驱动,其中一层在用户空间,另外一层在内核空间中,传统的linux 系统是将对硬件的支持和管理全 部放在内核空间中,对不同厂商的硬件支持全部放在硬件驱动模块之中。
本篇内容涉及到的具体的分析,我们都以audio模块为例来说明;
HAL层框架分析
首先我们需要关注几个重要的结构体定义,要实现一个Android的HAL,需要实现下面这三个结构体;
- hw_module_t
- hw_device_t
- hw_module_methods_t
这3个结构体定义都在hardware目录下的hardware.h中;
hw_module_t
用来描述硬件模块,hw_module_t是所有特定硬件模块的父类,例如对于audio、camera、sensor这些模块,他们不会直接使用hw_module_t结构体,而是会根据实际的情况将hw_module_t封装成一个新的结构体定义;
hw_module_t 结构体
arduino
/**
* Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
* and the fields of this data structure must begin with hw_module_t
* followed by module specific information.
*/
typedef struct hw_module_t {
uint32_t tag;
// 模块 API 版本号
uint16_t module_api_version;
// 主版本号
#define version_major module_api_version
// HAL层 API 版本号
uint16_t hal_api_version;
// 次版本号
#define version_minor hal_api_version
// 模块ID,用来区别其他硬件模块
/** Identifier of module */
const char *id;
// 模块名
/** Name of this module */
const char *name;
// 作者
/** Author/owner/implementor of the module */
const char *author;
// 硬件模块方法结构体,标识了硬件模块所包含的方法集
/** Modules methods */
struct hw_module_methods_t* methods;
// 加开硬件模块的库时得到的句柄,HAL层中的硬件模块是用动态链接库表示的,dso指针就是系统使用dlopen函数打开动态共享链接库获得的句柄
/** module's dso */
void* dso;
#ifdef __LP64__
uint64_t reserved[32-7];
#else
/** padding to 128 bytes, reserved for future use */
uint32_t reserved[32-7];
#endif
} hw_module_t;
在这个结构体的最前面有一段注释,含义为:
每一个硬件模块中都要定义一个名为HAL_MODULE_INFO_SYM的结构体变量,而这个结构体变量中的第一个成员必须是hw_module_t类型;
即每一个硬件模块都需要自己自定义一个模块结构体,其中该结构体中的第一个变量类型为hw_module_t;其本质上就是一种继承的思想,hw_module_t 是一个基类,描述所有硬件模块都应该具有的一些属性,具体到某个具体的硬件模块实现时,都需要继承hw_module_t 结构,也就是说hw_module_t 是所有特定硬件模块的父类。
hw_module_t id属性
在Android HAL的API定义中,我们关注hardware.h中定义的API接口,一共提供了两个:
arduino
int hw_get_module(const char *id, const struct hw_module_t **module);
int hw_get_module_by_class(const char *class_id, const char *inst, const struct hw_module_t **module);
在hardware.c中实现了这两个函数,其本质上hw_get_module函数的实现依赖hw_get_module_by_class,通过参数区别;
这两个函数的核心都是通过id值获取对应的module,id值作为该module的唯一标识与module一一映射;
我们看一下常见的一些module ID:
arduino
#define SENSORS_HARDWARE_MODULE_ID "sensors"
#define AUDIO_HARDWARE_MODULE_ID "audio"
#define RADIO_HARDWARE_MODULE_ID "radio"
#define RADIO_HARDWARE_MODULE_ID_FM "amfm" /* corresponds to RADIO_CLASS_AM_FM */
#define CAMERA_HARDWARE_MODULE_ID "camera"
#define GPS_HARDWARE_MODULE_ID "gps"
#define NFC_TAG_HARDWARE_MODULE_ID "nfc_tag"
#define AUDIO_HARDWARE_MODULE_ID_PRIMARY "primary"
#define AUDIO_HARDWARE_MODULE_ID_A2DP "a2dp"
#define AUDIO_HARDWARE_MODULE_ID_USB "usb"
#define AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX "r_submix"
#define BT_HARDWARE_MODULE_ID "bluetooth"
..................
这些module ID值都定义在各个模块的头文件中;
将指定的module ID值传入到了hw_get_module函数中,最终module指针就可以指向对应的module了,后续通过该module指针来open对应的模块等操作;
audio实例
audio_module 定义 & 初始化
arduino
struct audio_module {
struct hw_module_t common;
};
在hardware目录的audio.h文件中定义了audio_module结构体,该结构体中封装了hw_module_t结构体,audio_module结构体属于简单的封装,其他的模块的module结构体定义有属于复杂的封装;
ini
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 = "QCOM Audio HAL",
.author = "The Linux Foundation",
.methods = &hal_module_methods,
},
};
在audio.h中定义好了audio_module结构体之后,在后续的使用中就需要对该结构体进行赋值了;具体的赋值位置在各个厂商自定义的目录中,一般情况下可以在vendor目录中查找;
上述的一系列定义印证了HAL_MODULE_INFO_SYM的概念;
在初始化common参数的时候,将id值赋值为了AUDIO_HARDWARE_MODULE_ID,即后续操作的module为AUDIO_HARDWARE_MODULE;
audio_module 加载
ini
// static
int DevicesFactory::loadAudioInterface(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);
if (rc) {
ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__, AUDIO_HARDWARE_MODULE_ID,
if_name, strerror(-rc));
goto out;
}
rc = audio_hw_device_open(mod, dev);
if (rc) {
ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__, AUDIO_HARDWARE_MODULE_ID,
if_name, strerror(-rc));
goto out;
}
if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
rc = -EINVAL;
audio_hw_device_close(*dev);
goto out;
}
return OK;
out:
*dev = NULL;
return rc;
}
而在audio hal模块进行加载时,首先调用了hw_get_module_by_class函数,传入了AUDIO_HARDWARE_MODULE_ID加载执行的module,module加载完成之后,调用audio_hw_device_open函数开启module中执行的device,上述的流程在AudioPolicyManager的loadHwModule中实现;
hw_module_methods_t
用来打开硬件模块中包含的硬件设备,获得指向硬件设备结构体的指针;
我们首先先描述一下hw_module_methods_t结构体,因为这个结构体中定义的open函数会关联到hw_device_t模块的内容;
hw_module_methods_t 结构体
arduino
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;
这个结构体非常简单,其中只定义了一个open函数指针,在open函数中传入了module参数和device参数,id为常量值AUDIO_HARDWARE_INTERFACE,用来打开hw_deivce_t硬件设备;
audio 实例
module获取成功之后,紧接着就是调用audio_hw_device_open函数开启指定的device;
arduino
static inline int audio_hw_device_open(const struct hw_module_t* module,
struct audio_hw_device** device)
{
return module->methods->open(module, AUDIO_HARDWARE_INTERFACE,
TO_HW_DEVICE_T_OPEN(device));
}
在audio_hw_device_open函数中,其实调用的就是module结构体中的hw_module_methods_t结构体中定义的open函数,而open函数的实现在audio_hw.c中定义;
open函数赋值
ini
static struct hw_module_methods_t hal_module_methods = {
.open = adev_open,
};
我们在audio_hw.c中初始化audio_module结构体的时候,将其中的common变量进行了赋值,其中包含了对hw_module_methods_t结构体的赋值,而该值就是hal_module_methods。所以在初始化audio_module的时候,open函数指针就已经定义好了,该open函数指针指向了adev_open函数,该函数定义在audio_hw.c中;
hw_device_t
用来描述硬件设备,其实和hw_module_t类似,hw_device_t也可以看做是一个基类,它描述了所有硬件设备都应该具有的属性,然后具体到某个特定的硬件设备实现时,都需要封装自己的结构体。所以每个HAL层中硬件设备而对应的结构体中的第一个成员必须是hw_device_t;
hw_device_t 结构体
arduino
/**
* Every device data structure must begin with hw_device_t
* followed by module specific public methods and attributes.
*/
typedef struct hw_device_t {
/** tag must be initialized to HARDWARE_DEVICE_TAG */
uint32_t tag;
// 版本
uint32_t version;
// 表明该device从属于的module
/** reference to the module this device belongs to */
struct hw_module_t* module;
/** padding reserved for future use */
#ifdef __LP64__
uint64_t reserved[12];
#else
uint32_t reserved[12];
#endif
// 关闭设备的函数指针
/** Close this device */
int (*close)(struct hw_device_t* device);
} hw_device_t;
- module变量表示该hw_device_t(硬件设备)是由哪个hw_module_t(硬件模块)进行管理;
- close:这是一个函数指针,表示关闭已打开的硬件设备,这个对应这open指针函数,open指针函数定义在hw_module_methods_t结构体中;
audio 实例
audio_hw_device 定义
rust
struct audio_hw_device {
struct hw_device_t common;
uint32_t (*get_supported_devices)(const struct audio_hw_device *dev);
int (*init_check)(const struct audio_hw_device *dev);
/** set the audio volume of a voice call. Range is between 0.0 and 1.0 */
int (*set_voice_volume)(struct audio_hw_device *dev, float volume);
int (*set_master_volume)(struct audio_hw_device *dev, float volume);
int (*get_master_volume)(struct audio_hw_device *dev, float *volume);
int (*set_mode)(struct audio_hw_device *dev, audio_mode_t mode);
/* mic mute */
int (*set_mic_mute)(struct audio_hw_device *dev, bool state);
int (*get_mic_mute)(const struct audio_hw_device *dev, bool *state);
/* set/get global audio parameters */
int (*set_parameters)(struct audio_hw_device *dev, const char *kv_pairs);
char * (*get_parameters)(const struct audio_hw_device *dev,
const char *keys);
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);
/** This method creates and opens the audio hardware input stream */
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);
int (*get_microphones)(const struct audio_hw_device *dev,
struct audio_microphone_characteristic_t *mic_array,
size_t *mic_count);
/** This method dumps the state of the audio hardware */
int (*dump)(const struct audio_hw_device *dev, int fd);
int (*set_master_mute)(struct audio_hw_device *dev, bool mute);
int (*get_master_mute)(struct audio_hw_device *dev, bool *mute);
int (*create_audio_patch)(struct audio_hw_device *dev,
unsigned int num_sources,
const struct audio_port_config *sources,
unsigned int num_sinks,
const struct audio_port_config *sinks,
audio_patch_handle_t *handle);
/* Release an audio patch */
int (*release_audio_patch)(struct audio_hw_device *dev,
audio_patch_handle_t handle);
int (*get_audio_port)(struct audio_hw_device *dev,
struct audio_port *port);
/* Set audio port configuration */
int (*set_audio_port_config)(struct audio_hw_device *dev,
const struct audio_port_config *config);
};
typedef struct audio_hw_device audio_hw_device_t;
在audio中,映射hw_device_t结构体的为audio_hw_device,其中第一个变量为hw_deivce_t类型的common,其余的都是指针函数,都是用于操作该audio_device,包括初始化检查、设置音量、设置静音状态、设置参数配置、打开/关闭output/input stream等等一些操作;
上述提及到的函数都为指针函数,在后续的audio_hw.c定义中都会做一一映射的操作;
audio_hw_device 赋值
在描述hw_module_methods_t的时候,我们知道,open函数指向了audio_hw.c中的adev_open函数,而在调用audio_hw_device_open函数时调用了open函数,即调用了adev_open函数;
而在adev_open函数中对audio_hw_device进行了初始化:
ini
static int adev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
ALOGV("adev_open: %s", name);
struct stub_audio_device *adev;
if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
return -EINVAL;
adev = calloc(1, sizeof(struct stub_audio_device));
if (!adev)
return -ENOMEM;
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;
}
在该初始化过程中涉及到的函数都是在audio_hw.c中定义的;
总结
至此,涉及到的3个结构体定义就清晰了;