Android中HAL如何向上层提供接口总结

转自:http://blog.csdn.net/flydream0/article/details/7086273

参考文献:

http://blog.csdn.net/luoshengyang/article/details/6573809

http://blog.csdn.net/hongtao_liu/article/details/6060734

1.什么是HAL?


HAL的全称是Hardware Abstraction Layer,即硬件抽象层.其架构图如下:

Android的HAL是为了保护一些硬件提供商的知识产权而提出的,是为了避开linux的GPL束缚。思路是把控制硬件的动作都放到了Android HAL中,而linux driver仅仅完成一些简单的数据交互作用,甚至把硬件寄存器空间直接映射到user space。而Android是基于Aparch的license,因此硬件厂商可以只提供二进制代码,所以说Android只是一个开放的平台,并不是一个开源的平台。也许也正是因为Android不遵从GPL,所以Greg Kroah-Hartman才在2.6.33内核将Andorid驱动从linux中删除。GPL和硬件厂商目前还是有着无法弥合的裂痕。Android想要把这个问题处理好也是不容易的。

总结下来,Android HAL存在的原因主要有:

1. 并不是所有的硬件设备都有标准的linux kernel的接口

2. KERNEL DRIVER涉及到GPL的版权。某些设备制造商并不原因公开硬件驱动,所以才去用HAL方式绕过GPL。

3. 针对某些硬件,Android有一些特殊的需求.

2.与接口相关的几个结构体


首先来看三个与HAL对上层接口有关的几个结构体:

  1. struct hw_module_t;                      //模块类型
  2. struct hw_module_methods_t;      //模块方法
  3. struct hw_device_t;                      //设备类型

这几个数据结构是在Android工作目录/hardware/libhardware/include/hardware/hardware.h文件中定义.

 
 
 

3.解释


一般来说,在写HAL相关代码时都得包含这个hardware.h头文件,所以有必要先了解一下这个头文件中的内容.

  1. /*
  2. * Copyright (C) 2008 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. *      http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef ANDROID_INCLUDE_HARDWARE_HARDWARE_H
  17. #define ANDROID_INCLUDE_HARDWARE_HARDWARE_H
  18. #include <stdint.h>
  19. #include <sys/cdefs.h>
  20. #include <cutils/native_handle.h>
  21. #include <system/graphics.h>
  22. __BEGIN_DECLS
  23. /*
  24. * Value for the hw_module_t.tag field
  25. */
  26. #define MAKE_TAG_CONSTANT(A,B,C,D) (((A) << 24) | ((B) << 16) | ((C) << 8) | (D))
  27. #define HARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', 'T')
  28. #define HARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', 'T')
  29. struct hw_module_t;
  30. struct hw_module_methods_t;
  31. struct hw_device_t;
  32. /**
  33. * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
  34. * and the fields of this data structure must begin with hw_module_t
  35. * followed by module specific information.
  36. */
  37. //每一个硬件模块都每必须有一个名为HAL_MODULE_INFO_SYM的数据结构变量,它的第一个成员的类型必须为hw_module_t
  38. typedef struct hw_module_t {
  39. /** tag must be initialized to HARDWARE_MODULE_TAG */
  40. uint32_t tag;
  41. /** major version number for the module */
  42. uint16_t version_major;
  43. /** minor version number of the module */
  44. uint16_t version_minor;
  45. /** Identifier of module */
  46. const char *id;
  47. /** Name of this module */
  48. const char *name;
  49. /** Author/owner/implementor of the module */
  50. const char *author;
  51. /** Modules methods模块方法列表,指向hw_module_methods_t */
  52. struct hw_module_methods_t* methods;
  53. /** module's dso */
  54. void* dso;
  55. /** padding to 128 bytes, reserved for future use */
  56. uint32_t reserved[32-7];
  57. } hw_module_t;

    //硬件模块方法列表的定义,这里只定义了一个open函数

  1. typedef struct hw_module_methods_t {
  2. /** Open a specific device */
  3. int (*open)(const struct hw_module_t* module, const char* id, //注意这个open函数明确指出第三个参数的类型为struct hw_device_t**
  4. struct hw_device_t** device);
  5. } hw_module_methods_t;
  1. /**
  2. * Every device data structure must begin with hw_device_t
  3. * followed by module specific public methods and attributes.
  4. */
  5. //每一个设备数据结构的第一个成员函数必须是hw_device_t类型,其次才是各个公共方法和属性
  6. typedef struct hw_device_t {
  7. /** tag must be initialized to HARDWARE_DEVICE_TAG */
  8. uint32_t tag;
  9. /** version number for hw_device_t */
  10. uint32_t version;
  11. /** reference to the module this device belongs to */
  12. struct hw_module_t* module;
  13. /** padding reserved for future use */
  14. uint32_t reserved[12];
  15. /** Close this device */
  16. int (*close)(struct hw_device_t* device);
  17. } hw_device_t;
  18. /**
  19. * Name of the hal_module_info
  20. */
  21. #define HAL_MODULE_INFO_SYM         HMI
  22. /**
  23. * Name of the hal_module_info as a string
  24. */
  25. #define HAL_MODULE_INFO_SYM_AS_STR  "HMI"
  26. /**
  27. * Get the module info associated with a module by id.
  28. *
  29. * @return: 0 == success, <0 == error and *module == NULL
  30. */
  31. int hw_get_module(const char *id, const struct hw_module_t **module);
  32. /**
  33. * Get the module info associated with a module instance by class 'class_id'
  34. * and instance 'inst'.
  35. *
  36. * Some modules types necessitate multiple instances. For example audio supports
  37. * multiple concurrent interfaces and thus 'audio' is the module class
  38. * and 'primary' or 'a2dp' are module interfaces. This implies that the files
  39. * providing these modules would be named audio.primary.<variant>.so and
  40. * audio.a2dp.<variant>.so
  41. *
  42. * @return: 0 == success, <0 == error and *module == NULL
  43. */
  44. int hw_get_module_by_class(const char *class_id, const char *inst,
  45. const struct hw_module_t **module);
  46. __END_DECLS
  47. #endif  /* ANDROID_INCLUDE_HARDWARE_HARDWARE_H */

由以上内容可以看出(typedef struct hw_module_t ,typedef struct hw_device_t),如果我们要写一个自定义设备的驱动的HAL层时,我们得首先自定义两个数据结构:

假设我们要做的设备名为XXX:

在头文件中定义:XXX.h

  1. /*定义模块ID*/
  2. #define XXX_HARDWARE_MODULE_ID "XXX"
  3. /*硬件模块结构体*/
  4. //见hardware.h中的hw_module_t定义的说明,xxx_module_t的第一个成员必须是hw_module_t类型,其次才是模块的一此相关信息,当然也可以不定义,
  5. //这里就没有定义模块相关信息
  6. struct xxx_module_t {
  7. struct hw_module_t common;
  8. };
  9. /*硬件接口结构体*/
  10. //见hardware.h中的hw_device_t的说明,要求自定义xxx_device_t的第一个成员必须是hw_device_t类型,其次才是其它的一些接口信息.
  11. struct xxx_device_t {
  12. struct hw_device_t common;
  13. //以下成员是HAL对上层提供的接口或一些属性
  14. int fd;
  15. int (*set_val)(struct xxx_device_t* dev, int val);
  16. int (*get_val)(struct xxx_device_t* dev, int* val);
  17. };

注:特别注意xxx_device_t的结构定义,这个才是HAL向上层提供接口函数的数据结构,其成员就是我们想要关心的接口函数.

接下来我们在实现文件XXX.c文件中定义一个xxx_module_t的变量:

  1. /*模块实例变量*/
  2. struct xxx_module_t HAL_MODULE_INFO_SYM = {    //变量名必须为HAL_MODULE_INFO_SYM,这是强制要求的,你要写Android的HAL就得遵循这个游戏规则,
  3. //见hardware.h中的hw_module_t的类型信息说明.
  4. common: {
  5. tag: HARDWARE_MODULE_TAG,
  6. version_major: 1,
  7. version_minor: 0,
  8. id: XXX_HARDWARE_MODULE_ID,    //头文件中有定义
  9. name: MODULE_NAME,
  10. author: MODULE_AUTHOR,
  11. methods: &xxx_module_methods,  //模块方法列表,在本地定义
  12. }
  13. };

注意到上面有HAL_MODULE_INFO_SYM变量的成员common中包含一个函数列表xxx_module_methods,而这个成员函数列表是在本地自定义的。那么这个成员函数列是不是就是HAL向上层提供函数的地方呢?很失望,不是在这里,前面我们已经说过了,是在xxx_device_t中定义的,这个xxx_module_methods实际上只提供了一个open函数,就相当于只提供了一个模块初始化函数.其定义如下:

  1. /*模块方法表*/
  2. static struct hw_module_methods_t xxx_module_methods = {
  3. open: xxx_device_open
  4. };

注意到,上边的函数列表中只列出了一个xxx_device_open函数,这个函数也是需要在本地实现的一个函数。前面说过,这个函数只相当于模块初始化函数。

那么HAL又到底是怎么将xxx_device_t中定义的接口提供到上层去的呢?

且看上面这个函数列表中唯一的一个xxx_device_open的定义:

  1. static int xxx_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) {
  2. struct xxx_device_t* dev;
  3. dev = (struct hello_device_t*)malloc(sizeof(struct xxx_device_t));//动态分配空间
  4. if(!dev) {
  5. LOGE("Hello Stub: failed to alloc space");
  6. return -EFAULT;
  7. }
  8. memset(dev, 0, sizeof(struct xxx_device_t));
  9. //对dev->common的内容赋值,
  10. dev->common.tag = HARDWARE_DEVICE_TAG;
  11. dev->common.version = 0;
  12. dev->common.module = (hw_module_t*)module;
  13. dev->common.close = xxx_device_close;
  14. //对dev其它成员赋值
  15. dev->set_val = xxx_set_val;
  16. dev->get_val = xxx_get_val;
  17. if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {
  18. LOGE("Hello Stub: failed to open /dev/hello -- %s.", strerror(errno));
  19. free(dev);
  20. return -EFAULT;
  21. }
  22. //输出&(dev->common),输出的并不是dev,而是&(dev->common)!(common内不是只包含了一个close接口吗?)
  23. *device = &(dev->common);
  24. LOGI("Hello Stub: open /dev/hello successfully.");
  25. return 0;
  26. }

经验告诉我们,一般在进行模块初始化的时候,模块的接口函数也会“注册”,上面是模块初始化函数,那么接口注册在哪?于是我们找到*device =&(dev->common);这行代码,可问题是,这样一来,返回给调用者不是&(dev->common)吗?而这个dev->common仅仅只包含了一个模块关闭接口!到底怎么回事?为什么不直接返回dev,dev下不是提供所有HAL向上层接口吗?

在回答上述问题之前,让我们先看一下这xxx_device_open函数原型,还是在hardware.h头文件中,找到下面几行代码:

  1. typedef struct hw_module_methods_t {
  2. /** Open a specific device */
  3. int (*open)(const struct hw_module_t* module, const char* id,
  4. struct hw_device_t** device);
  5. } hw_module_methods_t;

这是方法列表的定义,明确要求了方法列表中有且只一个open方法,即相当于模块初始化方法,且,这个方法的第三个参数明确指明了类型是struct hw_device_t **,而不是用户自定义的xxx_device_t,这也就是解译了在open函数实现内为什么输出的是&(dev->common)而不是dev了,原来返回的类型在hardware.h中的open函数原型中明确指出只能返回hw_device_t类型.

可是,dev->common不是只包含close接口吗?做为HAL的上层,它又是怎么"看得到"HAL提供的全部接口的呢?

接下来,让我们来看看做为HAL上层,它又是怎么使用由HAL返回的dev->common的:

参考: 在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口 这篇文章,从中可以看到这么几行代码:

  1. /*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/
  2. static inline int hello_device_open(const hw_module_t* module, struct hello_device_t** device) {
  3. return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
  4. }

由此可见,返回的&(dev->common)最终会返回给struce hello_device_t **类型的输出变量device,换句话说,类型为hw_device_t的dev->common在初始化函数open返回后,会强制转化为xxx_device_t来使用,终于明白了,原来如此!另外,在hardware.h中对xxx_device_t类型有说明,要求它的第一个成员的类型必须是hw_device_t,原来是为了HAL上层使用时的强制转化的目的,如果xxx_device_t的第一个成员类型不是hw_device_t,那么HAL上层使用中强制转化就没有意义了,这个时候,就真的“看不到”HAL提供的接口了.

此外,在hardware.h头文件中,还有明确要求定义xxx_module_t类型时,明确要求第一个成员变量类型必须为hw_module_t,这也是为了方便找到其第一个成员变量common,进而找到本地定义的方法列表,从而调用open函数进行模块初始化.

综上所述,HAL是通过struct xxx_device_t这个结构体向上层提供接口的.

即:接口包含在struct xxx_device_t这个结构体内。

而具体执行是通过struct xxx_module_t HAL_MODULE_INFO_SYM这个结构体变量的函数列表成员下的open函数来返回给上层的.

MTK Androiod HAL如何向上层提供接口的更多相关文章

  1. Android MTK平台 客制化系统来电界面(屏蔽 InCallUI 提供接口给客户自行展示来电去电页面)

    OS: Android 8.1 需求分析 1.禁止系统来电铃声,提供接口给客户自己播放铃声 2.禁止系统拉起来去电页面(InCallActivity),消息通知客户拉起自己的来去电页面 3.禁止来电消 ...

  2. Android 11(R) Power HAL AIDL简析 -- 基本接口

    Android 11(R) Power HAL AIDL将分三篇文章来介绍: Android 11(R) Power HAL AIDL简析 -- 基本接口 Android 11(R) Power HA ...

  3. Java服务器对外提供接口以及Android端向服务器请求数据

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5056780.html 讲解下java服务器是如何对移动终端提供接口的,以什么数据格式提供出去,移动端又是怎么 ...

  4. android中自定义view---实现竖直方向的文字功能,文字方向朝上,同时提供接口,判断当前touch的是哪个字符,并改变颜色

    android自定义view,实现竖直方向的文字功能,文字方向朝上,同时提供接口,判断当前touch的是哪个字符,并改变颜色. 由于时间比较仓促,因此没有对代码进行过多的优化,功能远远不如androi ...

  5. 使用WCF对外提供接口

    本篇将通过WCF以webservices的方式对外提供接口.同时使用NUnit对webservices中的方法进行单元测试. 开发契约 contract Contract项目为类库项目,该项目下会包含 ...

  6. springboot+CXF开发webservice对外提供接口(转)

    文章来源:http://www.leftso.com/blog/144.html 1.项目要对外提供接口,用webservcie的方式实现 2.添加的jar包 maven: <dependenc ...

  7. 开发FTP服务接口,对外提供接口服务

    注意:本文只适合小文本文件的上传下载,因为post请求是有大小限制的.默认大小是2m,虽然具体数值可以调节,但不适合做大文件的传输 最近公司有这么个需求:以后所有的项目开发中需要使用ftp服务器的地方 ...

  8. Frp内网穿透搭建,家庭主机对外提供接口,支持ssh访问

    Frp内网穿透搭建,家庭主机对外提供接口,支持ssh访问 1.使用场景: 需求1.家中服务器 ubuntu 主机,跑接口服务,需要对外暴漏, 需求2.同时需要在外网ssh远程 ​ 关键词: frp内网 ...

  9. MTK andorid从底层到上层添加驱动

    1 [编写linux驱动程序] 1.1 一.编写驱动核心程序 1.2 二.配置Kconfig 1.3 三.配置Makefile 1.4 四.配置系统的autoconfig 1.5 五.编译 2 [编写 ...

随机推荐

  1. button控件根据文本自适应

    2020-03-12 每日一例第5天 1.添加按钮1和label.textbox控件,并修改相应的text值: 2.修改textBox1的TextChanged事件并输入代码: button1.Tex ...

  2. JAVAEE学习day03,基本的流程控制

    有问题请留言 1.流程控制语句分类 1)顺序控制语句 2)选择结构语句 if... if...else... if...else if... else... for... switch... whil ...

  3. burpsuit的安装和简单使用

    一.burpsuit的环境搭建 Burp Suite可以说是Web安全工具中的瑞士军刀,打算写几篇Blog以一个小白的角度去学习Burp Suite(简称BP),会详细地说一下的用法,说明一下每一个部 ...

  4. Spring Boot 结合 Redis 序列化配置的一些问题

    前言 最近在学习Spring Boot结合Redis时看了一些网上的教程,发现这些教程要么比较老,要么不知道从哪抄得,运行起来有问题.这里分享一下我最新学到的写法 默认情况下,Spring 为我们提供 ...

  5. Centos7报Could not resolve host: mirrorlist.centos.org; Unknown error(VMware网络设置)

    软件:VMware 12 Linux版本:centOS 7 网络设置:桥接模式 安装后ping百度网址时报错:Name or service not know,使用yum安装时报错:Could not ...

  6. [Alg] 文本匹配-单模匹配-KMP

    1. 暴力求解 如下图所示.蓝色的小三角表示和sequence比较时的开始字符,绿色小三角表示失败后模式串比对的开始字符,红色框表示当前比较的字符对. 当和模式串发生不匹配时,蓝色小三角后移一位,绿色 ...

  7. 都2020年了 还要学JSP吗?

    前言 2020年了,还需要学JSP吗?我相信现在还是在大学的同学肯定会有这个疑问. 其实我在18年的时候已经见过类似的问题了「JSP还应该学习吗」.我在18年发了几篇JSP的文章,已经有不少的开发者评 ...

  8. 关于MySQL数据库事务的机制学习总结

    这几天面试多次被问到了数据库事务机制.隔离级别.乐观锁悲观锁类的问题,之前对这些只能说有所了解,有些概念还停留在记忆层面,没有理解,所以回答的不好.后面翻书学习了下,理解了一些东西,在此做一个记录. ...

  9. jsp(3,6,9) EL表达式及JSTL

    1. jsp 1.1jsp是什么 全称: Java Server Pages,java服务器页面.和Servlet一样,是sun公司定义的一种动态网页开发技术.    特点:基于html模版,可以在h ...

  10. mybatis入门详解

    一.mybatis-config.xml文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYP ...