Chinaunix首页 | 论坛 | 博客
  • 博客访问: 688414
  • 博文数量: 207
  • 博客积分: 1743
  • 博客等级: 上尉
  • 技术积分: 2044
  • 用 户 组: 普通用户
  • 注册时间: 2012-08-20 14:36
文章分类

全部博文(207)

文章存档

2016年(24)

2015年(10)

2014年(50)

2013年(45)

2012年(78)

分类: Android平台

2016-01-25 14:53:33

http://blog.csdn.net/rickbeyond/article/details/7839245

二、 使用JNI在应用程序框架层添加服务访问接口

       APP应用不能直接访问HAL层,需要JNI层访问HAL模块并向上提供API接口。可以直接提供接口,但建议最好使用服务的方式提供访问。

       我们先看JNI如何访问刚才的HAL模块。

       进入源码根目录下的frameworks/base/service/jni目录,新建com_android_server_IICService.cpp,代码如下:

  1. #include "jni.h"    
  2. #include "JNIHelp.h"    
  3. #include "android_runtime/AndroidRuntime.h"    
  4. #include     
  5. #include     
  6. #include     
  7. #include     
  8. #include   
  9.   
  10. namespace android    
  11. {    
  12.     /*在硬件抽象层中定义的硬件访问结构体,参考*/    
  13.         struct iic_device_t* iic_device = NULL;    
  14.     /*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/    
  15.     static void iic_setVal(JNIEnv* env, jobject clazz, jstring val, jint slaveAddr, jint subAddr, jint len) {    
  16.         const char *str = env->GetStringUTFChars(val, NULL);    
  17.         LOGI("iic JNI: set value %s to device.", str);    
  18.         if(!iic_device) {    
  19.             LOGI("iic JNI: device is not open.");    
  20.             return;    
  21.         }    
  22.         iic_device->iic_write(iic_device, (unsigned char*)str, slaveAddr, subAddr, len);    
  23.     env->ReleaseStringUTFChars(val, str);  //注意释放资源  
  24.     }    
  25.   
  26.        /*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/    
  27.     static jstring iic_getVal(JNIEnv* env, jobject clazz, jint slaveAddr, jint len) {  
  28.     unsigned char* data = (unsigned char*)malloc(len);  
  29.     iic_device->iic_read(iic_device, data, slaveAddr, len);  
  30.         if(!iic_device) {    
  31.             LOGI("iic JNI: device is not open.");    
  32.         }  
  33.     int i = 0;  
  34.     for(;iconst char*)data);i++){  
  35.       LOGI("data: %c ", data[i]);  
  36.     }    
  37.         //LOGI("iic JNI: get value %s from device @ %x address!", data, subAddr);  
  38.     jstring tmp = env->NewStringUTF((const char*)data);  
  39.     free(data);  
  40.     data = NULL;  
  41.     return tmp;     
  42.     }   
  43.     
  44.         /*通过硬件抽象层定义的硬件模块open接口打开硬件设备*/    
  45.     static inline int iic_device_open(const hw_module_t* module, struct iic_device_t** device) {    
  46.         return module->methods->open(module, IIC_HARDWARE_MODULE_ID, (struct hw_device_t**)device);    
  47.     }    
  48.         /*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/    
  49.     static jboolean iic_init(JNIEnv* env, jclass clazz) {    
  50.         iic_module_t* module;    
  51.             
  52.         LOGI("iic JNI: initializing......");    
  53.         if(hw_get_module(IIC_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {    
  54.             LOGI("iic JNI: iic Stub found.");    
  55.             if(iic_device_open(&(module->common), &iic_device) == 0) {    
  56.                 LOGI("eeprom JNI: iic device is opening...");    
  57.                 return 0;    
  58.             }    
  59.             LOGE("eeprom JNI: failed to open iic device.");    
  60.             return -1;    
  61.         }    
  62.         LOGE("eeprom JNI: failed to get iic stub module.");    
  63.         return -1;          
  64.     }    
  65.         /*JNI方法表*/    
  66.     static const JNINativeMethod method_table[] = {    
  67.         {"init_native""()Z", (void*)iic_init},    
  68.         {"setVal_native""(Ljava/lang/String;III)V", (void*)iic_setVal},    
  69.         {"getVal_native""(III)Ljava/lang/String;", (void*)iic_getVal},    
  70.     };    
  71.         /*注册JNI方法*/    
  72.     int register_android_server_IICService(JNIEnv *env) {    
  73.             return jniRegisterNativeMethods(env, "com/android/server/IICService", method_table, NELEM(method_table));    
  74.     }    
  75. };  

然后需要让android启动时加载此jni模块

在同目录下修改onload.cpp:

在namespace android中添加一行    int register_android_server_IICService(JNIEnv *env);

在JNI_onLoad方法中添加一行  register_android_server_IICService(env);

在同目录下修改Android.mk:

LOCAL_SRC_FILES增加一行   com_android_server_IICService \

编译命令:mmm frameworks/base/services/jni

注意: HAL是根据iic_init中的IIC_HARDWARE_MODULE_ID加载相应模块。

然后,使用AIDL进行进程间通信,使APP能访问自定义的硬件服务。

我们需要在frameworks/base/core/java/android/os中新建IIICService.aidl(注意是III)

package android.os;  
interface IIICService {  
    void setVal(String val, int slaveAddr, int regAddr, int len);  
    String getVal(int slaveAddr, int len);  

它定义了服务的接口,接口在IICService中实现并关联到jni本地方法中。

同时我们需要修改frameworkd/base下的Android.mk编译文件,在LOCAL_SRC_FILES中增加 core/java/android/os/IIICService.aidl

编译命令: mmm frameworks/base


下面是AIDL的实现方法类:com.android.server.IICService 位置为:frameworks/base/services/java/com/android/server 代码如下:

  1. package com.android.server;    
  2. import android.content.Context;    
  3. import android.os.IIICService;    
  4. import android.util.Slog;    
  5. public class IICService extends IIICService.Stub {    
  6.     private static final String TAG = "IICService";    
  7.     IICService() {    
  8.         init_native();    
  9.     }    
  10.     public void setVal(String val,int slaveAddr, int regAddr, int len) {    
  11.         setVal_native(val, slaveAddr, regAddr, len);    
  12.     }       
  13.     public String getVal(int slaveAddr,int len) {    
  14.         return getVal_native( slaveAddr, len);    
  15.     }    
  16.        
  17.     //本地方法   
  18.     private static native boolean init_native();    
  19.     private static native void setVal_native(String val, int slaveAddr, int regAddr, int len);    
  20.     private static native String getVal_native(int slaveAddr, int len);    
  21. };   
从代码中我们可以看到它继承了IIICService.Stub,实现两个接口方法。因为硬件访问一般需要放在一个独立的线程中,这里使用了代理的方法来处理app与硬件服务的通信。

最后需要把新增的IICService服务加入到ServiceManager中,这样就可以通过ServiceManager进行调用。

修改frameworks/base/services/java/com/android/server下的SystemServer.java  在run()方法中添加

try{

    Slog.i(TAG, "IIC SERVICE");

    ServiceManager.addService("iic", new IICService());

}catch(Throwable e){

    Slog.e(TAG, "Failure starting IIC Service", e);

}
编译命令:mmm frameworks/base/services/java

或者使用另一种形式来调用服务:如同使用binder机制绑定service一样的方法, 具体就不详细写了。 


注意:有可能会编译不通过,因为这里修改了android的官方api, 需要运行make update-api更新frameworks/base/api/current.xml

打包后,app就可以使用IICService接口来访问硬件了。
下一节发上app相关代码

(待续)


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