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

众所周知,现代的计算机系统由硬件系统以及软件系统两个部分组成,再好的硬件,如果没有软件的支持,就不能发挥其应有的作用。没有硬件,软件也就没有了运行条件的支持。手机中的软硬件关系也是如此。

Android系统从上而下分为以下几层:应用层(Application)->框架层(Framework)->外部库及Android运行时(External Libraries & Android Runtime)->硬件抽象层(HAL)->Linux内核(Linux Kernel)这几层。其中,直接与硬件相关的是内核硬件抽象层。由于android的Linux内核只提供简单的访问硬件逻辑,而从硬件中读取了什么值或者写入了什么值到硬件的逻辑则放入了硬件抽象层中。而这部分由于出于保护厂家的利益,遵循Apache License,不必进行开源,正是由于这样,Android从Linux内核主线的代码树中被踢出去了。所以说Android是一个开放的系统而不是开源的系统。

HAL从上而下涉及到android系统的硬件驱动层、硬件抽象层、运行时库以及应用程序框架层等,因此,学习HAL层,对理解Android整个系统具有重要的意义。而这一层的代码遵循的一定的规范,了解这些规范,有利于阅读Android源码时的理解。

Android系统的硬件抽象层采用模块的形式来管理硬件的访问接口。每个硬件抽象模块都对应一个动态链接库。这些动态链接库的命名要满足一定的规范。同时,Android使用hw_module_t结构体和hw_device_t分别描述每个硬件抽象模块和硬件抽象模块中的每个硬件设备。下面就来看看硬件抽象模块的命名规范以及hw_module_thw_device_t的定义吧。

Android的硬件抽象模块的命名规范在hardware/libhardware/hardware.c文件中定义,下面就来解析一下它的意思。

/**
 * There are a set of variant filename for modules. The form of the filename
 * is "<MODULE_ID>.variant.so" so for the led module the Dream variants 
 * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
 *
 * led.trout.so
 * led.msm7k.so
 * led.ARMV6.so
 * led.default.so
 */

static const char *variant_keys[] = {
    "ro.hardware",  /* This goes first so that it can pick up a different
                       file on the emulator. */
    "ro.product.board",
    "ro.board.platform",
    "ro.arch"
};

由上面代码可以知道,硬件抽象层的命名规则为<MODULE_ID>.variant.so,其中MODULE_ID表示硬件抽象模块的唯一编号ID,而variant则为ro.hardwarero.product.boardro.board.platform以及ro.arch四个系统属性中的一个类型,系统启动后按照定义的属性的顺序逐一取相应的值,若值存在,则使用该值作为variant的值,否则就使用xxx.default.so作为默认的抽象模块文件来加载硬件抽象层。

hardware/libhardware/include/hardware.h文件中,定义了ht_module_thw_device_t及相关结构体。下面来了解一下吧(为便于描述,代码有些许调整)

****struct hw_module_t****


/*
 * Value for the hw_module_t.tag field
 */

#define MAKE_TAG_CONSTANT(A,B,C,D) (((A) << 24) | ((B) << 16) | ((C) << 8) | (D))

#define HARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', 'T')

/**
 * 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"

/**
 * 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;

    /**
     * The API version of the implemented module. The module owner is
     * responsible for updating the version when a module interface has
     * changed.
     *
     * The derived modules such as gralloc and audio own and manage this field.
     * The module user must interpret the version field to decide whether or
     * not to inter-operate with the supplied module implementation.
     * For example, SurfaceFlinger is responsible for making sure that
     * it knows how to manage different versions of the gralloc-module API,
     * and AudioFlinger must know how to do the same for audio-module API.
     *
     * The module API version should include a major and a minor component.
     * For example, version 1.0 could be represented as 0x0100. This format
     * implies that versions 0x0100-0x01ff are all API-compatible.
     *
     * In the future, libhardware will expose a hw_get_module_version()
     * (or equivalent) function that will take minimum/maximum supported
     * versions as arguments and would be able to reject modules with
     * versions outside of the supplied range.
     */
    uint16_t module_api_version;
#define version_major module_api_version
    /**
     * version_major/version_minor defines are supplied here for temporary
     * source code compatibility. They will be removed in the next version.
     * ALL clients must convert to the new version format.
     */

    /**
     * The API version of the HAL module interface. This is meant to
     * version the hw_module_t, hw_module_methods_t, and hw_device_t
     * structures and definitions.
     *
     * The HAL interface owns this field. Module users/implementations
     * must NOT rely on this value for version information.
     *
     * Presently, 0 is the only valid value.
     */
    uint16_t hal_api_version;
#define version_minor hal_api_version

    /** 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;

    /** 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;

从上面代码可以看到:
(1)每个硬件模块都必须定义一个硬件抽象模块结构体,而且其第一个成员变量的类型必须是hw_module_t类型的变量
(2)硬件抽象层的每一个模块都必须存在一个导出符号HAL_MODULE_INFO_SYM,即HMI,它指向一个自定义的硬件抽象层模块结构体,换句话说,就是要存在一个变量名为HMI的自定义的硬件抽象层模块的结构体变量。到后续博文讲述硬件抽象层模块的加载过程会看到具体的使用。
(3)结构体struct hw_module_ttag变量必须设为HARDWARE_MODULE_TAG(((H)<<24)|((W)<<16)|((M)<<8)|(T))常量。
(4)hw_module_t结构体的dso变量用来保存加载硬件抽象模块后得到的句柄值,每一个硬件抽象模块都对应一个动态链接库文件,硬件抽象模块的加载过程其实就是使用dlopen函数打开对应的动态链接库文件获得这个句柄的过程,而使用dlclose函数进行硬件抽象模块的卸载时需要用到这个句柄,因此需要把它保存起来,供之后卸载使用。
(5)hw_module_t结构体的methods给出了一个硬件抽象模块的操作方法列表,它的类型为struct hw_module_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的函数指针变量,用来打开硬件抽象层模块中的硬件设备。其中,module表示硬件设备所处的硬件抽象模块,由于一个硬件抽象模块可能包含若干个设备,因此我们需要提供唯一标示设备的id。前面说过,android使用hw_device_t来表示硬件抽象模块中的硬件设备,所以用参数device来表示一个已经打开的设备。下面来看看hw_device_t结构体的定义。

/**
 * Every device data structure must begin with hw_device_t
 * followed by module specific public methods and attributes.
 * 使用hw_device_t结构体来描述模块代表的硬件设备
 */
typedef struct hw_device_t {
    /** tag must be initialized to HARDWARE_DEVICE_TAG */
    uint32_t tag; //设备标记,必须使用系统定义的HARDWARE_DEVICE_TAG来初始化
    uint32_t version; //版本

    /** reference to the module this device belongs to */
    struct hw_module_t* module; //hw_module_t信息,硬件抽象模块

    /** 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;

从上面可以看到:
(1)和hw_module_t的说明一样,硬件抽象模块中的每一个硬件设备都必须自定义一个硬件设备结构体,该结构的第一个变量的类型必须为hw_device_t
(2)hw_device_ttag变量必须用HARDWARE_DEVICE_TAG即常量(((H)<<24)|((W)<<16)|((M)<<8)|(T)),用来标识这是一个硬件设备结构体
(3)函数指针close用来关闭一个硬件设备。

从上面的代码中,我们来总结一下在android硬件抽象层的编码规范:
(1)所写的抽象模块动态库的命名必须以<MODULE_ID>.variant.so为格式命名
(2)需要自定义硬件抽象模块结构体,其中第一个变量的类型必须为struct hw_module_t,同时,该自定义硬件抽象模块结构体的变量名必须为HAL_MODULE_INFO_SYMHMI。同时提供相应的操作列表hw_method_t
(3)需要自定义硬件抽象模块的硬件设备结构体,其中第一个变量的类型必须为struct hw_device_t

本篇博文就写到这里,第一次认真写,还真是不太容易啊,希望自己要努力坚持!!后面将继续分析硬件抽象模块的加载过程以及如何实现从内核驱动到应用层代码的编写,当然,水平有限,要借助罗升阳老师博客【博客地址】的力量~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,540评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,640评论 2 374
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,643评论 0 326
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,672评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,525评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,387评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,809评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,450评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,743评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,787评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,560评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,406评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,824评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,048评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,335评论 1 253
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,784评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,997评论 2 337

推荐阅读更多精彩内容