应用层到驱动层的接口实现(二)

                                                                 ----应用框架层&&app应用层

     这里介绍的是应用框架层的实现和上层app应用层对已定义的JNI的调用方法(binder通讯)。主要介绍是JNI方法的具体实现和在Android的ApplicationFrameworks层增加API接口到app层,以至于让上层Application能够访问到硬件。

     当然,访问的前提是在硬件抽象层已实现对硬件驱动层的访问并提供了相应接口(详见上篇文章的介绍)。

    1. JNI方法&api接口的实现

        1.com _android_server的创建和修改

    创建:

在/framework/base/services/core/jni/下创建:com_android_server_SublcdService.cpp 内容如下:

//相应头文件的添加
#define LOG_TAG "SublcdService"
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
#include <hardware/sublcd.h>
#include <stdio.h>
namespace android
 {
	struct sublcd_device_t* sublcd_device = NULL;
	static void sublcd_setVal(JNIEnv* env, jobject clazz, jint value) {
		ALOGI("Sublcd JNI: sublcd_setVal");
		int val = value;
		ALOGI("Sublcd JNI: set value %d to device.", val);
		if(!sublcd_device) {
			ALOGI("Sublcd JNI: device is not open.");
			return;
		}
		sublcd_device->set_val(sublcd_device, val);
	}
static jint sublcd_getVal(JNIEnv* env, jobject clazz) {
		int val = 0;
		if(!sublcd_device) {
			ALOGI("Sublcd JNI: device is not open.");
			return val;
		}
		sublcd_device->get_val(sublcd_device, &val);
		ALOGI("Sublcd JNI: get value %d from device.", val);
		return val;
	}
static inline int sublcd_device_open(const hw_module_t* module, struct sublcd_device_t** device) {
		return module->methods->open(module, SUBLCD_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
	}
static jboolean sublcd_init(JNIEnv* env, jclass clazz) {
		sublcd_module_t* module;
		ALOGI("Sublcd JNI: initializing......");
			if(hw_get_module(SUBLCD_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
			ALOGI("Sublcd JNI: hello Stub found.");
				if(sublcd_device_open(&(module->common), &sublcd_device) == 0) {
					ALOGI("Sublcd JNI: hello device is open.");
					return 0;
				}
			ALOGI("Sublcd JNI: failed to open hello device.");
			return -1;
			}
		ALOGI("Sublcd JNI: failed to get hello stub module.");
		return -1;
	}
//Java Method VS C/C++ Method map
	static const JNINativeMethod method_table[] = {
		{"init_native", "()Z", (void*)sublcd_init},
		{"setVal_native", "(I)V", (void*)sublcd_setVal},
		{"getVal_native", "()I", (void*)sublcd_getVal},
	};
/*method of register JNI*/
	int register_android_server_SublcdService(JNIEnv *env) {
		return jniRegisterNativeMethods(env, "com/android/server/SublcdService", method_table, NELEM(method_table));
	}
};

修改:

1、/framework/base/services/core/jni/Android.mk

在LOCAL_SRC_FILES下添加:

$(LOCAL_REL_DIR)/com_android_server_SublcdService.cpp\

2、/framework/base/services/core/jni/onload.cpp

在namespaceandroid下添加:

intregister_android_server_SublcdService(JNIEnv *env);

在JNI_OnLoad下添加:

register_android_server_SublcdService(env);

代码解释

这里主要定义了四个函数:

sublcd_setVal:调用hardware下定义的set_val接口;

sublcd_getVal:调用hardware下定义的get_val接口;

sublcd_device_open:通过hardware下定义的硬件模块接口(open)打开硬件设备;

sublcd_init:初始化函数,通过在hardware下定义的硬件模块ID加载到hardware下编译生成的方法库文件(.so)。

最后定义JNI的方法表和注册JNI的方法:

staticconst JNINativeMethod method_table[]

intregister_android_server_SublcdService(JNIEnv *env)

其中方法表中便是C/C++的方法与java方法的对应。

   2. aidl的创建和修改

创建:

  1. 在/framework/base/services/core/java/com/android/server/下添加:

SublcdService.java

内容如下:

package com.android.server; 

import android.content.Context;  
import android.os.ISublcdService;  
import android.util.Slog; 

public class SublcdService extends ISublcdService.Stub { 
    private static final String TAG = "SublcdService.java";  
    SublcdService() {  
        init_native();  
    }  
    public void openSublcdTese(int val) { 
        setVal_native(val);  
    }   
    public int closeSublcdTese() {  
        return getVal_native();  
    }       
    private static native boolean init_native();  
    private static native void setVal_native(int val);  
    private static native int getVal_native();  
};

这里定义的SublcdService类主要是两个方面:

a/对在上面进行JNI方法注册时定义的C/C++&java方法表中的java方法进行声明,以此才能对其C/C++方法进行调用。这里需要注意的是对非系统加载JNI时,需要添加:

static {
 	   System.loadLibrary("库名");//载入本地库
 }

         b/定义类的方法供app应用层进行调用。

2、在/framework/base/core/java/android/os/下添加:ISublcdService.aidl 内容如下:

package android.os;

interface ISublcdService{
	void openSublcdTese(int val);
	int closeSublcdTese();
}

    修改:

1、/framework/base/Android.mk

将上面添加的.aidl添加到LOCAL_SRC_FILES下:

LOCAL_SRC_FILES+= \core/java/android/os/ISublcdService.aidl

至此,JNI的定义便完成了,主要是三个部分:

com_android_server_XxxService.cpp

XxxService.java

IXxxService.aidl

其中.cpp文件主要实现的是对硬件抽象层的访问的相应C方法定义和与其对应的java调用方法声明。

其中.classl部分便是定义其上面文件中声明的与C方法对应的java方法,也是我们在java中所要访问到C中所调用的接口方法。

在这里需要注意的是,android源码中对aidl/api的修改添加可能会造成代码编译不过,因为在framework/base/api/current.txt和framework/base/api/system-current.txt下有对系统定义的api的信息,但是编译不会将修改或者添加的api同步过来,这个时候需要做的是执行:

make update-api

      进行api的同步。

       3.为app添加硬件访问服务

     这里需要注意的是android下添加binderserver可能会抛出安全错误异常:PERMISSIONDENIED。这个时候我们需要在/external/sepolicy/service.te和/external/sepolicy/service_contexts下添加对该server的type定义。

   4.app层对接口的访问实现

在app应用层对framework层的访问(对classSublcdService调用)的实现是通过binder通讯服务对在上面的添加的binderserver进行获取,从而便可调用到SublcdService下的方法。

获取binderserver:

private ISublcdService sublcdService = null;
sublcdService = ISublcdService.Stub.asInterface(ServiceManager.getService("sublcd_test"));

方法调用:

try{
	int a = 1;
	sublcdService.openSublcdTese(a);
sublcdService.closeSublcdTese();
		}catch(RemoteException e){
}
}

至此,便完成了从app应用层到framework应用框架层的访问,结合上面的硬件抽象层的实现,便实现了从app到硬件驱动层的访问。

中间如果顺利的话,结合上一篇的Blog便能从log可以看到流程完整的能走到虚拟硬件层了,当然,如果有遇到什么问题的话,也希望能分享出来一些学习……