Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1736908
  • 博文数量: 206
  • 博客积分: 1450
  • 博客等级: 上尉
  • 技术积分: 2285
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-11 11:38
个人简介

学习永无止境!!

文章分类

全部博文(206)

文章存档

2022年(5)

2019年(3)

2018年(8)

2017年(32)

2016年(7)

2015年(13)

2014年(44)

2013年(24)

2011年(6)

2010年(17)

2009年(46)

2008年(1)

分类: 嵌入式

2011-10-12 16:52:56

一、概述

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

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

 

 

    AndroidHAL实现需要通JNI(Java Native Interface)JNI简单就是java程序可以C/C++写的动态链这样HAL可以使用C/C++效率更高。在Android下访问HAL大致有以下两方式:

 

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

 

 

 

 

 

 

(2)经过Manager调用service

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

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

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

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

1HAL

    一般来说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

  1. struct led_module_t {  
  2.    struct hw_module_t common;  
  3. };  
  4. //HAL 规定不能直接使用hw_module_t结构,因此需要做这么一个继承。   
  5. struct led_control_device_t {    
  6. //自定义的一个针对Led控制的结构,包含hw_device_t和支持的API操作   
  7.    struct hw_device_t common;  
  8.    /* attributes */  
  9.    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

  1. #define LOG_TAG "MokoidLedStub"  
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include    
  7. //#include   
  8. #include "../include/mokoid/led.h"   
  9. /*****************************************************************************/  
  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 #include #include #include #include //#include #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 */ };

2JNI

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

  1. struct led_control_device_t *sLedDevice = NULL;  
  2.   
  3. static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led)   
  4. {  
  5.     LOGI("LedService JNI: mokoid_setOn() is invoked.");  
  6.   
  7.     if (sLedDevice == NULL) {  
  8.         LOGI("LedService JNI: sLedDevice was not fetched correctly.");  
  9.         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 charconst 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; }  

 

3service  属于Framework

文件:frameworks/base/service/java/com/mokoid/server/LedService.java

  1. package com.mokoid.server;  
  2. import android.util.Config;  
  3. import android.util.Log;  
  4. import android.content.Context;  
  5. import android.os.Binder;  
  6. import android.os.Bundle;  
  7. import android.os.RemoteException;  
  8. import android.os.IBinder;  
  9. 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); }  

4APP 测试程序 (属于APP

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

  1. package com.mokoid.LedClient;  
  2. import com.mokoid.server.LedService;// 导入Framework层的LedService   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.widget.TextView;  
  6.   
  7. public class LedClient extends Activity {  
  8.     @Override  
  9.     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

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

1Manager 属于Framework

    APP通过这个Managerservice通讯。

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

 

  1. package mokoid.hardware;  
  2. import android.content.Context;  
  3. import android.os.Binder;  
  4. import android.os.Bundle;  
  5. import android.os.Parcelable;  
  6. import android.os.ParcelFileDescriptor;  
  7. import android.os.Process;  
  8. import android.os.RemoteException;  
  9. 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; } }   

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

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

  1. package mokoid.hardware;  
  2. interface ILedService  
  3. {  
  4.     boolean setOn(int led);  
  5.     boolean setOff(int led);  
  6. }  
  7. //系统的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   

2SystemServer 属于APP

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

  1. package com.mokoid.LedTest;  
  2. import com.mokoid.server.LedService;  
  3. import android.os.IBinder;  
  4. import android.os.ServiceManager;  
  5. import android.util.Log;  
  6. import android.app.Service;  
  7. import android.content.Context;  
  8. import android.content.Intent;  
  9.   
  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."); } } }

3APP 测试程序属于APP

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

  1. package com.mokoid.LedTest;  
  2. import mokoid.hardware.LedManager;  
  3. import com.mokoid.server.LedService;  
  4. import android.app.Activity;  
  5. import android.os.Bundle;  
  6. import android.util.Log;  
  7. import android.widget.TextView;  
  8. import android.widget.Button;  
  9. 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

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

  1. static int registerMethods(JNIEnv* env) {  
  2.     static const charconst kClassName ="com/mokoid/server/LedService";  
  3.     jclass clazz;   
  4.         /* look up the class */  
  5.         clazz = env->FindClass(kClassName);  
  6.         if (clazz == NULL) {  
  7.             LOGE("Can't find class %s/n", kClassName);  
  8.             return -1;  
  9.         }  
  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工程源码中已经做了这些。

阅读(1460) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~