Android系統開發(二)JNI

前言

    在嵌入式底層工程師的世界裏JNI就是java跟c/c++世界溝通的橋樑,包括我也是這樣認爲了很多年;前幾天跟做app的同事聊天,無意中發現在他們的知識體系中jni是Java世界和Native世界的媒介。"Native"沒錯這個纔是理解的關鍵。在java語言出現之前,就有很多程序和庫都是由Native語言寫的,利用現有的庫開發事半功倍同時可以保證更好的性能。 就是好比Android的底層是linux內核——c語言世界的極致表達。 今天整理一下JNI。

一、通過一個案例開始說起吧java讓c說聲"Hello world!"

1、java

public class JavaSayHello{
	/*通過構造塊來加載C庫*/
	static{
		System.loadLibrary("native");
	}
	public native String java_say_to_c(String str); //聲明爲native方法
	
	public static void main (String args[]){
		JavaSayHello oTmp = new JavaSayHello(); //執行此句話時會調用構造塊
        /*調用c中的映射的函數打印Hello world!*/
	System.out.println(oTmp.java_say_to_c("Hello world!"))
    }
}

2、c (c程序裏的工作量比較多,包括建立映射表、JNI加載C庫、被調用的c程序)

1)映射表結構

static const JNINativeMethod methods[] = {
	{"java_say_to_c", "(Ljava/lang/String;)Ljava/lang/String;", (void *)c_get_from_java},
};

2)c程序

jstring JNICALL c_get_from_java(JNIEnv *env, jobject cls, jstring str)
{
	const jbyte *cstr;
	cstr = (*env)->GetStringUTFChars(env, str, NULL);
	if (cstr == NULL) {
		return NULL; /* OutOfMemoryError already thrown */
	}
	printf("Get string from java :%s\n", cstr);
	(*env)->ReleaseStringUTFChars(env, str, cstr);

	return (*env)->NewStringUTF(env, "This is c env return...\n");
}

3)系統加載c函數

/* System.loadLibrary */
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
	JNIEnv *env;
	jclass cls;

	if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {
		return JNI_ERR; /* JNI version not supported */
	}
	cls = (*env)->FindClass(env, "JavaSayHello");
	if (cls == NULL) {
		return JNI_ERR;
	}

	/* 2. map (java) java_say_to_c<-->(c) c_get_from_java*/
	if ((*env)->RegisterNatives(env, cls, methods, 1) < 0) //這個數字1代表映射了一個方法映射數組的個數
		return JNI_ERR;

	return JNI_VERSION_1_4;
}

基本邏輯可以理解爲:

1、java在實例化對象oTmp時構造塊會加載C庫(System.loadLibrary("native");)

2、JNI_OnLoad會先獲取java環境,通過環境找到java中的類(這部分自己理解),然後通過methods建立的數組映射表,建立一一映射關係。

3、在java中調用 方法,方法通過映射找到函數,然後調用對應的c函數。

二、實際編譯運行測試:

1、

編譯c文件 native.c: gcc -I /home/bupt/miao/box/soft/java-7-openjdk-amd64/include/ -fPIC -shared -o libnative.so native.c

-I /home/bupt/miao/box/soft/java-7-openjdk-amd64/include/ 是指定編譯的中jni.h的路徑,根據自己的JDK安裝路徑選擇。

2、

編譯java:javac JavaSayHello.java
注:編譯錯誤

Exception in thread "main" java.lang.UnsatisfiedLinkError: no native in java.library.path
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1889)
	at java.lang.Runtime.loadLibrary0(Runtime.java:849)
	at java.lang.System.loadLibrary(System.java:1088)
	at JavaSayHello.<clinit>(JavaSayHello.java:4)
 解決方法:
export LD_LIBRARY_PATH=.
運行結果:
bupt@machine:~/miao/project/android/jni/myJNI$ java JavaSayHello 
Get string from java :Hello world!
This is c env return ...
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章