• JNI 的学习(一)对于 JNIEnv 的一些认识


    JNI 的学习(一)对于 JNIEnv 的一些认识

      Java 通过 JNI 机制调用 c/c++ 写的 native 程序。c/c++ 开发的 native 程序需要遵循一定的 JNI 规范,下面的例子就是一个 JNI 函数声明:

    1 JNIEXPORT jstring JNICALL Java_com_clay_example_JNITest_getJNIString
    2 (JNIEnv* env, jobject obj)

      JVM 负责从Java Stack 转入 C/C++ Native Stack。当 Java 进入 JNI 调用,除了函数本身的参数(arg0),会多出两个参数:JNIEnv 指针和 jobject 指针。而我们在Java端定义这个方法的时候,是没有参数的,如下:

    1 public native String printHello();

      JNIEnv 指针是 JVM 创建的,用于 Native的 c/c++ 方法操纵 Java 执行栈中的数据,比如 Java Class, Java Method 等。

      首先,JNI 对于JNIEnv 的使用, 提供了两种语法: c 语法以及 c++ 语法,如下:

      c 语法:

    1 jsize len = (*env)->GetArrayLength(env,array);

      c++ 语法:

    1 jsize len =env->GetArrayLength(array);
      那么这个 JNIEnv 是干什么用的?
      其实从这个参数的名称就可以看到,就是指 JNI 的运行环境,我觉得它就是对 Java 虚拟环境的一个引用,在 Android 中,就是指 Dalvik VM。
      参考 jni.h 文件中关于 JNIEnv 的定义,如下(对于 C 和 C++,它的定义有点不一样):
     1 struct _JNIEnv;
     2 struct _JavaVM;
     3 typedef const struct JNINativeInterface* C_JNIEnv;
     4 
     5 #if defined(__cplusplus)
     6 typedef _JNIEnv JNIEnv;  //从这里可以看出 C++ 中对 JNIEnv 的使用就是对结构体的使用
     7 typedef _JavaVM JavaVM;
     8 #else
     9 typedef const struct JNINativeInterface* JNIEnv;  //从这里可以看出 C 中队 JNIEnv 的使用就是对结构体指针的使用
    10 typedef const struct JNIInvokeInterface* JavaVM;
    11 #endif

      在 C 中,我们可以看到 JNIEnv 的类型就是 JNINativeInterface* ,是一个指针类型,那么在 C++中呢,_JNIEnv 是什么样的呢?

     1 /*
     2  * C++ object wrapper. c++对象包装器。
     3  *
     4  * This is usually overlaid on a C struct whose first element is a
     5  * JNINativeInterface*.  We rely somewhat on compiler behavior. 这通常覆盖在第一个元素是 JNINativeInterface* 的 C 结构上。我们多少依赖于编译器的行为。
     6  */
     7 struct _JNIEnv {
     8     /* do not rename this; it does not seem to be entirely opaque */
     9     const struct JNINativeInterface* functions;
    10 
    11 #if defined(__cplusplus)
    12 
    13     jint GetVersion()
    14     { return functions->GetVersion(this); }

      而对于 C++ 来说, _JNIEnv 是一个结构体,里面包含了 JNINativeInterface* 的结构。

      所以从这里也可以看到,对于 C 和 C++ 来说,它们引用 JNIEnv 中的方法是有一点不一样的。 总的来说,JNIEnv,不管是 C,还是 C++,其实关键都是 JNINativeInterface 的这个结构。

      我们可以简单看一下 JNINativeInterface 结构的定义,如下:(删减的~~~)

      1 /*
      2  * Table of interface function pointers.
      3  */
      4 struct JNINativeInterface {
      5     void*       reserved0;
      6     void*       reserved1;
      7     void*       reserved2;
      8     void*       reserved3;
      9 
     10     jint        (*GetVersion)(JNIEnv *);
     11 
     12     jclass      (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,
     13                         jsize);
     14     jclass      (*FindClass)(JNIEnv*, const char*);
     15 
     16     jmethodID   (*FromReflectedMethod)(JNIEnv*, jobject);
     17     jfieldID    (*FromReflectedField)(JNIEnv*, jobject);
     18     /* spec doesn't show jboolean parameter */
     19     jobject     (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean);
     20 
     21    ......
     22 
     23     jboolean    (*ExceptionCheck)(JNIEnv*);
     24 
     25     jobject     (*NewDirectByteBuffer)(JNIEnv*, void*, jlong);
     26     void*       (*GetDirectBufferAddress)(JNIEnv*, jobject);
     27     jlong       (*GetDirectBufferCapacity)(JNIEnv*, jobject);
     28 
     29     /* added in JNI 1.6 */
     30     jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject);
     31 };
      可以看到在它其中定义了很多的函数指针,而通过这些定义,JNI 层其实就获得了对 DVM 的引用,通过定义的这些函数指针,可以定位到虚拟机中的 JNI 函数表,从而实现 JNI 层在 DVM 中的函数调用。
      所以,可以这样理解,其实 JNIEnv,就是对 DVM 运行环境中 C/C++ 函数的一个引用,而也正因为此,当 C/C++ 想要在 DVM 中调用函数的时候,由于其是在 DVM 的环境中,所以它们必须通过 JNIEnv*  这个参数来获得这些方法,之后才能够使用。
      那么这个 JNIEnv 是什么时候产生的呢?
      当 Android 中第一个 Java 线程要调用本地的 C/C++ 代码的时候,DVM 就会为该线程产生一个 JNIEnv* 的指针。而每一个线程在和 C/C++ 互相调用的时候,其对应的 JNIEnv 也是相互独立。
      嗯,结束。
  • 相关阅读:
    Java Swing TextArea 滚动条和获得焦点
    Windows下一个AndroidStudio 正在使用Git(AndroidStudio工程GitHub关联)
    我们将与操作系统工作谈一场无私的爱──《云情人》思考
    CSDN markdown 编辑 三 基本语法
    Android项目包装apk和apk反编译,xml反编译
    char (*(*p[3])( int ))[5] 等等一系列 左右法则
    typedef 优于 #define
    int *(*a[5])(int, char*)
    C++宏定义详解
    STL 案例分析
  • 原文地址:https://www.cnblogs.com/Reverse-xiaoyu/p/14117991.html
Copyright © 2020-2023  润新知