转一篇eoe论坛上sfshine大神的文章--AndroidHal底层! ConsumerIrService分析

首先介绍一下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, 将来需要在这里打开驱动文件, 下面有一个打开驱动文件的实例代码:


  • 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的函数实现功能.
 

综上就是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的代码

  • 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模块了!
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值