首先介绍一下HAL, Android的HAL是为了保护一些硬件提供商的知识产权而提出的,是为了避开linux的GPL束缚。思路是把控制硬件的动作都放到了Android HAL中,而linux driver仅仅完成一些简单的数据交互作用,甚至把硬件寄存器空间直接映射到user space。而Android是基于Aparch的license,因此硬件厂商可以只提供二进制代码,所以说Android只是一个开放的平台,并不是一个开源的平台。
总结下来,Android HAL存在的原因主要有:
1. 并不是所有的硬件设备都有标准的linux kernel的接口
2. KERNEL DRIVER涉及到GPL的版权。某些设备制造商并不原因公开硬件驱动,所以才去用HAL方 式绕过GPL。
3. 针对某些硬件,An有一些特殊的需求
如果我们的App需要调用硬件的功能, 一般需经过如下步骤
ConsumerIrService(CIRS)是Android中的一个简单的系统服务, 通过这个服务, 我们不仅可以了解ConsumerIrManager是如何运行的,也可以举一反三学习Android系统服务的实现框架.
CIRS的实现分为初始化, 和发送红外信号两个方面; 他们的时序图如下
CIRS涉及的文件
Framework层-Java
android.hardware.ConsumerIrManager.java
com.android.serve.ConsumerIrService.java
Framework层-C++
frameworks\base\services\core\jni\com_android_server_ConsumerIrService.cpp
HAL层:
hardware\libhardware\include\hardware\consumerir.h
hardware\libhardware\modules\consumerir\consumerir.c
一 首先分析一下初始化流程
1.SystemServer注册CIRS
作为一个Android的系统服务, CIRS在Android启动的时候就开始启动了.
在Android启动, Zygote初始化的时候会启动 SystemServer,
在SystemServer.java中就会初始化并注册CIRS
2.ConsumerIrService 的初始化
可以看到, CIRS通过halOpen()函数,打开了红外的硬件设备, 并一直持有这个设备对象的指针 (mNaticeHal),
这就将来就可以通过这个指针, 调用Hal层的红外设备对象, 发送红外信号了
3.com_android_server_ConsumerIrService.cpp中的halOpen函数, 打开红外设备
其实都是Android Hal 层提供的接口
a.使用hw_get_module来拿到红外设备,
b.通过module->methods->open 来打开这个红外设备
CONSUMERIR_HARDWARE_MODULE_ID 这个宏在consumerir.h中定义, 用来标识红外模块,
4. consumerir.h , consumerir.c 这是IR模块的Hal模块代码, 将来会和真正的硬件驱动打交道
定义了 CONSUMERIR_HARDWARE_MODULE_ID:
#define CONSUMERIR_HARDWARE_MODULE_ID "consumerir"
这是在 consumerir.c 中向Hal层注册(声明)的, 这样就可以使用hw_get_module来拿到红外设备,
在 consumerir.c中也定义了 module的open函数指针指向consumerir_open函数:
这样就可以通过module->methods->open 调用到consumerir_open函数了
5.consumerir_open函数定义了外部的模块调用consumerir模块的api, 当然这也是使用了hal框架的模板
这里就有发送红外的函数注册, 这样外界通过使用 dev->transmit函数就可以发送红外信号了
这里谷歌github的代码只是提供了一个demo, 将来需要在这里打开驱动文件, 下面有一个打开驱动文件的实例代码:
参考. http://blog.csdn.net/luoshengyang/article/details/6573809
这个过程很像是Java的基类调用子类, 子类函数自己去实现 .
这样就通过函数指针在C中实现了类似Java的函数实现功能.
综上就是CIRS的初始化
二 发送红外信号的流程
上面初始化进行完毕,下面发送红外就不在话下了:
1.在App启动的时候会初始化一个Context, 这时候就会初始化一个ConsumerIrManager也就是CIRS的在App端的Proxy出来:
2.在后面,发送红外的时候, 就可以拿到CIRMgr来发送红外了, 当然不过是通过AIDL调用到CIRS的transmit函数
3.在CIRS中, 处理之后调用到haltransmit函数, 注意mNativeHal就是红外的hal模块对象的指针, 他初始化后一直在内存中.
Java不能直接使用调用hal, 所以转发到 CIRS的C++层, 然后调用device进行发送红外
4.前面我们把transmit指针指向了consumerir_transmit, 于是调用consumerir_transmit开始真正的红外发送了:
同样参考一下 人家发送halloword的代码
至此, 发送流程就完成了.
三 总结
和Android App的Framework一样. Android 底层的Hal其实也是提供了接口给厂商, 这样厂商就可以
编写自己的Hal模块了!
总结下来,Android HAL存在的原因主要有:
1. 并不是所有的硬件设备都有标准的linux kernel的接口
2. KERNEL DRIVER涉及到GPL的版权。某些设备制造商并不原因公开硬件驱动,所以才去用HAL方 式绕过GPL。
3. 针对某些硬件,An有一些特殊的需求
如果我们的App需要调用硬件的功能, 一般需经过如下步骤
![](http://a1.eoeandroid.com/attachment/forum/201502/06/142815jzt8vvpkn0kkvrlu.png)
ConsumerIrService(CIRS)是Android中的一个简单的系统服务, 通过这个服务, 我们不仅可以了解ConsumerIrManager是如何运行的,也可以举一反三学习Android系统服务的实现框架.
CIRS的实现分为初始化, 和发送红外信号两个方面; 他们的时序图如下
![](http://a1.eoeandroid.com/attachment/forum/201502/06/142814t4spr4cy2tsk5sz7.png)
CIRS涉及的文件
Framework层-Java
android.hardware.ConsumerIrManager.java
com.android.serve.ConsumerIrService.java
Framework层-C++
frameworks\base\services\core\jni\com_android_server_ConsumerIrService.cpp
HAL层:
hardware\libhardware\include\hardware\consumerir.h
hardware\libhardware\modules\consumerir\consumerir.c
一 首先分析一下初始化流程
1.SystemServer注册CIRS
作为一个Android的系统服务, CIRS在Android启动的时候就开始启动了.
在Android启动, Zygote初始化的时候会启动 SystemServer,
在SystemServer.java中就会初始化并注册CIRS
![](http://a1.eoeandroid.com/attachment/forum/201502/06/142814shuvig8mtisuih4i.png)
2.ConsumerIrService 的初始化
![](http://a1.eoeandroid.com/attachment/forum/201502/06/142814ul4e8047c8hse8z8.png)
可以看到, CIRS通过halOpen()函数,打开了红外的硬件设备, 并一直持有这个设备对象的指针 (mNaticeHal),
这就将来就可以通过这个指针, 调用Hal层的红外设备对象, 发送红外信号了
3.com_android_server_ConsumerIrService.cpp中的halOpen函数, 打开红外设备
其实都是Android Hal 层提供的接口
a.使用hw_get_module来拿到红外设备,
b.通过module->methods->open 来打开这个红外设备
CONSUMERIR_HARDWARE_MODULE_ID 这个宏在consumerir.h中定义, 用来标识红外模块,
![](http://a1.eoeandroid.com/attachment/forum/201502/06/142814pyotthi6f0ll3l8u.png)
4. consumerir.h , consumerir.c 这是IR模块的Hal模块代码, 将来会和真正的硬件驱动打交道
定义了 CONSUMERIR_HARDWARE_MODULE_ID:
#define CONSUMERIR_HARDWARE_MODULE_ID "consumerir"
这是在 consumerir.c 中向Hal层注册(声明)的, 这样就可以使用hw_get_module来拿到红外设备,
![](http://a1.eoeandroid.com/attachment/forum/201502/06/142813jxcd2xr151n0gn0x.png)
在 consumerir.c中也定义了 module的open函数指针指向consumerir_open函数:
这样就可以通过module->methods->open 调用到consumerir_open函数了
![](http://a1.eoeandroid.com/attachment/forum/201502/06/142813w9ua9h91kak8kkuk.png)
5.consumerir_open函数定义了外部的模块调用consumerir模块的api, 当然这也是使用了hal框架的模板
这里就有发送红外的函数注册, 这样外界通过使用 dev->transmit函数就可以发送红外信号了
![](http://a1.eoeandroid.com/attachment/forum/201502/06/142813i5y9z4zo4otowfok.png)
这里谷歌github的代码只是提供了一个demo, 将来需要在这里打开驱动文件, 下面有一个打开驱动文件的实例代码:
-
static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) { - struct hello_device_t* dev;dev = (struct hello_device_t*)malloc(sizeof(struct hello_device_t));
- if(!dev) {
- LOGE("Hello Stub: failed to alloc space");
- return -EFAULT;
- }
- memset(dev, 0, sizeof(struct hello_device_t));
- dev->common.tag = HARDWARE_DEVICE_TAG;
- dev->common.version = 0;
- dev->common.module = (hw_module_t*)module;
- dev->common.close = hello_device_close;
- dev->set_val = hello_set_val;dev->get_val = hello_get_val;
- if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {
- LOGE("Hello Stub: failed to open /dev/hello -- %s.", strerror(errno));free(dev);
- return -EFAULT;
- }
- *device = &(dev->common);
- LOGI("Hello Stub: open /dev/hello successfully.");
- return 0;
- }
参考. http://blog.csdn.net/luoshengyang/article/details/6573809
这个过程很像是Java的基类调用子类, 子类函数自己去实现 .
这样就通过函数指针在C中实现了类似Java的函数实现功能.
![](http://a1.eoeandroid.com/attachment/forum/201502/06/142814fzeq4m0pe80knzee.png)
综上就是CIRS的初始化
二 发送红外信号的流程
上面初始化进行完毕,下面发送红外就不在话下了:
1.在App启动的时候会初始化一个Context, 这时候就会初始化一个ConsumerIrManager也就是CIRS的在App端的Proxy出来:
![](http://a1.eoeandroid.com/attachment/forum/201502/06/143207kunpx66eszezu2lw.png)
2.在后面,发送红外的时候, 就可以拿到CIRMgr来发送红外了, 当然不过是通过AIDL调用到CIRS的transmit函数
![](http://a1.eoeandroid.com/attachment/forum/201502/06/143221h4hwfxehwxwqqzoa.png)
3.在CIRS中, 处理之后调用到haltransmit函数, 注意mNativeHal就是红外的hal模块对象的指针, 他初始化后一直在内存中.
![](http://a1.eoeandroid.com/attachment/forum/201502/06/143233px944aldnqz95o1m.png)
Java不能直接使用调用hal, 所以转发到 CIRS的C++层, 然后调用device进行发送红外
![](http://a1.eoeandroid.com/attachment/forum/201502/06/143258qzh5xqeh115d5rze.png)
4.前面我们把transmit指针指向了consumerir_transmit, 于是调用consumerir_transmit开始真正的红外发送了:
![](http://a1.eoeandroid.com/attachment/forum/201502/06/143314k7rl6lzrqpggl6zb.png)
同样参考一下 人家发送halloword的代码
- static int hello_device_close(struct hw_device_t* device) {
- struct hello_device_t* hello_device = (struct hello_device_t*)device;
- if(hello_device) {
- close(hello_device->fd);
- free(hello_device);
- }
- return 0;
- }
- static int hello_set_val(struct hello_device_t* dev, int val) {
- LOGI("Hello Stub: set value %d to device.", val);
- write(dev->fd, &val, sizeof(val));
- return 0;
- }
- static int hello_get_val(struct hello_device_t* dev, int* val) {
- if(!val) {
- LOGE("Hello Stub: error val pointer");
- return -EFAULT;
- }
- read(dev->fd, val, sizeof(*val));
- LOGI("Hello Stub: get value %d from device", *val);
- return 0;
- }
至此, 发送流程就完成了.
三 总结
和Android App的Framework一样. Android 底层的Hal其实也是提供了接口给厂商, 这样厂商就可以
编写自己的Hal模块了!