600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > NDK(13)JNIEnv和JavaVM

NDK(13)JNIEnv和JavaVM

时间:2021-08-01 17:15:59

相关推荐

NDK(13)JNIEnv和JavaVM

转自: /canphp/archive//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*这两个指针的做法是有区别的,网上大部分代码都使用C++,基本上找不到关于C和C++在这个问题上的详细叙述。

在C中:

使用JNIEnv* env要这样 (*env)->方法名(env,参数列表)

使用JavaVM* vm要这样 (*vm)->方法名(vm,参数列表)

在C++中:

使用JNIEnv* env要这样 env->方法名(参数列表)

使用JavaVM* vm要这样 vm->方法名(参数列表)

上面这二者的区别是,在C中必须先对env和vm间接寻址(得到的内容仍然是一个指针),在调用方法时要将env或vm传入作为第一个参数。C++则直接利用env和vm指针调用其成员。那到底C中的(*env)和C++中的env是否有相同的数据类型呢?C中的(*vm) 和C++中的vm是否有相同的数据类型呢?

为了验证上面的猜测,我们可以查看JNIEnv和JavaVM的定义。他们位于头文件jni.h。我开发JNI用的是android-5平台,下面是 $NDK\platforms\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 JNINativeInterface12 13 {14 15/****省略了的代码****/16 17jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);18 19/****省略了的代码****/20 21jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);22 23/****省略了的代码****/24 25 };26 27 struct _JNIEnv {28const struct JNINativeInterface* functions;29 #if defined(__cplusplus) 30/****省略了的代码****/31jmethodID GetMethodID(jclass clazz, const char* name, const char* sig) {32 return functions->GetMethodID(this, clazz, name, sig);33}34/****省略了的代码****/35jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) {36 return functions->GetStaticObjectField(this, clazz, fieldID);37}38/****省略了的代码****/39 #endif /*__cplusplus*/ 40 };41 42 struct JNIInvokeInterface {43/****省略了的代码****/44jint (*GetEnv)(JavaVM*, void**, jint);45jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);46 };47 48 struct _JavaVM {49const struct JNIInvokeInterface* functions;50 #if defined(__cplusplus) 51/****省略了的代码****/52jint GetEnv(void** env, jint version) {53 return functions->GetEnv(this, env, version);54}55jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args) {56 return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args);57}58 #endif /*__cplusplus*/ 59 };

假如我们用C编码,宏__cplusplus没有定义,那么从最上面的宏#if defined(__cplusplus)可推断

JNIEnv 代表类型 const struct JNINativeInterface*

JavaVM 代表类型 const struct JNIInvokeInterface*

那么JNIEnv* env实际上等价于声明 const struct JNINativeInterface** env

JavaVM* vm实际上等价于声明 const struct JNIInvokeInterface ** vm

因此要调用JNINativeInterface结构体内的函数指针就必须先对env间接寻址。

(*env)的类型是const struct JNINativeInterface*(指向JNINativeInterface结构体的指针),这时候可以用这个指针调用结构体的成员函数指针,(*env)-> GetMethodID(env, jclass, const char*, const char*)。同理可分析JavaVM* vm。

----------------------------------------------------------------------------------------------------------------------------------------------

假如我们用C++编码,宏__cplusplus有定义,那么从最上面的宏#if defined(__cplusplus)可推断

JNIEnv 代表类型 struct _JNIEnv

JavaVM 代表类型 struct _JavaVM

那么JNIEnv* env实际上等价于声明 struct _JNIEnv* env

JavaVM* vm实际上等价于声明 struct _JavaVM* vm

要调用_JNIEnv结构体内的函数指针这直接使用env而不需间接寻址, env-> GetMethodID(jclass, const char*, const char*)。同理可分析JavaVM* vm。

现在可以回答刚才的猜测了,C中的(*env)类型是const struct JNINativeInterface*,C++中的env类型是struct _JNIEnv*,因此他们的数据类型不相同(虽然都是指针,但指向不同的结构体类型)。

我们再看结构体_JNIEnv(C++的JNIEnv所代表的类型),这个结构体内有一个成员const struct JNINativeInterface* functions,再仔细看_JNIEnv内定义的函数。当调用_JNIEnv内定义的函数时,其实就是通过functions这个指针调用JNINativeInterface内的函数指针,因此_JNIEnv的成员方法是JNINativeInterface的同名成员函数指针的包装而已,归根结底无论在C还是C++中其实都使用了JNINativeInterface结构体。这时调用JNINativeInterface的函数指针的第一参数是this,在C++中this代表指向当前上下文对象的指针其类型是struct _JNIEnv*(即JNIEnv*)。同理可分析_JavaVM。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。
相关阅读
JNIEnv与JavaVM

JNIEnv与JavaVM

2022-04-25

JavaVM和JNIEnv

JavaVM和JNIEnv

2019-04-29

09-JavaVM与JNIEnv

09-JavaVM与JNIEnv

2023-10-09

浅谈 JNIEnv 和 JavaVM

浅谈 JNIEnv 和 JavaVM

2022-01-05