.android
jni.h文件 : 瞭解 JNI 需要配合 jni.h 文件, jni.h 是 Google NDK 中的一個文件, 位置是 $/android-ndk-r9d/platforms/android-19/arch-arm/usr/include/jni.h ;數組
JNIEnv 概念 : 是一個線程相關的結構體, 該結構體表明瞭 Java 在本線程的執行環境 ; app
JNIEnv 與 JavaVM : 注意區分這兩個概念; 函數
-- JavaVM : JavaVM 是 Java虛擬機在 JNI 層的表明, JNI 全局僅僅有一個;post
-- JNIEnv : JavaVM 在線程中的表明, 每個線程都有一個, JNI 中可能有很是多個 JNIEnv;this
JNIEnv 做用 : spa
-- 調用 Java 函數 : JNIEnv 表明 Java 執行環境, 可以使用 JNIEnv 調用 Java 中的代碼;線程
-- 操做 Java 對象 : Java 對象傳入 JNI 層就是 Jobject 對象, 需要使用 JNIEnv 來操做這個 Java 對象;指針
JNIEnv 建立 和 釋放 : 從 JavaVM 得到 : 如下是 JavaVM 結構體的代碼, code
-- C語言 中來源 : JNIInvokeInterface 是 C 語言環境中的 JavaVM 結構體, 調用 (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*) 方法, 可以獲取 JNIEnv結構體;
-- C++ 中來源 : _JavaVM 是 C++ 中的 JavaVM 結構體, 調用 jint AttachCurrentThread(JNIEnv** p_env, void* thr_args) 方法, 可以獲取 JNIEnv 結構體;
-- C語言 中釋放 : 調用 JavaVM結構體 (JNIInvokeInterface) 中的 (*DetachCurrentThread)(JavaVM*)方法, 可以釋放本線程中的 JNIEnv;
-- C++ 中釋放 : 調用 JavaVM 結構體 (_JavaVM) 中的 jint DetachCurrentThread(){ return functions->DetachCurrentThread(this); } 方法, 就能夠釋放 本線程中的 JNIEnv ;
/* * JNI invocation interface. */ struct JNIInvokeInterface { void* reserved0; void* reserved1; void* reserved2; jint (*DestroyJavaVM)(JavaVM*); /* 建立 JNIEnv , 每個線程建立一個 */ jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*); /* 釋放本線程的 JNIEnv */ jint (*DetachCurrentThread)(JavaVM*); jint (*GetEnv)(JavaVM*, void**, jint); jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*); }; /* * C++ version. */ struct _JavaVM { const struct JNIInvokeInterface* functions; #if defined(__cplusplus) jint DestroyJavaVM() { return functions->DestroyJavaVM(this); } /* 建立 JNIEnv , 每個線程建立一個 , 調用的C語言結構提中的方法, C 與 C++ 方法一樣 */ jint AttachCurrentThread(JNIEnv** p_env, void* thr_args) { return functions->AttachCurrentThread(this, p_env, thr_args); } /* 釋放本線程的 JNIEnv , 調用的C語言結構提中的方法, C 與 C++ 方法一樣 */ jint DetachCurrentThread() { return functions->DetachCurrentThread(this); } jint GetEnv(void** env, jint version) { return functions->GetEnv(this, env, version); } jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args) { return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); } #endif /*__cplusplus*/ };
線程相關 : JNIEnv 是線程相關的, 即 在 每個線程中 都有一個 JNIEnv 指針, 每個JNIEnv 都是線程專有的, 其餘線程不能使用本線程中的 JNIEnv, 線程 A 不能調用 線程 B 的 JNIEnv;
JNIEnv 不能跨線程 :
-- 當前線程有效 : JNIEnv 僅僅在當前線程有效, JNIEnv 不能在 線程之間進行傳遞, 在同一個線程中, 屢次調用 JNI層方法, 傳入的 JNIEnv 是一樣的;
-- 本地方法匹配多JNIEnv : 在 Java 層定義的本地方法, 可以在不一樣的線程調用, 所以 可以接受不一樣的 JNIEnv;
JNIEnv 結構 : 由上面的代碼可以得出, JNIEnv 是一個指針, 指向一個線程相關的結構, 線程相關結構指向 JNI 函數指針 數組, 這個數組中存放了大量的 JNI 函數指針, 這些指針指向了詳細的 JNI 函數;
JNIEnv 定義的相關代碼 :
/* 聲明結構體, 以便在如下可以使用 */
struct _JNIEnv;
struct _JavaVM;
/* 聲明 C 語言環境中的 JNIEnv 爲 C_JNIEnv 指針, 指向 JNINativeInterface 結構體 */
typedef const struct JNINativeInterface* C_JNIEnv;
#if defined(__cplusplus)
/* C++環境下, JNIEnv 是結構體 */
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
/* C語言環境下, JNIEnv是指針 */
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif
-- JNINativeInterface 結構體 : 該結構體中定義了大量的函數指針, 這些函數指針 指向 與 Java 相關的變量有關的函數, 假設是 C 語言環境中, JNIEnv 就是指向 該結構體的指針;
-- _JNIEnv 結構體 : C++ 環境中的 JNIEnv 就是該結構體, 該結構體中封裝了 一個 JNINativeInterface 結構體指針, 即 C++ 中的 JNIEnv 要比 C 語言中的要多, 並且 全然兼容 C 語言中的 JNIEnv;
-- _JavaVM 結構體 : 該結構體 是 Java 虛擬機 在 JNI 中的表明, 整個 JNI 層 僅僅存在一個 該 虛擬機映射;
JNINativeInterface 源代碼(刪減過) : 省略後的, 當中定義了 與 Java 有關的相關方法, 都是 指向相應函數的函數指針;
-- 解析 JNIEnv* : C語言環境中的 typedef const struct JNINativeInterface* JNIEnv , JNIEnv* env 等價於 JNINativeInterface** env1 (指向結構體地址的指針), 要想 依據 二級指針 env1 獲取 JNINativeInterface 結構體中定義的函數指針, 首先獲取 指向結構體的一級指針, 獲取方法是 (*env1), 所以調用當中的函數指針指向的方法要這樣 : (*env1)->FindClass(JNIEnv*, const char*);
/* * Table of interface function pointers. */ struct JNINativeInterface { void* reserved0; void* reserved1; void* reserved2; void* reserved3; jint (*GetVersion)(JNIEnv *); ... ... jobject (*NewDirectByteBuffer)(JNIEnv*, void*, jlong); void* (*GetDirectBufferAddress)(JNIEnv*, jobject); jlong (*GetDirectBufferCapacity)(JNIEnv*, jobject); /* added in JNI 1.6 */ jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject); };
_JNIEnv 源代碼(刪減過) : 該源代碼中有一個 JNINativeInterface 結構體指針, 說明 C++ 環境的 JNIEnv 是在 C 語言環境的 JNIEnv 下擴展的;
-- 解析 JNIEnv* : 定義是這種 typedef _JNIEnv JNIEnv, JNIEnv* env 等價於 _JNIEnv* env1, 所以調用 _JNIEnv 中定義的函數指針指向的函數的時候, 僅僅需要 使用 env1->FindClass(JNIEnv*, const char*) 就能夠;
/* * C++ object wrapper. * * This is usually overlaid on a C struct whose first element is a * JNINativeInterface*. We rely somewhat on compiler behavior. */ struct _JNIEnv { /* do not rename this; it does not seem to be entirely opaque */ const struct JNINativeInterface* functions; #if defined(__cplusplus) jint GetVersion() { return functions->GetVersion(this); } ... ... jlong GetDirectBufferCapacity(jobject buf) { return functions->GetDirectBufferCapacity(this, buf); } /* added in JNI 1.6 */ jobjectRefType GetObjectRefType(jobject obj) { return functions->GetObjectRefType(this, obj); } #endif /*__cplusplus*/ };