在jni.h中,JNIEnv的定义如下:
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif
/*
* 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); }
/*
* wrapper for JNINativeInterface
*/
}
在C语言编译环境下,JNIEnv定义为指向JNINativeInterface结构体的指针。
而在C++编译环境下,JNIEnv定义为_JNIEnv 结构体, _JNIEnv 是对JNINativeInterface结构体的封装, 最终会调用JNINativeInterface中的函数。
由此引出下面两个问题:
一、C/C++下JNIEnv函数的调用形式
我们知道,在C++环境下,结构体与类相同,都有this指针,以NewStringUTF函数为例,在C环境下,其调用形式如下:
(*env)->NewStringUTF(env, "From native to java"); //解引用得到JNINativeInterface类型的指针,然后调用JNINativeInterface中对应的函数
而在C++环境下,其调用形式则为:
env->NewStringUTF("From native to java"); //env为_JNIEnv类的指针,调用_JNIEnv类对应的成员函数
二、C/C++下的编译
我们知道,JNIEnv函数的实现最终会被编译到在libdvm中,而我们在编写自己的apk时,不可能再去重新编译libdvm,那么C++下,JNIEnv对JNINativeInterface的封装代码编译到哪里了?答案是编译到本地库中。
仍以NewStringUTF函数为例,在C语言编译环境下,编译后的代码如下:
.text:00000CF8 LDR R3, [SP,#0x20+var_1C] .text:00000CFA LDR R2, [R3] ;解引用env得到JNINativeInterface指针 .text:00000CFC MOVS R3, 0x29C .text:00000D00 LDR R2, [R2,R3] ;JNINativeInterface偏移0x29C个字节,找到对应的函数NewStringUTF .text:00000D02 LDR R1, [SP,#0x20+var_1C] .text:00000D04 LDR R3, =(aFromNativeToJa - 0xD0A) .text:00000D06 ADD R3, PC ; "From native to java" .text:00000D08 MOVS R0, R1 ;准备参数 .text:00000D0A MOVS R1, R3 .text:00000D0C BLX R2 ;调用NewStringUTF
在C语言环境下,通过env找到NewStringUTF函数,然后直接调用。
在C++编译环境下,编译后的代码如下:
.text:00000EEE LDR R3, =(aFromNativeToJa - 0xEF4)
.text:00000EF0 ADD R3, PC ; "From native to java"
.text:00000EF2 MOVS R0, R2
.text:00000EF4 MOVS R1, R3
.text:00000EF6 BL _ZN7_JNIEnv12NewStringUTFEPKc ; _JNIEnv::NewStringUTF(char const*)
;......
.text:00000E98 ; _JNIEnv::NewStringUTF(char const*)
.text:00000E98 var_10 = -0x10
.text:00000E98 var_C = -0xC
.text:00000E98
.text:00000E98 PUSH {LR}
.text:00000E9A SUB SP, SP, #0xC
.text:00000E9C STR R0, [SP,#0x10+var_C] ;R0为this指针,指向_JNIEnv结构体
.text:00000E9E STR R1, [SP,#0x10+var_10]
.text:00000EA0 LDR R3, [SP,#0x10+var_C]
.text:00000EA2 LDR R2, [R3] ;获取_JNIEnv结构体的第一个成员,即struct JNINativeInterface* functions;
.text:00000EA4 MOVS R3, 0x29C
.text:00000EA8 LDR R3, [R2,R3] ;functions偏移0x293个字节,找到对应函数NewStringUTF
.text:00000EAA LDR R1, [SP,#0x10+var_C]
.text:00000EAC LDR R2, [SP,#0x10+var_10]
.text:00000EAE MOVS R0, R1 ;准备参数
.text:00000EB0 MOVS R1, R2
.text:00000EB2 BLX R3 ;调用JNINativeInterface中NewStringUTF
.text:00000EB4 MOVS R3, R0
.text:00000EB6 MOVS R0, R3
.text:00000EB8 ADD SP, SP, #0xC
.text:00000EBA POP {PC}
.text:00000EBA ; End of function _JNIEnv::NewStringUTF(char const*)
可见,在C++中,编译器为我们编译了一个“壳子函数”:_JNIEnv::NewStringUTF(char const*)。该函数对应的C++源代码就是jni.h中_JNIEnv::NewStringUTF的实现:
jstring NewStringUTF(const char* bytes)
{ return functions->NewStringUTF(this, bytes); }
浙公网安备 33010602011771号