博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

JniEnv在C与C++下的不同

Posted on 2014-04-28 16:03  scope  阅读(1884)  评论(0)    收藏  举报

   在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); }