Android硬件抽象层(HAL)模块编写规范

2,001


HAL(硬件抽象层)

Android的硬件抽象层,简单来说,就是对Linux内核驱动程序的封装,向上提供接口,向下屏蔽了具体的实现细节。也就是将Linux内核对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中,硬件抽象层运行在用户空间,对应具体的驱动实现细节,而Linux内核驱动程序运行在内核空间,只提供简单的数据访问逻辑。

那为什么要将驱动的具体实现细节封装到硬件抽象层呢?

Android系统使用的是Linux内核,Linux内核是基于GPL许可(GNU License),即对源码的修改都必须开源,如果将驱动的实现细节放在Linux内核层,那么就意味着需要公开驱动程序的源代码,这样显然是违背了硬件厂商的自身利益。

那为什么将其抽象到硬件抽象层就可以规避这个问题呢?

除Linux内核外的Android源码使用的是ASL许可(Apache License),而ASL许可无须发布源代码,这样Android就可以对该部分的代码不开源。

另外,HAL也可以屏蔽不同硬件设备的差异,为Android提供了统一的访问硬件设备的接口。不同的硬件厂商遵循HAL标准来实现自己的硬件控制逻辑,这样开发者不必关心不同硬件设备的差异,只需要按照HAL提供的标准接口访问硬件就可以了。

HAL 模块的实现

Android 系统的 HAL 层其实并不复杂,只要你能理解清楚下面这 3 个结构体的含义:

  • hw_module_t:用来描述硬件模块
  • hw_device_t:用来描述硬件设备
  • hw_module_methods_t:用来打开硬件模块中包含硬件设备,获得指向硬件设备结构体的指针

hw_module_t

/**
 * 每个硬件模块中都要定义一个名字叫做 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。 

hw_module_methods_t

/**
 * 该结构体只有一个名为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;

hw_device_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。

Audio HAL 模块的实现

Step 1:定义 struct audio_module 模块

具体的硬件模块要定义一个新的结构体并且这个结构体的第一个成员必须是 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