【Android 系统开发】Android JNI 之 JNIEnv 解析
.
jni.h文件 : 了解 JNI 需要配合 jni.h 文件, jni.h 是 Google NDK 中的一個文件, 位置是 $/android-ndk-r9d/platforms/android-19/arch-arm/usr/include/jni.h ;
1. JNIEnv 作用
JNIEnv 概念 : 是一個線程相關(guān)的結(jié)構(gòu)體, 該結(jié)構(gòu)體代表了 Java 在本線程的運行環(huán)境 ;?
JNIEnv 與 JavaVM : 注意區(qū)分這兩個概念;?
-- JavaVM : JavaVM 是 Java虛擬機在 JNI 層的代表, JNI 全局只有一個;
-- JNIEnv : JavaVM 在線程中的代表, 每個線程都有一個, JNI 中可能有很多個 JNIEnv;
JNIEnv 作用 :?
-- 調(diào)用 Java 函數(shù) : JNIEnv 代表 Java 運行環(huán)境, 可以使用 JNIEnv 調(diào)用 Java 中的代碼;
-- 操作 Java 對象 : Java 對象傳入 JNI 層就是 Jobject 對象, 需要使用 JNIEnv 來操作這個 Java 對象;
2. JNIEnv 的創(chuàng)建和釋放
JNIEnv 創(chuàng)建 和 釋放?:?從 JavaVM 獲得 : 下面是 JavaVM 結(jié)構(gòu)體的代碼,?
-- C語言 中來源 : JNIInvokeInterface 是 C 語言環(huán)境中的 JavaVM 結(jié)構(gòu)體, 調(diào)用?(*AttachCurrentThread)(JavaVM*, JNIEnv**, void*) 方法, 可以獲取 JNIEnv結(jié)構(gòu)體;
-- C++ 中來源 :?_JavaVM 是 C++ 中的 JavaVM 結(jié)構(gòu)體, 調(diào)用?jint AttachCurrentThread(JNIEnv** p_env, void* thr_args) 方法, 可以獲取 JNIEnv 結(jié)構(gòu)體;
-- C語言 中釋放 : 調(diào)用 JavaVM結(jié)構(gòu)體 (JNIInvokeInterface) 中的?(*DetachCurrentThread)(JavaVM*)方法, 可以釋放本線程中的 JNIEnv;
-- C++ 中釋放 : 調(diào)用 JavaVM 結(jié)構(gòu)體 (_JavaVM) 中的?jint DetachCurrentThread(){ return functions->DetachCurrentThread(this); } 方法, 即可釋放 本線程中的 JNIEnv ;
/** JNI invocation interface.*/ struct JNIInvokeInterface {void* reserved0;void* reserved1;void* reserved2;jint (*DestroyJavaVM)(JavaVM*);/* 創(chuàng)建 JNIEnv , 每個線程創(chuàng)建一個 */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); }/* 創(chuàng)建 JNIEnv , 每個線程創(chuàng)建一個 , 調(diào)用的C語言結(jié)構(gòu)提中的方法, C 與 C++ 方法相同 */jint AttachCurrentThread(JNIEnv** p_env, void* thr_args){ return functions->AttachCurrentThread(this, p_env, thr_args); }/* 釋放本線程的 JNIEnv , 調(diào)用的C語言結(jié)構(gòu)提中的方法, 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*/ };
3. JNIEnv 體系結(jié)構(gòu)?
線程相關(guān)?: JNIEnv 是線程相關(guān)的, 即 在 每個線程中 都有一個 JNIEnv 指針, 每個JNIEnv 都是線程專有的, 其它線程不能使用本線程中的 JNIEnv, 線程 A 不能調(diào)用 線程 B 的 JNIEnv;
JNIEnv 不能跨線程 :?
-- 當(dāng)前線程有效 : JNIEnv 只在當(dāng)前線程有效, JNIEnv 不能在 線程之間進(jìn)行傳遞, 在同一個線程中, 多次調(diào)用 JNI層方法, 傳入的 JNIEnv 是相同的;
-- 本地方法匹配多JNIEnv : 在 Java 層定義的本地方法, 可以在不同的線程調(diào)用, 因此 可以接受不同的 JNIEnv;
JNIEnv 結(jié)構(gòu) : 由上面的代碼可以得出, JNIEnv 是一個指針, ?指向一個線程相關(guān)的結(jié)構(gòu), 線程相關(guān)結(jié)構(gòu)指向 JNI 函數(shù)指針 數(shù)組, 這個數(shù)組中存放了大量的 JNI 函數(shù)指針, 這些指針指向了具體的 JNI 函數(shù);?
4. 分析 JNIEnv 相關(guān)代碼
JNIEnv 定義的相關(guān)代碼?:?
/* 聲明結(jié)構(gòu)體, 以便在下面能夠使用 */ struct _JNIEnv; struct _JavaVM; /* 聲明 C 語言環(huán)境中的 JNIEnv 為 C_JNIEnv 指針, 指向 JNINativeInterface 結(jié)構(gòu)體 */ typedef const struct JNINativeInterface* C_JNIEnv;#if defined(__cplusplus) /* C++環(huán)境下, JNIEnv 是結(jié)構(gòu)體 */ typedef _JNIEnv JNIEnv; typedef _JavaVM JavaVM; #else /* C語言環(huán)境下, JNIEnv是指針 */ typedef const struct JNINativeInterface* JNIEnv; typedef const struct JNIInvokeInterface* JavaVM; #endif
--?JNINativeInterface 結(jié)構(gòu)體 : 該結(jié)構(gòu)體中定義了大量的函數(shù)指針, 這些函數(shù)指針 指向 與 Java 相關(guān)的變量有關(guān)的函數(shù), 如果是 C 語言環(huán)境中, JNIEnv 就是指向 該結(jié)構(gòu)體的指針;
-- _JNIEnv 結(jié)構(gòu)體 : C++ 環(huán)境中的 JNIEnv 就是該結(jié)構(gòu)體, 該結(jié)構(gòu)體中封裝了 一個?JNINativeInterface 結(jié)構(gòu)體指針, 即 C++ 中的 JNIEnv 要比 C 語言中的要多, 并且 完全兼容 C 語言中的 JNIEnv;
-- _JavaVM 結(jié)構(gòu)體 : 該結(jié)構(gòu)體 是 Java 虛擬機 在 JNI 中的代表, 整個 JNI 層 只存在一個 該 虛擬機映射;
JNINativeInterface 源碼(刪減過) : 省略后的, 其中定義了 與 Java 有關(guān)的相關(guān)方法, 都是 指向?qū)?yīng)函數(shù)的函數(shù)指針;
-- 解析 JNIEnv* : C語言環(huán)境中的?typedef const struct JNINativeInterface* JNIEnv , JNIEnv* env 等價于?JNINativeInterface** env1 (指向結(jié)構(gòu)體地址的指針), 要想 根據(jù) 二級指針 env1 獲取?JNINativeInterface 結(jié)構(gòu)體中定義的函數(shù)指針, 首先獲取 指向結(jié)構(gòu)體的一級指針, 獲取方法是 (*env1), 因此調(diào)用其中的函數(shù)指針指向的方法要這樣 : (*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 結(jié)構(gòu)體指針, 說明 C++ 環(huán)境的 JNIEnv 是在 C 語言環(huán)境的 JNIEnv 下擴(kuò)展的;
-- 解析 JNIEnv* : 定義是這樣的?typedef _JNIEnv JNIEnv, JNIEnv* env 等價于 _JNIEnv* env1, 因此調(diào)用 _JNIEnv 中定義的函數(shù)指針指向的函數(shù)的時候, 只需要 使用 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*/ };
總結(jié)
以上是生活随笔為你收集整理的【Android 系统开发】Android JNI 之 JNIEnv 解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Unity 3D 游戏开发】Unity
- 下一篇: 【网络安全】网络安全攻防 -- 黑客攻击