Android系统HAL基本概念

1、前言

Android系统硬件抽象层(Hardware Abstraction Layer),简写为HAL,是连接Android Framework与Linux内核设备驱动的重要桥梁。HAL存在的意义有以下两个方面:

(1)HAL层屏蔽掉不同硬件设备的差异,为Android提供了统一的设备访问接口。不同的硬件厂商遵循HAL标准来实现自己的硬件控制逻辑,开发者不必关心硬件设备的差异,只需按照HAL提供的标准接口对硬件进行访问即可。

(2)HAL层帮助硬件厂商隐藏了设备的核心细节,HAL层位于用户空间,遵循Apache协议,允许硬件厂商不公开源码,将设备相关的实现放在HAL层中实现,并以共享库(.so)的形式进行提供。

下面的图描述了HAL层在Android系统中的位置:

使用HAL这种设计模式,使得上层服务与底层硬件之间的耦合度降低。

2、Stub HAL

Android系统中HAL具有两种实现方式:Legacy以及Stub HAL,初期使用的是Legacy HAL的方式,该方式为标准的Linux共享库,其它应用程序直接调用HAL层共享库导出的函数。Google后来提出了Stub HAL的方式,仍然以共享库(.so)的形式提供,它把所有供外部访问的的方法(函数)的入口指针保存在统一的数据结构,其它程序需要访问HAL中方法时,需要先获得Stub,然后通过具体的函数指针去读写底层设备。

3、HAL标准接口的定义

Android已经为常用的硬件设备定义了标准的HAL接口,这些组件有以下:

当我们需要为这些设备编写HAL层代码时,必须严格按照Google定义的标准接口去实现,否则将导致设备无法在Android Framework下正常工作。

关于HAL的源码在Android源码树的hardware目录,其中关于Stub方式的HAL实现在libhardware目录下:

# 常用设备HAL标准接口的头文件
AOSP/hardware/libhardware/include/hardware

# 常用设备HAL标准接口实现
AOSP/hardware/libhardware/modules/

在目录AOSP/hardware/libhardware/include/hardware中包含了一个hardware.h的接口头文件,里面具有比较重要的结构体、变量和函数指针,在开发自己设备的HAL文件时,需要嵌入这些结构体,也就是继承它们的特性,接下来对这些标准接口做介绍。

首先是struct hw_module_t结构体,定义如下:

typedef struct hw_module_t {
    uint32_t tag;
    uint16_t module_api_version;
    uint16_t hal_api_version;
    const char *id;
    const char *name;
    const char *author;
    struct hw_module_methods_t* module;
    void* dso;
    uint32_t reserved[32-7];
} hw_module_t;

成员简单介绍:

tag:该值为module的tag,必须定义为HARDWARE_MODULE_TAG;

module_api_version:模块中API函数接口的版本号;

hal_api_version:HAL模块接口的API版本号;

id:硬件的id号,唯一标识模块;

name:该模块的名称;

author:模块的作者;

module:指向封装有open函数指针的结构体,用于模块打开。

对于struct hw_module_t结构体的理解为,每个硬件通过hw_module_t结构体来描述,我们可以"继承"这个结构体,拓展自己的属性,但是需要注意的是,宿主结构的第一个成员必须是struct hw_module_t类型,硬件对象必须定义一个固定的名字:HMI(Hardware Module Information),每个硬件对象里面都包含了module指针,对应得结构体里面封装了open函数指针,用于打开硬件,并会返回硬件的操作方式。

接下来是struct hw_module_methods_t结构体的定义,如下所示:

typedef struct hw_module_methods_t {
    int (*open)(const struct hw_module_t* module, const char* id,
            struct hw_device_t** device);

} hw_module_methods_t;

该结构体里面封装了一个open函数指针,该函数用于实现打开一个特定的设备,打开的设备通过device二级指针进行返回。

另外一个重要的结构体为struct hw_device_t,该定义如下:

typedef struct hw_device_t {
    uint32_t tag;
    uint32_t version;
    struct hw_module_t* module;
    uint32_t reserved[12];
    int (*close)(struct hw_device_t* device);
} hw_device_t;

成员简单介绍:

tag:设备的tag,必须定义为HARDWARE_DEVICE_TAG;

version:设备操作方式的版本号;

module:hw_module_t结构体指针,指向设备所属的硬件模块,设备操作接口与硬件模块的联系;

close:函数指针,关闭该硬件设备的方法。

对于struct hw_device_t结构体的理解为,硬件设备的操作方法,通过struct module_methods_t结构内的open函数指针将返回hw_device_t结构体指针,从而获得了该硬件设备的操作方法,我们也可以"继承"该结构体,拓展实际硬件设备的操作方式,但是需要注意的是,在宿主结构中,第一个成员必须是struct hw_device_t类型。

在上面介绍的三个结构之间是紧密联系的,每个硬件模块都由一个struct hw_module_t结构体进行描述,当用户拿到了这个硬件模块,调用其封装的open函数,便返回了硬件设备的操作方法接口,从而便可以调用相关接口对硬件设备进行读写了。

在HAL标准中还有两个比较重要的宏定义和一个函数,如下:

/**
 * Name of the hal_module_info
 */
#define HAL_MODULE_INFO_SYM         HMI

/**
 * Name of the hal_module_info as a string
 */
#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"

/**
 * Get the module info associated with a module by id.
 *
 * @return: 0 == success, <0 == error and *module == NULL
 */
int hw_get_module(const char *id, const struct hw_module_t **module);

在上面的代码中,HAL_MODULE_INFO_SYM为硬件模块固定的变量名,另外一个宏只是字符串的显示,当用户调用hw_get_module()函数时,将硬件的id名进行传入,那么函数将会从当前系统中注册的硬件模块里查找对应的硬件模块,并通过module二级指针进行返回。

4、小结

本篇文章对Android系统中HAL的基本概念做简单介绍,另外,对HAL提供的接口进行了简单的描述。

猜你喜欢

转载自www.cnblogs.com/Cqlismy/p/11816005.html