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

RK3588 Android12 自定义HAL服务到上层app 背景:荣品开发板RD-rk3588 sdk不支持编译app源码,所以只能将jar包导入到上层app中实现。再导入到AndroidStudio项目中,复制jar包到libs目录下。右键该jar包,选择add as library。编译后烧入开发板,查看日志。 阅读详情

参考文献:

http://blog.youkuaiyun.com/luoshengyang/article/details/6573809

http://blog.youkuaiyun.com/hongtao_liu/article/details/6060734

建议阅读本文时先浏览以上两篇文章,本文是对上两篇文章在HAL对上层接口话题的一个总结.

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.   
  17. #ifndef ANDROID_INCLUDE_HARDWARE_HARDWARE_H  
  18. #define ANDROID_INCLUDE_HARDWARE_HARDWARE_H  
  19.   
  20. #include <stdint.h>   
  21. #include <sys/cdefs.h>   
  22.   
  23. #include <cutils/native_handle.h>  
  24. #include <system/graphics.h>   
  25.   
  26. __BEGIN_DECLS  
  27.   
  28. /* 
  29.  * Value for the hw_module_t.tag field 
  30.  */  
  31.   
  32. #define MAKE_TAG_CONSTANT(A,B,C,D) (((A) << 24) | ((B) << 16) | ((C) << 8) | (D))  
  33.   
  34. #define HARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', 'T')  
  35. #define HARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', 'T')  
  36.   
  37. struct hw_module_t;  
  38. struct hw_module_methods_t;  
  39. struct hw_device_t;  
  40.   
  41. /** 
  42.  * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM 
  43.  * and the fields of this data structure must begin with hw_module_t 
  44.  * followed by module specific information. 
  45.  */  
  46. //每一个硬件模块都每必须有一个名为HAL_MODULE_INFO_SYM的数据结构变量,它的第一个成员的类型必须为hw_module_t  
  47. typedef struct hw_module_t {  
  48.     /** tag must be initialized to HARDWARE_MODULE_TAG */  
  49.     uint32_t tag;  
  50.   
  51.     /** major version number for the module */  
  52.     uint16_t version_major;  
  53.   
  54.     /** minor version number of the module */  
  55.     uint16_t version_minor;  
  56.   
  57.     /** Identifier of module */  
  58.     const char *id;  
  59.   
  60.     /** Name of this module */  
  61.     const char *name;  
  62.   
  63.     /** Author/owner/implementor of the module */  
  64.     const char *author;  
  65.   
  66.     /** Modules methods */  
  67.     //模块方法列表,指向hw_module_methods_t*  
  68.     struct hw_module_methods_t* methods;  
  69.   
  70.     /** module's dso */  
  71.     void* dso;  
  72.   
  73.     /** padding to 128 bytes, reserved for future use */  
  74.     uint32_t reserved[32-7];  
  75.   
  76. } hw_module_t;  
  77.   
  78. typedef struct hw_module_methods_t {                 //硬件模块方法列表的定义,这里只定义了一个open函数  
  79.     /** Open a specific device */  
  80.     int (*open)(const struct hw_module_t* module, const char* id, //注意这个open函数明确指出第三个参数的类型为struct hw_device_t**  
  81.             struct hw_device_t** device);  
  82. } hw_module_methods_t;  
  83.   
  84. /** 
  85.  * Every device data structure must begin with hw_device_t 
  86.  * followed by module specific public methods and attributes. 
  87.  */  
  88. //每一个设备数据结构的第一个成员函数必须是hw_device_t类型,其次才是各个公共方法和属性  
  89. typedef struct hw_device_t {  
  90.     /** tag must be initialized to HARDWARE_DEVICE_TAG */  
  91.     uint32_t tag;  
  92.   
  93.     /** version number for hw_device_t */  
  94.     uint32_t version;  
  95.   
  96.     /** reference to the module this device belongs to */  
  97.     struct hw_module_t* module;  
  98.   
  99.     /** padding reserved for future use */  
  100.     uint32_t reserved[12];  
  101.   
  102.     /** Close this device */  
  103.     int (*close)(struct hw_device_t* device);  
  104.   
  105. } hw_device_t;  
  106.   
  107. /** 
  108.  * Name of the hal_module_info 
  109.  */  
  110. #define HAL_MODULE_INFO_SYM         HMI  
  111.   
  112. /** 
  113.  * Name of the hal_module_info as a string 
  114.  */  
  115. #define HAL_MODULE_INFO_SYM_AS_STR  "HMI"  
  116.   
  117. /** 
  118.  * Get the module info associated with a module by id. 
  119.  * 
  120.  * @return: 0 == success, <0 == error and *module == NULL 
  121.  */  
  122. int hw_get_module(const char *id, const struct hw_module_t **module);  
  123.   
  124. /** 
  125.  * Get the module info associated with a module instance by class 'class_id' 
  126.  * and instance 'inst'. 
  127.  * 
  128.  * Some modules types necessitate multiple instances. For example audio supports 
  129.  * multiple concurrent interfaces and thus 'audio' is the module class 
  130.  * and 'primary' or 'a2dp' are module interfaces. This implies that the files 
  131.  * providing these modules would be named audio.primary.<variant>.so and 
  132.  * audio.a2dp.<variant>.so 
  133.  * 
  134.  * @return: 0 == success, <0 == error and *module == NULL 
  135.  */  
  136. int hw_get_module_by_class(const char *class_id, const char *inst,  
  137.                            const struct hw_module_t **module);  
  138.   
  139. __END_DECLS  
  140.   
  141. #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. /*硬件模块结构体*/  
  5. //见hardware.h中的hw_module_t定义的说明,xxx_module_t的第一个成员必须是hw_module_t类型,其次才是模块的一此相关信息,当然也可以不定义,  
  6. //这里就没有定义模块相关信息   
  7. struct xxx_module_t {  
  8.     struct hw_module_t common;  
  9. };  
  10.   
  11. /*硬件接口结构体*/  
  12. //见hardware.h中的hw_device_t的说明,要求自定义xxx_device_t的第一个成员必须是hw_device_t类型,其次才是其它的一些接口信息.   
  13. struct xxx_device_t {  
  14.     struct hw_device_t common;  
  15.         //以下成员是HAL对上层提供的接口或一些属性  
  16.         int fd;  
  17.     int (*set_val)(struct xxx_device_t* dev, int val);  
  18.     int (*get_val)(struct xxx_device_t* dev, int* val);  
  19. };  
注:特别注意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的类型信息说明.  它是一个宏定义:#define HAL_MODULE_INFO_SYM         HMI
  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.       
  5.     if(!dev) {  
  6.         LOGE("Hello Stub: failed to alloc space");  
  7.         return -EFAULT;  
  8.     }  
  9.   
  10.     memset(dev, 0, sizeof(struct xxx_device_t));  
  11.         //对dev->common的内容赋值,   
  12.         dev->common.tag = HARDWARE_DEVICE_TAG;  
  13.     dev->common.version = 0;  
  14.     dev->common.module = (hw_module_t*)module;  
  15.     dev->common.close = xxx_device_close;  
  16.         //对dev其它成员赋值   
  17.         dev->set_val = xxx_set_val;  
  18.     dev->get_val = xxx_get_val;  
  19.   
  20.     if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {  
  21.         LOGE("Hello Stub: failed to open /dev/hello -- %s.", strerror(errno));  
  22.         free(dev);  
  23.         return -EFAULT;  
  24.     }  
  25.           
  26.         //输出&(dev->common),输出的并不是dev,而是&(dev->common)!(common内不是只包含了一个close接口吗?)  
  27.     *device = &(dev->common);  
  28.     LOGI("Hello Stub: open /dev/hello successfully.");  
  29.   
  30.     return 0;  
  31. }  
经验告诉我们,一般在进行模块初始化的时候,模块的接口函数也会“注册”,上面是模块初始化函数,那么接口注册在哪?于是我们找到*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.   
  6. } 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函数来返回给上层的.

Android应用程序实现调用HAL层接口功能 在上述代码中,我们通过获取传感器管理器(SensorManager)和指定要使用的传感器类型(Sensor.TYPE_ACCELEROMETER),来实现对加速度传感器的访问。首先,我们需要了解HAL层接口是什么。HAL层是Android系统的一部分,它提供了一组抽象的接口,使得不同的硬件设备可以在上层应用程序中以统一的方式进行访问和使用。在开发Android应用程序时,有时候我们需要访问硬件抽象层(Hardware Abstraction Layer,简称HAL)接口,以实现与底层硬件的交互。 阅读详情

相关推荐

Android应用程序调用硬件抽象层(HAL)接口实现功能

通过使用硬件抽象层(HAL)接口,Android应用程序可以与底层硬件进行通信,实现与硬件相关的功能。硬件抽象层(HAL)是Android系统的一部分,它提供了一个标准化的接口,用于访问底层硬件功能。HAL层位于Android系统的最低层,它隐藏了不同硬件设备的具体实现细节,使得应用程序可以通过统一的接口访问硬件功能,而不用考虑硬件的具体实现。这就需要使用HAL接口来实现应用程序与硬件之间的通信。具体的HAL接口调用方法和参数根据硬件设备的不同而异,请参考硬件厂商提供的文档和示例代码进行具体实现。

CodeRoarX的博客 615

Android架构分析之硬件抽象层(HAL)

一、分析HAL module 架构 Android硬件抽象层有三个核心数据结构,分别是hw_module_t , hw_module_methods_t, hw_device_t。定义在hardware/libhardware/include/hardware/hardware.h文件中: 1、hw_module_t: typedef struct hw_module_t { /*...

空中的晨曦博客 2024

电荷灵敏前置放大器噪声优化策略:从理论到实践

本文深入探讨了电荷灵敏前置放大器的噪声优化策略,从理论分析到实践应用。文章系统解析了并联电流噪声与串联电压噪声的来源,并引入噪声等效原理与“冷电容”模型作为统一分析工具。通过详解a、b、c三类噪声的频谱特性,为实战优化提供了清晰指导。核心策略包括选用高跨导、低漏电流FET,优化静态工作点,采用共源-共基结构,精心设计反馈网络,以及实施严格的PCB布局、屏蔽与接地,旨在全面提升微弱信号检测系统的信噪比。

weixin_29292431的博客 466

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

参考文献: http://blog.youkuaiyun.com/luoshengyang/article/details/6573809 http://blog.youkuaiyun.com/hongtao_liu/article/details/6060734 建议阅读本文时先浏览以上两篇文章,本文是对上两篇文章在HAL对上层接口话题的一个总结. 1 什么是HAL HAL的全称是Hardware Abstr...

管子(zero)的杂乱空间 979

QoderWake 与 Qoder 工具生态详解

Qoder CLIQoder SDKQoderWake谁在用你(开发者)你的程序你的数字员工谁在跑你的终端会话你的应用进程Daemon 后台进程什么时候跑你启动时你的代码调用时7×24 持续运行怎么触发键盘输入函数调用定时/事件/API/IM有记忆吗会话级 + 文件无多层持久记忆能协作吗Subagent多 Waker + IM 群组核心价值编码效率集成灵活性自主生产力一句话总结。

驽马不舍 945

Win11家庭版如何让Win+R运行CMD默认管理员权限?3种方法实测有效

本文针对Win11家庭版用户,实测了三种让Win+R运行CMD默认获取管理员权限的有效方法。通过分析UAC机制与家庭版功能限制,详细介绍了注册表编辑、快捷方式创建与任务计划程序三种方案的原理、步骤与风险对比,帮助用户根据安全与效率需求选择最佳方案,实现一键高效管理。

sat99的博客 1266

Android中HAL如何向上层提供接口总结-hw device t

Android中HAL如何向上层提供接口总结-hw device t

hddghhfd的博客 607

字符集的选择

字符集的选择 一:背景介绍 DICOM特定字符集(0008,0005) 此标签获得不同的值就代表使用不同的语言进行解码。 以下为多家CT厂商的(0008,0005)取值: 字符集: unicode是字符集,ASCII、GB2312、GBK、GB18030既是字符集也是编码方式,UTF-8只是编码方式。 二:中文字符集介绍 世界通用字符集——UTF 中文字符集——GB2312、GBK、GB18030 字符集的详细介绍 一:UTF-8 程序是把一个字节一个字节的来读取,然后再根据字节中开头的bit

qq_41972968的博客 1518

android 7 hal,Android中HAL如何向上层提供接口总结-hw_device_t

参考文献:建议阅读本文时先浏览以上两篇文章,本文是对上两篇文章在HAL对上层接口话题的一个总结.1 什么是HALHAL的全称是Hardware Abstraction Layer,即硬件抽象层.其架构图如下:Android的HAL是为了保护一些硬件提供商的知识产权而提出的,是为了避开linux的GPL束缚。思路是把控制硬件的动作都放到了AndroidHAL中,而linux driver仅仅完成一些...

weixin_36401013的博客 581

芒果YOLO11改进137:卷积AKConv篇,即插即用,具有任意采样形状和任意数量的参数的卷积内核

卷积AKConv篇,即插即用,具有任意采样形状和任意数量的参数的卷积内核

包括YOLOv5、YOLOv7、YOLOv8等模型改进 295

化工过程设计软件:Aspen Plus二次开发_(2).二次开发概述

假设我们需要创建一个自定义的换热器模型,该模型能够计算两个物流之间的热交换量,并根据传热系数和换热面积进行调整。ACM 模型代码示例!自定义换热器模型!参数:传热系数 U (W/m^2·K)!换热面积 A (m^2)!热物流 T_hot_in (K), T_hot_out (K), F_hot (kmol/h)!冷物流 T_cold_in (K), T_cold_out (K), F_cold (kmol/h)!模型输入!U - 传热系数!A - 换热面积!

kkchenjj的博客 367

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

点击打开链接

fuyongming的专栏 792

ORB-SLAM3编程实践指南

它基于特征点的立体视觉和视觉惯性里程计技术,能够在没有先验知识的情况下,从单目、双目或RGB-D摄像头的输入中实时构建稠密三维地图,并实现相机的定位。通过正确配置环境、准备数据集和运行ORB-SLAM3,您可以实现高效的视觉SLAM系统,并获取相机在三维空间中的位姿。其中,[path_to_vocabulary]是ORB-SLAM3的词汇文件路径,[path_to_settings]是相机参数配置文件路径,[path_to_sequence]是输入图像的路径。运行ORB-SLAM3。

ByteNinja的博客 551

HAL 如何向上层提供接口--hw_device_t

参考文献: http://blog.youkuaiyun.com/luoshengyang/article/details/6573809 http://blog.youkuaiyun.com/hongtao_liu/article/details/6060734 建议阅读本文时先浏览以上两篇文章,本文是对上两篇文章在HAL对上层接口话题的一个总结. 1 什么是HAL HAL的全称是Hardware A

2323

栅格数据做相关性分析前的预处理(批量定义投影、栅格投影、重采样)

最近在做两个栅格数据的相关性分析,这个最主要的是两个栅格数的行列号是一致的(也就是说坐标系、分辨率一致),那么标准的栅格数据的分辨率是以米的形式存在的,但是有一些栅格数据是以度为单位存在的,所以在做分析前,一定要先把其转换为米,否则在重采样的时候就会出错。(相关文章——栅格数据以度为单位变为以米为单位的简单做法)当然,在变其分辨率的单位前,一定要将其坐标系转换为一致。所以就有以下的步骤(如何将两个栅格数据的坐标系、分辨率的单位和分辨率一致) 1.首先,要看两个栅格数据的坐标系是否一致,如果不一致,要先统一到

qq_41828818的博客 8350

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

上一篇: Kobject结构体分析
下一篇: android中hw_get_module函数分析
计算机与认知
博客等级 码龄14年 31粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值