HAL知识

什么是HAL

硬件抽象层:Hardware abstraction layer,缩略语为:HAL。是介于android Framework和 linux kernel之间的抽象出来的一层结构。 对上层调用提供统一的接口,上层应用不需要知道下层硬件是如何具体实现的,屏蔽了底层实现的细节。

定义HAL层的原因
  1. Android 使用的开源协议是Apache Liscence,这个协议比较宽松,允许开发者获得并且修改了源代码之后,不公布源代码; 而linux 使用的是开源协议GPL,它的限制比较多,它要求开发者添加或者修改了源码之后,必须把添加或者修改后的源码公布出来。
  2. 如果 Android 系统像其他 Linux 系统一样,把对硬件的支持完全实现在 Linux 内核的驱动模块中,那么硬件厂商就必须将这些硬件驱动源码公开,这样就可能损害到厂商的利益,因为这相当于暴露了硬件的实现细节和参数。
  3. 所以,Android 就在用户空间搞了一个 HAL 层,将硬件的一些重要的操作都放在这一层中完成,这些操作都封装在厂商所提供的一个动态链接库中,从而达到了避免源码公开的目的,而底层 Linux 内核空间中的设备驱动模块,现在则只提供一些最基本的硬件设备寄存器操作的功能。
HAL层的基本知识
  1. HAL 实现通常会以.so的形式,内置在共享库模块中,但 Android 并不要求 HAL 实现与设备驱动程序之间进行标准交互,因此可以视情况采取适当的做法。不过,要使 Android 系统能够与您的硬件正确互动,您必须遵守各个特定于硬件的 HAL 接口中定义的规则
  2. 为了保证 HAL 具有可预测的结构,每个特定于硬件的 HAL 接口都要具有 hardware/libhardware/include/hardware/hardware.h 中定义的属性。这类接口可让 Android 系统以一致的方式加载 HAL 模块的正确版本。
HAL层框架分析
结构体
要实现一个Android 的HAL,需要实现下面这三个结构体:
hw_module_t : 用来描述硬件模块
hw_device_t :  用来描述硬件设备
hw_module_methods_t: 用来打开硬件模块中包含硬件设备,获得指向硬件设备结构体的指针

在下面的文件中描述了HAL的编写规范,并且给出了标准接口

代码路径:/hardware/libhardware/include/hardware/hardware.h
hw_module_t
/**
 * 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 {
    /** tag must be initialized to HARDWARE_MODULE_TAG */
    uint32_t tag;  //tag,根据引文注释可以看到必须被初始化为HARDWARE_MODULE_TAG

    /** major version number for the module */
    uint16_t version_major;//主版本号

    /** minor version number of the module */
    uint16_t version_minor;//次版本号

    /** Identifier of module */
    const char *id;//模块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;//硬件模块方法结构体

    /** module's dso */
    void* dso;//打开硬件模块的库时得到的句柄

    /** padding to 128 bytes, reserved for future use */
    uint32_t reserved[32-7];

} hw_module_t;
1. 每个硬件模块中都要定义一个名字叫做 HAL_MODULE_INFO_SYM 结构体变量,而这结构体变量中的第一个成员必须是 hw_module_t 
   类型。也就是说,每个硬件模块都要自己实现一个结构体,但是这个结构体的第一个成员必须是 hw_module_t 结构体类型。

2. 这里有一种继承思想,hw_module_t 是一个基类,描述所有硬件模块都应该具有的一些属性,具体到某个具体的硬件模块实现时,都需要
   继承hw_module_t 结构,也就是说hw_module_t 是所有特定硬件模块的父类。

3. hw_module_t 中包含一个hw_module_methods_t 的结构体,hw_module_methods_t 这个结构体定义了一个重要的open函数指针,需要硬件
    厂商去实现
hw_module_methods_t
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
/**
 * 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;   //设备tag

    /** version number for hw_device_t */
    uint32_t version;//版本

    /** reference to the module this device belongs to */
    struct hw_module_t* module;//本设备归属的硬件模块

    /** padding reserved for future use */
    uint32_t reserved[12];//保留

    /** Close this device */
    int (*close)(struct hw_device_t* device);//关闭设备的函数指针

} hw_device_t;
1. hw_device_t是在hw_module_t 中open 函数返回的一个结构,它用来描述所有硬件设备的属性,所有硬件设置相关的接口也会在这里实现,

2. 和hw_module_t 类似,hw_device_t 也可以看做是一个基类,描述了所有硬件设备应该具有的属性,然后具体到某个特定的硬件设备实现时,
    都需要继承相应的hw_device_t 结构。所以,每个HAL层硬件设备对应的结构体中的第一个成员必须是hw_device_t。比如说,传感器模块,
    sensor_module,是一个硬件模块,但是手机中的传感器就对应的有好多种,比如加速度acc_sensor,磁传感器M_sensor等,那么他们都属于
    sensor_module,但是他们有都有自己的hw_device_t结构体来描述。
常量
#define HAL_MODULE_INFO_SYM         HMI
#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"
函数
int hw_get_module(const char *id, const struct hw_module_t **module)    // 通过ID获取模块相关联的信息
{
    return hw_get_module_by_class(id, NULL, module);
}

当用户调用hw_get_module()函数时,将硬件的id名进行传入,那么函数将会从当前系统中,注册的硬件模块里查找对应的硬件模块,
并通过module二级指针进行返回。

HAL类型

HAL类型

HAL的调用逻辑
使用hw_get_module 传入目标HAL的id
根据传入的HAL id,拼装成路径,去寻找对应的.so文件
使用dlopen加载打开对应的so文件,传回一个操作句柄handle
调用 dlsym函数解析打开的库,即**用dlsym去寻找HAL_MODULE_INFO_SYM_AS_STR名字的结构体**
通过dlsym解析之后就得到了hw_module_t,将从库中解析得到的结构体中的id和传入的id做比较,看是否一致。如果一致则证明就是得到正确的硬件模块。
最后将得到的module结果赋值给传入的第三个参数hw_module_t
HAL module命名必须是HAL_MODULE_INFO_SYM的原因
每个HAL module 都使用HAL_MODULE_INFO_SYM作为xxx_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 = "NVIDIA Tegra Audio HAL",
        .author = "The Android Open Source Project",
        .methods = &hal_module_methods,
    },
};

通过dlsym去寻找HAL_MODULE_INFO_SYM_AS_STR这个统一的名称,
因为每个HAL module 结构体中的第一个成员必须是struct hw_module_t,且只有一个
所以在dlsym 找到 xxx_module_t 以后,返回的地址是xxx_module_t 地址,也是第一个成员变量的地址,也就是hw_module_t 模块
这样就能调用 module 的 open 函数,去找到xxx _device_t, hw_device_t必须要在第一个的原因也是如此
实现HAL设备

HAL开发实例

扩展知识

property_get / property_set

参考链接

https://www.jianshu.com/p/2dafe06cda15
https://www.cnblogs.com/qiangge-python/p/10142249.html
http://t.zoukankan.com/Cqlismy-p-11823592.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

多维不语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值