NDK(13)JNIEnvとJavaVM

10289 ワード


回転: http://www.cnblogs.com/canphp/archive/2012/11/13/2768937.html
 
JNIEnvはスレッドに関する変数であり、異なるスレッドのJNIEnvは互いに独立している.JavaVMはJNI層における仮想マシンの代表であり、一つの仮想マシンのプロセスにはJavaVMしかないので、このプロセスのすべてのスレッドはこのJavaVMを使用することができる.バックグラウンドスレッドがJNI nativeを呼び出す必要がある場合、nativeライブラリでグローバル変数を使ってJavaVMを保存することが特に重要であり、バックグラウンドスレッドがJavaVMを介してJNIEnvを取得することができる.(この言葉は「Android巻1を深く理解する」第二章の内容を引用しています.)
nativeプログラムではJNIEnv*とJavaVM*が頻繁に使われています.CとC++コードはJNIEnv*とJavaVM*という2つの指針を使うやり方に違いがあります.ネット上のほとんどのコードはC++を使っています.CとC++についての詳細な説明はほとんど見つからないです.
Cにおいて:
JNIEnv*envを使ってこのようにします.      (*env)->メソッド名(env,パラメータリスト)
JavaVM*vmを使ってこのようにします.       (*vm)->メソッド名(vm,パラメータリスト)
C++中:
JNIEnv*envを使ってこのようにします.      env->メソッド名(パラメータリスト)
JavaVM*vmを使ってこのようにします.       vm->メソッド名(パラメータリスト)
上記の2つの違いは、Cではまずenvとvmを間接的にアドレス指定しなければなりません.(得られた内容は依然としてポインタです.)方法を呼び出す時にenvまたはvmを最初のパラメータとして導入します.C++は直接にenvとvmポインタを利用してそのメンバーを呼び出します.Cの(*env)とC++のenvは同じタイプのデータがありますか?Cの(*vm)とC++のvmは同じタイプのデータがありますか?
上記の推測を検証するために、JNIEnvとJavaVMの定義を確認することができます.彼らはヘッドファイルのjni.hにいます.私はJNIを開発しています.android-5のプラットフォームを使っています.下は$NDK\plotforms\android-5\arch-arm\usr\include\jni.hの部分コードです.
 1 struct _JNIEnv;
 2 struct _JavaVM;
 3 #if defined(__cplusplus)  
 4 typedef _JNIEnv JNIEnv;                             //C++      
 5 typedef _JavaVM JavaVM;                             //C++      
 6 #else
 7 typedef const struct JNINativeInterface* JNIEnv;    //C      
 8 typedef const struct JNIInvokeInterface* JavaVM;    //C        
 9 
10 #endif  
11 struct JNINativeInterface
12 
13 {
14 
15     /****      ****/
16 
17     jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
18 
19     /****      ****/
20 
21     jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);
22 
23     /****      ****/
24 
25 };
26 
27 struct _JNIEnv {
28     const struct JNINativeInterface* functions;
29 #if defined(__cplusplus)  
30     /****      ****/
31     jmethodID GetMethodID(jclass clazz, const char* name, const char* sig) {
32         return functions->GetMethodID(this, clazz, name, sig);
33     }
34     /****      ****/
35     jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) {
36         return functions->GetStaticObjectField(this, clazz, fieldID);
37     }
38     /****      ****/
39 #endif /*__cplusplus*/  
40 };
41 
42 struct JNIInvokeInterface {
43     /****      ****/
44     jint (*GetEnv)(JavaVM*, void**, jint);
45     jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);
46 };
47 
48 struct _JavaVM {
49     const struct JNIInvokeInterface* functions;
50 #if defined(__cplusplus)  
51     /****      ****/
52     jint GetEnv(void** env, jint version) {
53         return functions->GetEnv(this, env, version);
54     }
55     jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args) {
56         return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args);
57     }
58 #endif /*__cplusplus*/  
59 };
 
もし私たちがCでコードすれば、マクロ_ucplusは定義されていません.一番上のマクロから推測できます.
JNIEniv    代表的なconst struct JNINativeInterface*
JavaVM   代表的なconst struct JNIInvoke Interface*
じゃ、JNIEnv*envは実は声明const struct JNINativeInterface*.  エンv
JavaVM*vmは、実は声明const struct JNI Invoke Interface**vmに相当します.
したがって、JNINativeInterface構造体の関数ポインタを呼び出すには、まずenvに対して間接的にアドレスを探さなければならない.
(*env)のタイプは、const struct JNINativeInterface*(JNINativeInterface構造体を指すポインタ)です.このとき、このポインタで構造体のメンバー関数ポインタを呼び出すことができます.同理論はJavaVM*vmを分析することができる.
--------------------------------------------------------------------------------
もし私たちがC++でコード化すれば、マクロ_cplusには定義がありますが、一番上のマクロから推測できます.
JNIEniv    代表タイプのstructuJNIEniv
JavaVM   代表タイプのstructuJavaVM
じゃJNIEnv*envは事実上structに相当します.JNIEniv*  エンv
JavaVM*vmは事実上structを宣言するのに相当します.JavaVM*vm
コールしたいですJNIEnv構造の体内の関数ポインタはこれは直接にenvを使って間接的にアドレスを探す必要がなくて、env->Get MethodID(jclass、const char*、const char*)です.同理論はJavaVM*vmを分析することができる.
今は先ほどの推測に答えられます.Cのタイプはconst struct JNINativeInterface*、C++の中のenvタイプはstructです.JNIEnv*は、データのタイプが違っています.
構造体をもう一度見ます.JNIEns(C++のJNIEnsが代表するタイプ)は、この構造の中にメンバーの一人であるconst struct JNINativeInterface*functionsがあります.JNIEnv内で定義されている関数.呼び出し時JNIEnvで定義されている関数は、実際にはfunctionsというポインタでJNINativeInterface内の関数ポインタを呼び出します.JNIEVのメンバー方法はJNINativeInterfaceの同名メンバー関数の指針の包装だけです.結局はCでもCでも+でもJNI NativeInterface構造体が使われています.このときJNINativeInterfaceを呼び出す関数ポインタの第一パラメータはthisで、C++の中でthisは現在のコンテキストオブジェクトを指すポインタのタイプはstruct_です.JNIEnv*(JNIEnv*)同じ道理で分析できるJavaVM
 
転載先:https://www.cnblogs.com/sjjg/p/4743824.html