大家好,欢迎来到IT知识分享网。
简介:
1、认识 HAL 层
1.1.1 HAL 层的发展
硬件抽象层大概分为一下 6种HAL:
- 上层软件
- 虚拟驱动,设置管理模块
- 内部通信Server
- 内部以太网
- 内部通信Client
- 用户接入口
定义硬件抽象层接口的代码具有一下5个特点:
- 硬件抽象层具有与硬件的密切相关性
- 硬件抽象层具有与操作系统无关性
- 接口定义的功能应该包含硬件或者系统所需硬件支持的所有功能
- 接口简单明了,太多接口函数会增加软件模拟的复杂性
- 具有可预测的接口设计有利于系统的软、硬件测试和集成。
在Android 源码中,HAL 主要被保存在下面的目录中:
- libhardware_legacy :过去的目录,采取链接库模块观念来架构
- libhardware: 新版的目录,被调整为用HAL stub 观念来架构
- ril: 是Radio 接口层
- msm7k : 和QUAL 平台相关的信息
1.1.2 过去和现在的区别
- HAL_legacy:这是过去HAL的模块,采用共享库形式,在编译时会调用到。由于采用functroncall形式调用,因此可被多个进程使用,但会被mapping到多个进程窄间中,造成浪费,同时需要考虑代码能否安全重入的问题(ThreadSafe)。
- HAL:这是新式的HAL,采用了HALmodule和HAL stub 结合形式。HALstub不是一个共
享库,在编译时上层只拥有访问HALstub的函数指针,并不需要HAL stub-在上层通过HAL
module提供的统一接口获取并操作HAL stub,所以,文件只会被映射到一个进程,而不会存
在重复映射和重入问题。
2.2 分析HAL 层源码
2.2.1 分析 HAL moudle
在 HAL moudle 中主要分为如下3个结构:
- struct hw_module
- struct hw_modulemethods_t
- struct hw_device_t
上述 3 个结构的集成关系 如图 6-4 所示
接下来分析 hardware.c 源码。
函数hw_get_module() 的具体实现代码如下:
代码 /hardware/libhardware/hardware.c
(1) 通过配置变量 循环寻找一个模块
·······
(2)数组variant_keys 在上述函数中,需要用到数组variant_keys,因为HAL_VARIANT_KEYS_COUNT就是数组variant_keys的大小。定义此数组的代码如下:
然后通过此数组,并使用如下代码获取操作权限:
(3) 将路径和文件名保存到 path , 接下来将通过如下代码将路径和文件保存在path 中:
通过上述代码,把 HAL_LIBRARY_PATH/id.*.so 保存到 path 中,其中 就是上面 variant_keys 中各个元素的值。
(4) 载入相应的库,并把他们的 HMI 不保存到 module 中,具体代码如下
return -ENOENT;
(5)打开相应的库并获得 hw_module_t 结构体,具体代码如下:
hmi->dso = handle;
*pHmi = hmi;
2.2.2 分析mokoid 工具
# svn checkout http://mokoid.googlecode.com/svn/trunk/mokoid-read-only
下载 mokoid 工程之后,目录结构如图6-5所示,
需要通过 JNI 来实现 Android 的HAL, JNI 是Java 程序可以调用C/C++ 写的动态链接库,所以HALkeyi shiyong C/C++语言编写,这样效率更高。在Android 下有以下两种访问HAL 的方式:
- Android 的app 直接通过 service 调用.so 格式的JNI : 此方法比较简单高效,但是不正规。
- 经过 Manager 调用 Service : 此方法实现起来比较复杂,但是更符合目前的Android 框架。在此方法中,在进程 LegManager 和 LedService (Java) 中需要通过进程通信的方式实现通信。
在 mokoid 工程中分别实现上述两种方法,下面将详细介绍这两种方法实现原理:
1.直接调用 Service 方法的实现代码
(1)HAL 层的实现代码
文件 hardware/modules/led/led.c 的实现代码如下:
#define LOG_TAG “MokoidLedStub”
#include <hardware/hardware.h>
#include <mokoid/led.h>
/*/
*device = &dev->common; // 将实例化的 led_control_device_t 地址返回给 Jni 层
(2) JNI 层的实例代码
文件 frameworks/base/service/jni/com_mokoid_server_LedService.cpp 的实现代码如下:
// —————————————————————————-
struct led_control_device_t *sLedDevice = NULL;
static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led) {
LOGI(“LedService JNI: mokoid_setOn() is invoked.”);
static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led) {
LOGI(“LedService JNI: mokoid_setOff() is invoked.”);
/ helper APIs */
// —————————————————————————-
// —————————————————————————-
(3) Service 的实现代码
这里的service 属于 Framwork 层,文件 framworks/base/service/java/com/mokoid/server/LedService.java 的实现代码:
package com.mokoid.server;
public final class LedService extends ILedService.Stub {
(4) App 测试程序的实现代码
这里的测试程序属于 APP 层,文件 apps/LedClient/src/com/mokoid/LedClient/LedClient.java 的实现代码如下:
2、通过 manager 调用 Service 的实现代码
(1) Manager 的实现代码
APP 通过 此 Manager 和 Service 实现通信功能,文件 framwork/base/core/java/mokoid/hardware/Ledmanager.java
package mokoid.hardware;
因为 LedService 和 Ledmanager 分别不属于不同的进程,所以在此需要考虑不同进程间的通信问题,此时,在 manager 中可以增加一个aidl 文件来描述通信接口,文件
framworks/base/core/java/mokoid/hardware/ILedService.aidl 的代码实现如下:
package mokoid.hardware;
(2) SystemService 的实现代码
此处的 SystemServer 属于 App 层,文件 apps /LedTest/src/com/mokoid/LedTest/Ledsystem/Server.java 的代码如下:
package com.mokoid.LedTest;
import com.mokoid.server.LedService;
public class LedSystemServer extends Service {
3.App 测试程序
这里的app测试程序属于APP 层,文件 mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedTest.java 的实现代码如下:
public void onClick(View v) {
4、使用HAL 的方法 总结
(1)Native code 通过hw_get_module 调用获取 HAL stub.
hw_get_module (LED_HARDWARE_MODULE_ID,(const hw_module_t )&module)
(2) 通过继承 hw_module_methods_t 的 callback 拉打开设备。
module->methods->open(module,LED_HARDWARE_MODULE_ID,(struct hw_device_t)device);
(3) 通过继承 hw_device_t 的callback (回访) 来控制设备
sLedDevice -> set_on(sLedDevice,led);
sLedDevice-> set_off(sLedDevice,led);
4.1. 编写 HAL stub 的方法
编写HAL stub 的基本流程入下图所示。
1)自定义 HAL 结构体,编写 头文件 led.h 和 hardware/hardware.h 主要代码如下:
struct ledmodulet {
struct hw_module_t common;
}
struct led_control_device_t {
struct hw_device_t common;
int fd ; // 文件描述符 的 LED 装置
int (*set_on) (struct led_control_device_t *dev, int32_t led); // 支持控制的 api
int (*set_off) (struct led_control_device_t *dev,int32_t led);
}
(2) 编写 文件 led.c 实现 HAL stub 注册功能
(3)设置 led_module_methods 继承于 hw_module_methods_t,并实现对 open() 方法的回访,
struct hw_module_methods_t led_module_methods = {
open : led_device_open
};
(4) 使用 HAL_MODULE_INFO_SYM 实例,led_module_t, 注意 这个名称不可修改,
const struct led_module_t HAL_MODULE_INFO_SYM = {
common : {
tag : HARDWARE_MODULE_TAG,
version_major:1,
version_minor:0,
id:LED_HARDWARE_MODULE_ID,
name:”Sample LED Stub”,
author: “The Mokoid Open Source Project”,
methods: &led_module_methods,
}
// 支持 api
};
(5) open() 是一个必须实现的回调 API ,用于负责 申请 结构体空间并填充信息,还可以注册具体操作API 接口, 并打开 Linux 驱动。但是系因为存在多重继承关系,所以只需要对结构体hw_device_t 对象申请空间即可。
*device = &dev->common;
// 初始化硬件接口
dev->fd = open(LED_DEVICE,o_RDONLY);
if (dev->fd < 0 ) {
return -1;
}
led_off(dev,LED_C608);
led_off(dev,LED_C609);
(6) 填充具体 API 操作,具体代码如下:
int led_on (struct led_control_device_t *dev,int32_t led) {
int fd;
LOGI(“LED Stub: set %d on.”,led);
fd = dev->fd;
switch(led) {
case LED_C608:
ioctl(fd,1,&led);
break;
case LED_C609:
ioctl(fd,1,&led)
break;
default:
return -1;
}
return 0;
}
int led_off (struct led_control_device_t *dev,int32_t led) {
int fd;
LOGI(”LED Stub : set %d off.”,led);
fd = dev-> fd;
switch(led) {
case LED_C608:
ioctl(fd,2,&led);
break;
case LED_C609:
ioctl(fd,2,&led);
break;
default:
return -1;
}
return 0;
}
文章摘自:
《Android 底层接口和驱动开发技术详解》
相关资料下载跳转
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/123035.html