一、概述

本文希望通过分析台湾的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实例解析

    原文网址:http://www.embedu.org/Column/Column339.htm 作者:刘老师,华清远见嵌入式学院讲师. 一.概述 本文希望通过分析台湾的Jollen的mokoid 工程 ...

  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. flask url_for()和redirect的区别

    一. 两者用来重定向的时候,被操作的对象不同. redirect直接是url,就是app.route的路径参数. url_for()是对函数进行操作. from flask import Flask, ...

  2. python re模块详解

    re模块 re模块使用python拥有全部的正则表达式功能 1 2 3 4 re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法)  re.M(MULTILINE):(多行模式,改变 ...

  3. [python][django学习篇][10]再次修改博客首页模板

    目前我们看到的只是模板中预先填充的一些数据,我们得让它显示从数据库中获取的文章数据.下面来稍微改造一下模板: 删除所有article标签,然后添加以下内容,将从数据库读取到的内容填充到模板变量{{ p ...

  4. Unity开发VR——Oculus Rif_将Oculus接入Unity

    该文档基于 Unity2018.3.12f1 1. 搭建简单场景 2. 设置,选择 Edit - Project Setting(若已经勾选,就去掉在勾选一次) 完成该步骤之后,可以带上Oculus头 ...

  5. 目前问题:plupload上传带参数到后台

    目前问题:plupload上传带参数到后台,迟迟没有解决!!! 昨晚到23点多终于完成了! 直接上代码! var uploader = new plupload.Uploader({ //实例化一个p ...

  6. 【bzoj1531】[POI2005]Bank notes 多重背包dp

    题目描述 Byteotian Bit Bank (BBB) 拥有一套先进的货币系统,这个系统一共有n种面值的硬币,面值分别为b1, b2,..., bn. 但是每种硬币有数量限制,现在我们想要凑出面值 ...

  7. WebGIS的开发方式

    (转)摘抄自<基于WebGIS的校友资源管理系统的设计与实现>_陈刚

  8. [HEOI2016/TJOI2016][bzoj4555] 求和 [斯特林数+NTT]

    题面 传送门 思路 首先,我们发现这个式子中大部分的项都和$j$有关(尤其是后面的$2^j\ast j!$),所以我们更换一下枚举方式,把这道题的枚举方式变成先$j$再$i$ $f(n)=\sum_{ ...

  9. [HNOI2011][bzoj 2329] 括号修复 [splay+前缀和]

    题面: http://www.lydsy.com/JudgeOnline/problem.php?id=2329 思路: 显然,操作4中输出补全的最小费用是关键 这决定了我们不可能在splay上只维护 ...

  10. jQuery 之 验证表单

    简单的东西重复做,做多了之后,才能说熟能生巧. 做好一个精美的页面,固然是好,但是,一个页面除了写好之外,我们更需要的是将其功能完善.比如表单的验证,这只是众多工作之一.然后本次就以jQuery的va ...