二、 使用JNI在应用程序框架层添加服务访问接口
APP应用不能直接访问HAL层,需要JNI层访问HAL模块并向上提供API接口。可以直接提供接口,但建议最好使用服务的方式提供访问。
我们先看JNI如何访问刚才的HAL模块。
进入源码根目录下的frameworks/base/service/jni目录,新建com_android_server_IICService.cpp,代码如下:
- #include "jni.h"
- #include "JNIHelp.h"
- #include "android_runtime/AndroidRuntime.h"
- #include <utils/misc.h>
- #include <cutils/log.h>
- #include <hardware/hardware.h>
- #include <hardware/iic.h>
- #include <stdio.h>
-
- namespace android
- {
- /*在硬件抽象层中定义的硬件访问结构体,参考<hardware/iic.h>*/
- struct iic_device_t* iic_device = NULL;
- /*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/
- static void iic_setVal(JNIEnv* env, jobject clazz, jstring val, jint slaveAddr, jint subAddr, jint len) {
- const char *str = env->GetStringUTFChars(val, NULL);
- LOGI("iic JNI: set value %s to device.", str);
- if(!iic_device) {
- LOGI("iic JNI: device is not open.");
- return;
- }
- iic_device->iic_write(iic_device, (unsigned char*)str, slaveAddr, subAddr, len);
- env->ReleaseStringUTFChars(val, str); //注意释放资源
- }
-
- /*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/
- static jstring iic_getVal(JNIEnv* env, jobject clazz, jint slaveAddr, jint len) {
- unsigned char* data = (unsigned char*)malloc(len);
- iic_device->iic_read(iic_device, data, slaveAddr, len);
- if(!iic_device) {
- LOGI("iic JNI: device is not open.");
- }
- int i = 0;
- for(;i<strlen((const char*)data);i++){
- LOGI("data: %c ", data[i]);
- }
- //LOGI("iic JNI: get value %s from device @ %x address!", data, subAddr);
- jstring tmp = env->NewStringUTF((const char*)data);
- free(data);
- data = NULL;
- return tmp;
- }
-
- /*通过硬件抽象层定义的硬件模块open接口打开硬件设备*/
- static inline int iic_device_open(const hw_module_t* module, struct iic_device_t** device) {
- return module->methods->open(module, IIC_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
- }
- /*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/
- static jboolean iic_init(JNIEnv* env, jclass clazz) {
- iic_module_t* module;
-
- LOGI("iic JNI: initializing......");
- if(hw_get_module(IIC_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
- LOGI("iic JNI: iic Stub found.");
- if(iic_device_open(&(module->common), &iic_device) == 0) {
- LOGI("eeprom JNI: iic device is opening...");
- return 0;
- }
- LOGE("eeprom JNI: failed to open iic device.");
- return -1;
- }
- LOGE("eeprom JNI: failed to get iic stub module.");
- return -1;
- }
- /*JNI方法表*/
- static const JNINativeMethod method_table[] = {
- {"init_native", "()Z", (void*)iic_init},
- {"setVal_native", "(Ljava/lang/String;III)V", (void*)iic_setVal},
- {"getVal_native", "(III)Ljava/lang/String;", (void*)iic_getVal},
- };
- /*注册JNI方法*/
- int register_android_server_IICService(JNIEnv *env) {
- return jniRegisterNativeMethods(env, "com/android/server/IICService", method_table, NELEM(method_table));
- }
- };
然后需要让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 代码如下:
- package com.android.server;
- import android.content.Context;
- import android.os.IIICService;
- import android.util.Slog;
- public class IICService extends IIICService.Stub {
- private static final String TAG = "IICService";
- IICService() {
- init_native();
- }
- public void setVal(String val,int slaveAddr, int regAddr, int len) {
- setVal_native(val, slaveAddr, regAddr, len);
- }
- public String getVal(int slaveAddr,int len) {
- return getVal_native( slaveAddr, len);
- }
-
- //本地方法
- private static native boolean init_native();
- private static native void setVal_native(String val, int slaveAddr, int regAddr, int len);
- private static native String getVal_native(int slaveAddr, int len);
- };
从代码中我们可以看到它继承了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相关代码
(待续) 原文:http://blog.csdn.net/rickbeyond/article/details/7838313 如有侵权,请告知,谢谢。
|