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