原文网址:http://www.embedu.org/Column/Column339.htm

作者:刘老师,华清远见嵌入式学院讲师。

一、概述

本文希望通过分析台湾的Jollen的mokoid 工程代码,和在s5pc100平台上实现过程种遇到的问题,解析Andorid HAL的开发方法。

二、HAL介绍

现有HAL架构由Patrick Brady (Google) 在2008 Google I/O演讲中提出的,如下图。

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. 针对某些硬件,An有一些特殊的需求。

三、HAL内容

1、HAL 主要的储存于以下目录:

(注意:HAL在其它目录下也可以正常编译)
       ● libhardware_legacy/ - 旧的架构、采取链接库模块的观念进行
       ● libhardware/ - 新架构、调整为 HAL stub 的观念
       ● ril/ - Radio Interface Layer 
       ● msm7k QUAL平台相关

主要包含以下一些模块:Gps、Vibrator、Wifi、Copybit、Audio、Camera、Lights、Ril、Overlay等。

2、两种 HAL 架构比较

目前存在两种HAL架构,位于libhardware_legacy目录下的“旧HAL架构”和位于libhardware目录下的“新HAL架构”。两种框架如下图所示。

图3.1 旧HAL架构 图3.2 新HAL架构

libhardware_legacy 是将 *.so 文件当作shared library来使用,在runtime(JNI 部份)以 direct function call 使用 HAL module。通过直接函数调用的方式,来操作驱动程序。当然,应用程序也可以不需要通过 JNI 的方式进行,直接加载 *.so (dlopen)的做法调用*.so 里的符号(symbol)也是一种方式。总而言之是没有经过封装,上层可以直接操作硬件。

现在的 libhardware 架构,就有stub的味道了。HAL stub 是一种代理人(proxy)的概念,stub 虽然仍是以 *.so檔的形式存在,但HAL已经将 *.so 档隐藏起来了。Stub 向 HAL提供操作函数(operations),而 runtime 则是向 HAL 取得特定模块(stub)的 operations,再 callback 这些操作函数。这种以 indirect function call 的架构,让HAL stub 变成是一种包含关系,即 HAL 里包含了许许多多的 stub(代理人)。Runtime 只要说明类型,即 module ID,就可以取得操作函数。对于目前的HAL,可以认为Android定义了HAL层结构框架,通过几个接口访问硬件从而统一了调用方式。

下面结合实例来分析HAL编程方法。

四、mokoid 工程代码下载与结构分析

1、mokid项目概述

modkoid工程提供了一个LedTest示例程序,是台湾的Jollen用于培训的。对于理解android层次结构、Hal编程方法都非常有意义。

2、下载方法

#svn checkout http://mokoid.googlecode.com/svn/trunk/mokoid-read-only

3、结构分析



Android的HAL的实现需要通过JNI(Java Native Interface),JNI简单来说就是java程序可以调用C/C++写的动态链接库,这样的话,HAL可以使用C/C++语言编写,效率更高。在Android下访问HAL大致有以下两种方式:

(1)Android的app可以直接通过service调用.so格式的jni

(2)经过Manager调用service

上面两种方法应该说是各有优缺点,第一种方法简单高效,但不正规。第二种方法实现起来比较复杂,但更符合目前的Android框架。第二种方法中,LegManager和LedService(java)在两个进程中,需要通过进程通讯的方式来通讯。

mokoid工程中实现了上述两种方法。下面将详细介绍这两种方法的实现原理。

4、第一种方法:直接调用service方法的实现过程

下面分析第一种方法中,各层的关键代码。

(1)HAL层

一般来说HAL moudle需要涉及的是三个关键结构体:
        struct hw_module_t;
        struct hw_module_methods_t;
        struct hw_device_t;

下面结合代码说明这3个结构的用法。部分代码经过修改,后面的章节会给出修改的原因。

文件:mokoid-read-only/hardware/modules/include/mokoid/led.h
        /***************************************************************************/
        struct led_module_t {
                struct hw_module_t common;
        };
        //HAL 规定不能直接使用hw_module_t结构,因此需要做这么一个继承。
        struct led_control_device_t { 
        //自定义的一个针对Led控制的结构,包含hw_device_t和支持的API操作
                struct hw_device_t common;
                /* attributes */
                int fd; //可用于具体的设备描述符
                /* supporting control APIs go here */
                int (*set_on)(struct led_control_device_t *dev, int32_t led);
                int (*set_off)(struct led_control_device_t *dev, int32_t led);
        };
        #define LED_HARDWARE_MODULE_ID "led" 
        //定义一个MODULE_ID,HAL层可以根据这个ID找到我们这个HAL stub

文件:mokoid-read-only/hardware/modules/led/led.c



(2)JNI层

文件:mokoid-read-only/frameworks/base/service/jni/com_mokoid_server_LedService.cpp




(3)service (属于Framework层)

(4)APP 测试程序 (属于APP层)

文件:apps/LedClient/src/com/mokoid/LedClient/LedClient.java

5、第二种方法:经过Manager调用service

HAL、JNI两层和第一种方法一样,所以后面只分析其他的层次。

(1)Manager (属于Framework层)

APP通过这个Manager和service通讯。

文件:mokoid-read-only /frameworks/base/core/java/mokoid/hardware/LedManager.java


因为LedService和LedManager在不同的进程,所以要考虑到进程通讯的问题。Manager通过增加一个aidl文件来描述通讯接口

文件:mokoid-read-only/frameworks/base/core/java/mokoid/hardware/ILedService.aidl

(2)SystemServer (属于APP层)

文件:mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedSystemServer.java

(3)APP 测试程序(属于APP层)

文件:mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedTest.java


五、实验中需要注意的问题

将下载后的源码放到你的android源码目录下,然后编译系统。本实验用的android版本为2.1。实验的过程中大致出现过以下几个问题:

1、目标系统中没有生成LedClient.apk或LedTest.apk应用程序

编译完成后,没有在目标系统的system/app/目录下找到LedClient.apk或LedTest应用程序。只有通过单独编译LedClient或LedTest才能在目标目录中生成。方法如下:

#mmm mokoid-read-only/apps/LedTest/

检查原因后发现mokoid-read-only/apps/LedTest/Android.mk

LOCAL_MODULES_TAGS :=user

而我们的s5pc100系统在配置时tapas时选择的是eng,所以没有装载到目标系统。

所以修改LedTest和LedClient的Android.mk

LOCAL_MODULES_TAGS :=user eng

再次编译即可自动装载到目标系统/system/app/目录下。

2、启动后没有图标,找不到应用程序

目标系统启动后找不到两个应用程序的图标。仔细阅读logcat输出的信息发现:

E/PackageManager( 2717): Package com.mokoid.LedClient requires unavailable shared library com.mokoid.server; failing!

原因是找不到 com.mokoid.server。检查mokoid-read-only/frameworks/base/Android.mk发现系统将LedManager和LedService编译成 mokoid.jar库文件。为了让应用程序可以访问到这个库,需要通过com.mokoid.server.xml 来设定其对应关系。解决方法:拷贝com.mokoid.server.xml到目标系统的system/etc/permissions/目录下。

此时两个应用的程序的图标都正常出现了。

3、提示找不到 JNI_OnLoad

按照以前的实验加入下列代码:


4、需要针对你的目标平台修改HAL的Makefile

修改mokoid-read-only/hardware/modules/led/Android.mk

LOCAL_MODULE := led.default

5、在eclipse中编译不了LedSystemServer.java

原因是程序中要用到ServiceManager.addService,这需要系统权限。

解决方法可以把应用程序放入Android源码中编译,并确保以下两点:

(1)在应用程序的AndroidManifest.xml中的manifest节点中加入android:sharedUserId="android.uid.system"这个属性。
        (2)修改Android 加入LOCAL_CERTIFICATE := platform.

当然:mokoid工程源码中已经做了这些。

【转】Android HAL实例解析的更多相关文章

  1. Android HAL实例解析

    一.概述 本文希望通过分析台湾的Jollen的mokoid 工程代码,和在s5pc100平台上实现过程种遇到的问题,解析Andorid HAL的开发方法. 二.HAL介绍 现有HAL架构由Patric ...

  2. Android AIDL实例解析

    AIDL这项技术在我们的开发中一般来说并不是很常用,虽然自己也使用新浪微博的SSO登录,其原理就是使用AIDL,但是自己一直没有动手完整的写过AIDL的例子,所以就有了这篇简单的文章. AIDL(An ...

  3. Android实例-Delphi开发蓝牙官方实例解析(XE10+小米2+小米5)

    相关资料:1.http://blog.csdn.net/laorenshen/article/details/411498032.http://www.cnblogs.com/findumars/p/ ...

  4. Android开发之IPC进程间通信-AIDL介绍及实例解析

    一.IPC进程间通信 IPC是进程间通信方法的统称,Linux IPC包括以下方法,Android的进程间通信主要采用是哪些方法呢? 1. 管道(Pipe)及有名管道(named pipe):管道可用 ...

  5. android HAL 教程(含实例)

    http://www.cnblogs.com/armlinux/archive/2012/01/14/2396768.html Android Hal 分析                       ...

  6. Android Service完全解析,关于服务你所需知道的一切(上)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11952435 相信大多数朋友对Service这个名词都不会陌生,没错,一个老练的A ...

  7. [转] Android Volley完全解析(一),初识Volley的基本用法

    版权声明:本文出自郭霖的博客,转载必须注明出处.   目录(?)[-] Volley简介 下载Volley StringRequest的用法 JsonRequest的用法   转载请注明出处:http ...

  8. Android IntentService完全解析 当Service遇到Handler

    一 概述 大家都清楚,在Android的开发中,凡是遇到耗时的操作尽可能的会交给Service去做,比如我们上传多张图,上传的过程用户可能将应用置于后台,然后干别的去了,我们的Activity就很可能 ...

  9. Android Volley完全解析

    1. Volley简介 我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据.Android系统中主要提供了两种方式来进行H ...

随机推荐

  1. eclipse,tomcat部署web项目,以及本地文件访问

    1.直接把项目复制到Tomcat安装目录的webapps目录中,这是最简单的一种Tomcat项目部署的方法,也是初学者最常用的方法. 2.在tomcat安装目录中有一个conf文件夹,打开此文件夹,其 ...

  2. bzoj3174 [Tjoi2013]拯救小矮人

    Description 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口.对于每一个小矮人, ...

  3. 关于js对象引用的小例子

    看完下面的代码,相信对js对象引用又有了新的认识,直接上代码: // split()把字符串分割成字符串数组 // reverse() 会改变数组本身,**并返回原数组的引用**.!!!! var a ...

  4. Android 百度地图API(01)_开发环境 HelloBaiduMap

    转载于:http://blog.csdn.net/lmj623565791/article/details/37729091 转载于:http://blog.csdn.net/crazy1235/ar ...

  5. Beyond Compare 忽略两个文件内容的顺序比较文件内容(xjl456852原创)

    有时两个文件内容的顺序是不固定的,对比时需要忽略文件顺序进行对比. 可以这样设置: 点击菜单下面工具栏按钮: 点击Format旁的三角,选择Sorted,就会按文件的顺序排序比较.忽略了文件内容顺序的 ...

  6. (转载)XML Tutorial for iOS: How To Read and Write XML Documents with GDataXML

    In my recent post on How To Choose the Best XML Parser for Your iPhone Project, Saliom from the comm ...

  7. HOG(方向梯度直方图)

    结合这周看的论文,我对这周研究的Histogram of oriented gradients(HOG)谈谈自己的理解: HOG descriptors 是应用在计算机视觉和图像处理领域,用于目标检測 ...

  8. ARM指令集——条件执行、内存操作指令、跳转指令

    ARM 汇编指令条件执行 在ARM模式下,任何一条数据处理指令可以选择是否根据操作的结果来更新CPSR寄存器中的ALU状态标志位.在数据处理指令中使用S后缀来实现该功能. 不要在CMP,CMN,TST ...

  9. 在WIN7系统下用Quartus ii 11.1 NIOS II 11.1 有时候会出现Nios II 的Run as hardware 中报错:Downloading ELF Process failed

    nios工程在编译通过后RUN的过程中出现Error Running Nios II Project: ‘Downloading ELF Process failed’问题原因: 1.nios2 cp ...

  10. AngularJs练习Demo4

    @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport&quo ...