Android HAL实例解析

一、概述
    本文希望通过分析台湾的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在其它目录下也可以正常编译)
l  libhardware_legacy/ - 旧的架构、采取链接库模块的观念进行
l  libhardware/ - 新架构、调整为 HAL stub 的观念
l  ril/ - Radio Interface Layer
l  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.mk  
|-- apps      //两种应用测试方法
|   |-- Android.mk
|   |-- LedClient    //直接调用service来调用jni
|   |   |-- AndroidManifest.xml
|   |   |-- Android.mk
|   |   `-- src
|   |       `-- com
|   |           `-- mokoid
|   |               `-- LedClient
|   |                   `-- LedClient.java     //第1种方式应用程序实现代码
|   `-- LedTest        //通过manager来调用jni
|       |-- AndroidManifest.xml
|       |-- Android.mk
|       `-- src
|           `-- com
|               `-- mokoid
|                   `-- LedTest
|                       |-- LedSystemServer.java  //开启了一个后台service,下文会有解释
|                       `-- LedTest.java    //第2种方式应用程序实现代码
|-- dma6410xp   //这个目录可以不要
|   |-- AndroidBoard.mk
|   |-- AndroidProducts.mk
|   |-- BoardConfig.mk
|   |-- dma6410xp.mk
|   |-- init.dma6410xp.rc
|   |-- init.goldfish.sh
|   `-- init.rc
|-- frameworks     //框架代码
|   |-- Android.mk
|   `-- base
|       |-- Android.mk
|       |-- core
|       |   `-- java
|       |       `-- mokoid
|       |           `-- hardware
|       |               |-- ILedService.aidl
|       |               `-- LedManager.java     //实现了Manager,给第2种方法用
|       `-- service  
|           |-- Android.mk
|           |-- com.mokoid.server.xml
|           |-- java
|           |   `-- com
|           |       `-- mokoid
|           |           `-- server
|           |               `-- LedService.java    //Framework service代码
|           `-- jni
|               |-- Android.mk
|               `-- com_mokoid_server_LedService.cpp  //jni代码
|-- hardware
|   |-- Android.mk
|   |-- libled
|   |   |-- Android.mk
|   |   `-- libled.c
|   `-- modules
|       |-- Android.mk
|       |-- include
|       |   `-- mokoid
|       |       `-- led.h
|       `-- led
|           |-- Android.mk
|           `-- led.c       //led stub 硬件控制代码
`-- README.txt
 
    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

 
view plaincopy to clipboardprint?
01.struct led_module_t {  
02.   struct hw_module_t common;  
03.};  
04.//HAL 规定不能直接使用hw_module_t结构,因此需要做这么一个继承。  
05.struct led_control_device_t {    
06.//自定义的一个针对Led控制的结构,包含hw_device_t和支持的API操作  
07.   struct hw_device_t common;  
08.   /* attributes */ 
09.   int fd;  //可用于具体的设备描述符  
10.   /* supporting control APIs go here */ 
11.   int (*set_on)(struct led_control_device_t *dev, int32_t led);  
12.   int (*set_off)(struct led_control_device_t *dev, int32_t led);  
13.}; 
14.#define LED_HARDWARE_MODULE_ID "led"    
15.//定义一个MODULE_ID,HAL层可以根据这个ID找到我们这个HAL stub 
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
view plaincopy to clipboardprint?
01.#define LOG_TAG "MokoidLedStub" 
02.#include <hardware/hardware.h> 
03.#include <fcntl.h> 
04.#include <errno.h> 
05.#include <cutils/log.h> 
06.#include <cutils/atomic.h>  
07.//#include <mokoid/led.h> 
08.#include "../include/mokoid/led.h"  
09./*****************************************************************************/ 
10.int fd;             //硬件led的设备描述符 。你也可以用led_control_device_t结构中定义的fd 
11.#define GPG3DAT2_ON 0x4800                 //ioctl控制命令 
12.#define GPG3DAT2_OFF 0x4801  
13.int led_device_close(struct hw_device_t* device)  
14.{  
15.    struct led_control_device_t* ctx = (struct led_control_device_t*)device;  
16.    if (ctx) {  
17.        free(ctx);  
18.    }  
19.    close(fd);  
20.    return 0;  
21.}  
22.int led_on(struct led_control_device_t *dev, int32_t led)  
23.{  
24.    LOGI("LED Stub: set %d on.", led);  
25.    ioctl(fd,GPG3DAT2_ON,NULL);           //控制Led亮灭,和硬件相关  
26.    return 0;  
27.}  
28.int led_off(struct led_control_device_t *dev, int32_t led)  
29.{  
30.    LOGI("LED Stub: set %d off.", led);  
31.    return 0;  
32.}  
33.static int led_device_open(const struct hw_module_t* module, const char* name,  
34.        struct hw_device_t** device)   
35.{  
36.    struct led_control_device_t *dev;  
37.    dev = (struct led_control_device_t *)malloc(sizeof(*dev));  
38.    memset(dev, 0, sizeof(*dev));  
39.    dev->common.tag =  HARDWARE_DEVICE_TAG;  
40.    dev->common.version = 0;  
41.    dev->common.module = module;  
42.    dev->common.close = led_device_close;  
43.    dev->set_on = led_on;        //实例化支持的操作  
44.    dev->set_off = led_off;  
45.    *device = &dev->common;     //将实例化后的led_control_device_t地址返回给jni层  
46.                    //这样jni层就可以直接调用led_on、led_off、led_device_close方法了。  
47.    if((fd=open("/dev/led",O_RDWR))==-1)      //打开硬件设备  
48.    {  
49.        LOGE("LED open error");  
50.    }  
51.    else 
52.        LOGI("open ok");  
53.success:  
54.    return 0;  
55.}  
56.static struct hw_module_methods_t led_module_methods = {  
57.    open: led_device_open  
58.};  
59.const struct led_module_t HAL_MODULE_INFO_SYM = {  
60.//定义这个对象等于向系统注册了一个ID为LED_HARDWARE_MODULE_ID的stub。注意这里HAL_MODULE_INFO_SYM的名称不能改。  
61.    common: {  
62.        tag: HARDWARE_MODULE_TAG,  
63.        version_major: 1,  
64.        version_minor: 0,  
65.        id: LED_HARDWARE_MODULE_ID,  
66.        name: "Sample LED Stub",  
67.        author: "The Mokoid Open Source Project",  
68.        methods: &led_module_methods,  //实现了一个open的方法供jni层调用,  
69.                                       //从而实例化led_control_device_t  
70.    }  
71.    /* supporting APIs go here */ 
72.}; 
#define LOG_TAG "MokoidLedStub"
#include <hardware/hardware.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
//#include <mokoid/led.h>
#include "../include/mokoid/led.h"
/*****************************************************************************/
int fd;             //硬件led的设备描述符 。你也可以用led_control_device_t结构中定义的fd
#define GPG3DAT2_ON 0x4800                 //ioctl控制命令
#define GPG3DAT2_OFF 0x4801
int led_device_close(struct hw_device_t* device)
{
 struct led_control_device_t* ctx = (struct led_control_device_t*)device;
 if (ctx) {
  free(ctx);
 }
 close(fd);
 return 0;
}
int led_on(struct led_control_device_t *dev, int32_t led)
{
 LOGI("LED Stub: set %d on.", led);
 ioctl(fd,GPG3DAT2_ON,NULL);           //控制Led亮灭,和硬件相关
 return 0;
}
int led_off(struct led_control_device_t *dev, int32_t led)
{
 LOGI("LED Stub: set %d off.", led);
 return 0;
}
static int led_device_open(const struct hw_module_t* module, const char* name,
        struct hw_device_t** device)
{
 struct led_control_device_t *dev;
 dev = (struct led_control_device_t *)malloc(sizeof(*dev));
 memset(dev, 0, sizeof(*dev));
 dev->common.tag =  HARDWARE_DEVICE_TAG;
 dev->common.version = 0;
 dev->common.module = module;
 dev->common.close = led_device_close;
 dev->set_on = led_on;        //实例化支持的操作
 dev->set_off = led_off;
 *device = &dev->common;     //将实例化后的led_control_device_t地址返回给jni层
                    //这样jni层就可以直接调用led_on、led_off、led_device_close方法了。
 if((fd=open("/dev/led",O_RDWR))==-1)      //打开硬件设备
 {
  LOGE("LED open error");
 }
 else
  LOGI("open ok");
success:
 return 0;
}
static struct hw_module_methods_t led_module_methods = {
    open: led_device_open
};
const struct led_module_t HAL_MODULE_INFO_SYM = {
//定义这个对象等于向系统注册了一个ID为LED_HARDWARE_MODULE_ID的stub。注意这里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,  //实现了一个open的方法供jni层调用,
                                       //从而实例化led_control_device_t
    }
    /* supporting APIs go here */
};
 
(2)JNI层文件:mokoid-read-only/frameworks/base/service/jni/com_mokoid_server_LedService.cpp
view plaincopy to clipboardprint?
01.struct led_control_device_t *sLedDevice = NULL;  
02. 
03.static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led)   
04.{  
05.    LOGI("LedService JNI: mokoid_setOn() is invoked.");  
06. 
07.    if (sLedDevice == NULL) {  
08.        LOGI("LedService JNI: sLedDevice was not fetched correctly.");  
09.        return -1;  
10.    } else {  
11.        return sLedDevice->set_on(sLedDevice, led);//调用hal层的注册的方法  
12.    }  
13.}  
14. 
15.static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led)   
16.{  
17.    LOGI("LedService JNI: mokoid_setOff() is invoked.");  
18. 
19. 
20.    if (sLedDevice == NULL) {  
21.        LOGI("LedService JNI: sLedDevice was not fetched correctly.");  
22.        return -1;  
23.    } else {  
24.        return sLedDevice->set_off(sLedDevice, led); //调用hal层的注册的方法  
25.    }  
26.}  
27. 
28./** helper APIs */ 
29.static inline int led_control_open(const struct hw_module_t* module,  
30.        struct led_control_device_t** device) {  
31.    return module->methods->open(module,  
32.            LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);  
33.//这个过程非常重要,jni通过LED_HARDWARE_MODULE_ID找到对应的stub  
34.}  
35. 
36.static jboolean mokoid_init(JNIEnv *env, jclass clazz)  
37.{  
38.    led_module_t* module;  
39.     LOGI("jni init-----------------------.");  
40.if (hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) {  
41.//根据LED_HARDWARE_MODULE_ID找到hw_module_t,参考hal层的实现  
42.        LOGI("LedService JNI: LED Stub found.");  
43.        if (led_control_open(&module->common, &sLedDevice) == 0) {    
44.    //通过hw_module_t找到led_control_device_t  
45.            LOGI("LedService JNI: Got Stub operations.");  
46.            return 0;  
47.        }  
48.    }  
49. 
50.    LOGE("LedService JNI: Get Stub operations failed.");  
51.    return -1;  
52.}  
53. 
54./* 
55. * Array of methods. 
56.* Each entry has three fields: the name of the method, the method 
57. * signature, and a pointer to the native implementation. 
58. */ 
59.static const JNINativeMethod gMethods[] = {  
60.    { "_init",      "()Z",  (void *)mokoid_init },//Framework层调用_init时促发  
61.    { "_set_on",        "(I)Z", (void *)mokoid_setOn },  
62.    { "_set_off",       "(I)Z", (void *)mokoid_setOff },  
63.};  
64./* 
65.*JNINativeMethod是jni层注册的方法,Framework层可以使用这些方法 
66.*_init 、_set_on、_set_off是在Framework中调用的方法名称,函数的类型及返回值如下: 
67.*()Z   无参数    返回值为bool型 
68.* (I)Z   整型参数  返回值为bool型 
69.*/ 
70.static int registerMethods(JNIEnv* env) {  
71.        static const char* const kClassName =  
72.        "com/mokoid/server/LedService";//注意:必须和你Framework层的service类名相同  
73.        jclass clazz;   
74.      /* look up the class */ 
75.        clazz = env->FindClass(kClassName);  
76.        if (clazz == NULL) {  
77.                    LOGE("Can't find class %s\n", kClassName);  
78.                    return -1;  
79.        }  
80.    /* register all the methods */ 
81.        if (env->RegisterNatives(clazz, gMethods,  
82.                        sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)  
83.        {  
84.            LOGE("Failed registering methods for %s\n", kClassName);  
85.            return -1;  
86.        }  
87.    /* fill out the rest of the ID cache */ 
88.        return 0;  
89.}   
90.jint JNI_OnLoad(JavaVM* vm, void* reserved) {//Framework层加载jni库时调用   
91.        JNIEnv* env = NULL;  
92.        jint result = -1;  
93.        LOGI("JNI_OnLoad LED");  
94.            if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
95.            LOGE("ERROR: GetEnv failed\n");  
96.            goto fail;  
97.        }  
98.            assert(env != NULL);  
99.        if (registerMethods(env) != 0) { //注册你的JNINativeMethod  
100.            LOGE("ERROR: PlatformLibrary native registration failed\n");  
101.            goto fail;  
102.        }  
103.        /* success -- return valid version number */      
104.        result = JNI_VERSION_1_4;  
105.fail:  
106.        return result;  
107.} 
struct led_control_device_t *sLedDevice = NULL;
static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led)
{
    LOGI("LedService JNI: mokoid_setOn() is invoked.");
    if (sLedDevice == NULL) {
        LOGI("LedService JNI: sLedDevice was not fetched correctly.");
        return -1;
    } else {
        return sLedDevice->set_on(sLedDevice, led);//调用hal层的注册的方法
    }
}
static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led)
{
    LOGI("LedService JNI: mokoid_setOff() is invoked.");

    if (sLedDevice == NULL) {
        LOGI("LedService JNI: sLedDevice was not fetched correctly.");
        return -1;
    } else {
        return sLedDevice->set_off(sLedDevice, led); //调用hal层的注册的方法
    }
}
/** helper APIs */
static inline int led_control_open(const struct hw_module_t* module,
        struct led_control_device_t** device) {
    return module->methods->open(module,
            LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
//这个过程非常重要,jni通过LED_HARDWARE_MODULE_ID找到对应的stub
}
static jboolean mokoid_init(JNIEnv *env, jclass clazz)
{
    led_module_t* module;
     LOGI("jni init-----------------------.");
if (hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) {
//根据LED_HARDWARE_MODULE_ID找到hw_module_t,参考hal层的实现
        LOGI("LedService JNI: LED Stub found.");
        if (led_control_open(&module->common, &sLedDevice) == 0) { 
    //通过hw_module_t找到led_control_device_t
         LOGI("LedService JNI: Got Stub operations.");
            return 0;
        }
    }
    LOGE("LedService JNI: Get Stub operations failed.");
    return -1;
}
/*
 * Array of methods.
* Each entry has three fields: the name of the method, the method
 * signature, and a pointer to the native implementation.
 */
static const JNINativeMethod gMethods[] = {
    { "_init",    "()Z", (void *)mokoid_init },//Framework层调用_init时促发
    { "_set_on",        "(I)Z", (void *)mokoid_setOn },
    { "_set_off",       "(I)Z", (void *)mokoid_setOff },
};
/*
*JNINativeMethod是jni层注册的方法,Framework层可以使用这些方法
*_init 、_set_on、_set_off是在Framework中调用的方法名称,函数的类型及返回值如下:
*()Z   无参数    返回值为bool型
* (I)Z   整型参数  返回值为bool型
*/
static int registerMethods(JNIEnv* env) {
  static const char* const kClassName =
  "com/mokoid/server/LedService";//注意:必须和你Framework层的service类名相同
  jclass clazz;
      /* look up the class */
  clazz = env->FindClass(kClassName);
  if (clazz == NULL) {
     LOGE("Can't find class %s\n", kClassName);
     return -1;
  }
 /* register all the methods */
  if (env->RegisterNatives(clazz, gMethods,
      sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)
  {
   LOGE("Failed registering methods for %s\n", kClassName);
   return -1;
  }
 /* fill out the rest of the ID cache */
  return 0;
}
jint JNI_OnLoad(JavaVM* vm, void* reserved) {//Framework层加载jni库时调用
  JNIEnv* env = NULL;
  jint result = -1;
  LOGI("JNI_OnLoad LED");
       if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
   LOGE("ERROR: GetEnv failed\n");
   goto fail;
  }
      assert(env != NULL);
  if (registerMethods(env) != 0) { //注册你的JNINativeMethod
   LOGE("ERROR: PlatformLibrary native registration failed\n");
   goto fail;
  }
  /* success -- return valid version number */ 
  result = JNI_VERSION_1_4;
fail:
  return result;
}
 
(3)service  (属于Framework层)文件:frameworks/base/service/java/com/mokoid/server/LedService.java
view plaincopy to clipboardprint?
01.package com.mokoid.server;  
02.import android.util.Config;  
03.import android.util.Log;  
04.import android.content.Context;  
05.import android.os.Binder;  
06.import android.os.Bundle;  
07.import android.os.RemoteException;  
08.import android.os.IBinder;  
09.import mokoid.hardware.ILedService;  
10.public final class LedService extends ILedService.Stub {  
11.//对于这种直接模式不需要进程通讯,所以可以不加extends ILedService.Stub,此处加上主要是为了后面的第二种模式.  
12.    static {  
13.        System.load("/system/lib/libmokoid_runtime.so");//加载jni的动态库  
14.    }  
15.    public LedService() {  
16.        Log.i("LedService", "Go to get LED Stub...");  
17.    _init();  
18.    }  
19.    /* 
20.     * Mokoid LED native methods. 
21.     */ 
22.    public boolean setOn(int led) {  
23.        Log.i("MokoidPlatform", "LED On");  
24.    return _set_on(led);  
25.    }  
26.    public boolean setOff(int led) {  
27.        Log.i("MokoidPlatform", "LED Off");  
28.    return _set_off(led);  
29.    }  
30.    private static native boolean _init();          //声明jni库可以提供的方法  
31.    private static native boolean _set_on(int led);  
32.    private static native boolean _set_off(int led);  
33.} 
package com.mokoid.server;
import android.util.Config;
import android.util.Log;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.IBinder;
import mokoid.hardware.ILedService;
public final class LedService extends ILedService.Stub {
//对于这种直接模式不需要进程通讯,所以可以不加extends ILedService.Stub,此处加上主要是为了后面的第二种模式.
    static {
        System.load("/system/lib/libmokoid_runtime.so");//加载jni的动态库
    }
    public LedService() {
        Log.i("LedService", "Go to get LED Stub...");
 _init();
    }
    /*
     * Mokoid LED native methods.
     */
    public boolean setOn(int led) {
        Log.i("MokoidPlatform", "LED On");
 return _set_on(led);
    }
    public boolean setOff(int led) {
        Log.i("MokoidPlatform", "LED Off");
 return _set_off(led);
    }
    private static native boolean _init();          //声明jni库可以提供的方法
    private static native boolean _set_on(int led);
    private static native boolean _set_off(int led);
}
 
(4)APP 测试程序 (属于APP层)文件:apps/LedClient/src/com/mokoid/LedClient/LedClient.java
 
view plaincopy to clipboardprint?
01.package com.mokoid.LedClient;  
02.import com.mokoid.server.LedService;// 导入Framework层的LedService  
03.import android.app.Activity;  
04.import android.os.Bundle;  
05.import android.widget.TextView;  
06. 
07.public class LedClient extends Activity {  
08.    @Override  
09.    public void onCreate(Bundle savedInstanceState) {  
10.        super.onCreate(savedInstanceState);  
11.        // Call an API on the library.  
12.    LedService ls = new LedService();  //实例化LedService  
13.    ls.setOn(1);                       //通过LedService提供的方法,控制底层硬件  
14.    ls.setOff(2);  
15.          
16.        TextView tv = new TextView(this);  
17.        tv.setText("LED 1 is on. LED 2 is off.");  
18.        setContentView(tv);  
19.    }  
20.} 
package com.mokoid.LedClient;
import com.mokoid.server.LedService;// 导入Framework层的LedService
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class LedClient extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Call an API on the library.
 LedService ls = new LedService();  //实例化LedService
 ls.setOn(1);                       //通过LedService提供的方法,控制底层硬件
 ls.setOff(2);
       
        TextView tv = new TextView(this);
        tv.setText("LED 1 is on. LED 2 is off.");
        setContentView(tv);
    }
}
 
5、第二种方法:经过Manager调用service
    HAL、JNI两层和第一种方法一样,所以后面只分析其他的层次。
(1)Manager (属于Framework层)
    APP通过这个Manager和service通讯。
文件:mokoid-read-only /frameworks/base/core/java/mokoid/hardware/LedManager.java
 
view plaincopy to clipboardprint?
01.package mokoid.hardware;  
02.import android.content.Context;  
03.import android.os.Binder;  
04.import android.os.Bundle;  
05.import android.os.Parcelable;  
06.import android.os.ParcelFileDescriptor;  
07.import android.os.Process;  
08.import android.os.RemoteException;  
09.import android.os.Handler;  
10.import android.os.Message;  
11.import android.os.ServiceManager;  
12.import android.util.Log;  
13.import mokoid.hardware.ILedService;  
14. 
15./* 
16. * Class that lets you access the Mokoid LedService. 
17. */ 
18.public class LedManager  
19.{  
20.    private static final String TAG = "LedManager";  
21.    private ILedService mLedService;  
22.    public LedManager() {  
23.        mLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));  
24./* 
25.*这一步是关键,利用ServiceManager获取到LedService,从而调用它提供的方法。这要求LedService必 
26.*须已经添加到了ServiceManager中,这个过程将在App中的一个service进程中完成。 
27.*/ 
28.    if (mLedService != null) {  
29.            Log.i(TAG, "The LedManager object is ready.");  
30.    }  
31.    }  
32.    public boolean LedOn(int n) {  
33.        boolean result = false;  
34.        try {  
35.            result = mLedService.setOn(n);  
36.        } catch (RemoteException e) {  
37.            Log.e(TAG, "RemoteException in LedManager.LedOn:", e);  
38.        }  
39.        return result;  
40.    }  
41.    public boolean LedOff(int n) {  
42.        boolean result = false;  
43.        try {  
44.            result = mLedService.setOff(n);  
45.        } catch (RemoteException e) {  
46.            Log.e(TAG, "RemoteException in LedManager.LedOff:", e);  
47.        }  
48.        return result;  
49.    }  
50.} 
package mokoid.hardware;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
import android.util.Log;
import mokoid.hardware.ILedService;
/*
 * Class that lets you access the Mokoid LedService.
 */
public class LedManager
{
    private static final String TAG = "LedManager";
    private ILedService mLedService;
    public LedManager() {
        mLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));
/*
*这一步是关键,利用ServiceManager获取到LedService,从而调用它提供的方法。这要求LedService必
*须已经添加到了ServiceManager中,这个过程将在App中的一个service进程中完成。
*/
 if (mLedService != null) {
            Log.i(TAG, "The LedManager object is ready.");
 }
    }
    public boolean LedOn(int n) {
        boolean result = false;
        try {
            result = mLedService.setOn(n);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in LedManager.LedOn:", e);
        }
        return result;
    }
    public boolean LedOff(int n) {
        boolean result = false;
        try {
            result = mLedService.setOff(n);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in LedManager.LedOff:", e);
        }
        return result;
    }
}
 
因为LedService和LedManager在不同的进程,所以要考虑到进程通讯的问题。Manager通过增加一个aidl文件来描述通讯接口。

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

view plaincopy to clipboardprint?
01.package mokoid.hardware;  
02.interface ILedService  
03.{  
04.    boolean setOn(int led);  
05.    boolean setOff(int led);  
06.}  
07.//系统的aidl工具会将ILedService.aidl文件ILedService.java文件,实现了ILedService 
package mokoid.hardware;
interface ILedService
{
    boolean setOn(int led);
    boolean setOff(int led);
}
//系统的aidl工具会将ILedService.aidl文件ILedService.java文件,实现了ILedService
 
(2)SystemServer (属于APP层)
文件:mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedSystemServer.java
view plaincopy to clipboardprint?
01.package com.mokoid.LedTest;  
02.import com.mokoid.server.LedService;  
03.import android.os.IBinder;  
04.import android.os.ServiceManager;  
05.import android.util.Log;  
06.import android.app.Service;  
07.import android.content.Context;  
08.import android.content.Intent;  
09. 
10.public class LedSystemServer extends Service {  
11.//注意这里的Service是APP中的概念,代表一个后台进程。注意区别和Framework中的service的概念。  
12.    @Override  
13.    public IBinder onBind(Intent intent) {  
14.        return null;  
15.    public void onStart(Intent intent, int startId) {  
16.        Log.i("LedSystemServer", "Start LedService...");  
17. 
18.    /* Please also see SystemServer.java for your interests. */ 
19.    LedService ls = new LedService();  
20.        try {  
21.            ServiceManager.addService("led", ls);  //将LedService添加到ServiceManager中  
22.        } catch (RuntimeException e) {  
23.            Log.e("LedSystemServer", "Start LedService failed.");  
24.        }  
25.    }  
26.} 
package com.mokoid.LedTest;
import com.mokoid.server.LedService;
import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Log;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
public class LedSystemServer extends Service {
//注意这里的Service是APP中的概念,代表一个后台进程。注意区别和Framework中的service的概念。
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    public void onStart(Intent intent, int startId) {
        Log.i("LedSystemServer", "Start LedService...");
 /* Please also see SystemServer.java for your interests. */
 LedService ls = new LedService();
        try {
            ServiceManager.addService("led", ls);  //将LedService添加到ServiceManager中
        } catch (RuntimeException e) {
            Log.e("LedSystemServer", "Start LedService failed.");
        }
    }
}
 
(3)APP 测试程序(属于APP层)
文件:mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedTest.java
view plaincopy to clipboardprint?
01.package com.mokoid.LedTest;  
02.import mokoid.hardware.LedManager;  
03.import com.mokoid.server.LedService;  
04.import android.app.Activity;  
05.import android.os.Bundle;  
06.import android.util.Log;  
07.import android.widget.TextView;  
08.import android.widget.Button;  
09.import android.content.Intent;  
10.import android.view.View;  
11. 
12.public class LedTest extends Activity implements View.OnClickListener {  
13.    private LedManager mLedManager = null;  
14.    @Override  
15.    public void onCreate(Bundle savedInstanceState) {  
16.        super.onCreate(savedInstanceState);  
17.        // Start LedService in a seperated process.  
18.        startService(new Intent("com.mokoid.systemserver"));//开启后台进程  
19.        Button btn = new Button(this);  
20.        btn.setText("Click to turn LED 1 On");  
21.     btn.setOnClickListener(this);  
22.        setContentView(btn);  
23.    }  
24.    public void onClick(View v) {  
25.        // Get LedManager.  
26.        if (mLedManager == null) {  
27.        Log.i("LedTest", "Creat a new LedManager object.");  
28.        mLedManager = new LedManager();  //实例化Framework层中的Manager  
29.        }      
30.        if (mLedManager != null) {  
31.        Log.i("LedTest", "Got LedManager object.");  
32.     }  
33.        /** Call methods in LedService via proxy object  
34.         * which is provided by LedManager.  
35.         */ 
36.        mLedManager.LedOn(1);  
37.        TextView tv = new TextView(this);  
38.        tv.setText("LED 1 is On.");  
39.        setContentView(tv);  
40.    }  
41.} 
package com.mokoid.LedTest;
import mokoid.hardware.LedManager;
import com.mokoid.server.LedService;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Button;
import android.content.Intent;
import android.view.View;
public class LedTest extends Activity implements View.OnClickListener {
    private LedManager mLedManager = null;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Start LedService in a seperated process.
        startService(new Intent("com.mokoid.systemserver"));//开启后台进程
        Button btn = new Button(this);
        btn.setText("Click to turn LED 1 On");
  btn.setOnClickListener(this);
        setContentView(btn);
    }
    public void onClick(View v) {
        // Get LedManager.
        if (mLedManager == null) {
     Log.i("LedTest", "Creat a new LedManager object.");
     mLedManager = new LedManager();  //实例化Framework层中的Manager
        }   
        if (mLedManager != null) {
     Log.i("LedTest", "Got LedManager object.");
  }
        /** Call methods in LedService via proxy object
         * which is provided by LedManager.
         */
        mLedManager.LedOn(1);
        TextView tv = new TextView(this);
        tv.setText("LED 1 is On.");
        setContentView(tv);
    }
}
 

五、实验中需要注意的问题
将下载后的源码放到你的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
按照以前的实验加入下列代码:

view plaincopy to clipboardprint?
01.static int registerMethods(JNIEnv* env) {  
02.    static const char* const kClassName ="com/mokoid/server/LedService";  
03.    jclass clazz;   
04.        /* look up the class */ 
05.        clazz = env->FindClass(kClassName);  
06.        if (clazz == NULL) {  
07.            LOGE("Can't find class %s\n", kClassName);  
08.            return -1;  
09.        }  
10.            /* register all the methods */ 
11.        if (env->RegisterNatives(clazz, gMethods,  
12.                    sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)  
13.        {  
14.            LOGE("Failed registering methods for %s\n", kClassName);  
15.            return -1;  
16.        }  
17.    /* fill out the rest of the ID cache */ 
18.        return 0;  
19.}   
20./* 
21. * This is called by the VM when the shared library is first loaded. 
22. */   
23.jint JNI_OnLoad(JavaVM* vm, void* reserved) {  
24.        JNIEnv* env = NULL;  
25.        jint result = -1;  
26.        LOGI("JNI_OnLoad LED");  
27.        if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
28.            LOGE("ERROR: GetEnv failed\n");  
29.            goto fail;  
30.        }  
31.        assert(env != NULL);  
32.        if (registerMethods(env) != 0) {  
33.            LOGE("ERROR: PlatformLibrary native registration failed\n");  
34.            goto fail;  
35.        }  
36.        /* success -- return valid version number */      
37.        result = JNI_VERSION_1_4;  
38.fail:  
39.        return result;  
40.}  
static int registerMethods(JNIEnv* env) {
 static const char* const kClassName ="com/mokoid/server/LedService";
 jclass clazz;
     /* look up the class */
  clazz = env->FindClass(kClassName);
  if (clazz == NULL) {
   LOGE("Can't find class %s\n", kClassName);
   return -1;
  }
   /* register all the methods */
  if (env->RegisterNatives(clazz, gMethods,
     sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)
  {
   LOGE("Failed registering methods for %s\n", kClassName);
   return -1;
  }
 /* fill out the rest of the ID cache */
  return 0;
}
/*
 * This is called by the VM when the shared library is first loaded.
 */
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  JNIEnv* env = NULL;
  jint result = -1;
  LOGI("JNI_OnLoad LED");
      if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
   LOGE("ERROR: GetEnv failed\n");
   goto fail;
  }
     assert(env != NULL);
  if (registerMethods(env) != 0) {
   LOGE("ERROR: PlatformLibrary native registration failed\n");
   goto fail;
  }
  /* success -- return valid version number */ 
  result = JNI_VERSION_1_4;
fail:
  return result;
}
 

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工程源码中已经做了这些。
 

 

  (2)经过Manager调用service
 
本文来自CSDN博客,转载请标明出处: http://blog.csdn.net/hongtao_liu/archive/2010/12/07/6060734.aspx

详细页面:http://www.verydemo.com/demo_c131_i121430.html

猜你喜欢

转载自huangxiaoshi8896513.iteye.com/blog/2073687
今日推荐