jni.h文件: 了解 JNI 需要配合 jni.h 文件, jni.h 是 Google NDK 中的一个文件, 位置是$/android-ndk-r9d/platforms/android-19/arch-arm/usr/include/jni.h;


1. JNIEnv 作用


JNIEnv 概念: 是一个线程相关的结构体, 该结构体代表了 Java 在本线程的运行环境 ;


JNIEnv 与 JavaVM: 注意区分这两个概念;

--JavaVM: JavaVM 是 Java虚拟机在 JNI 层的代表, JNI 全局只有一个;

--JNIEnv: JavaVM 在线程中的代表, 每个线程都有一个, JNI 中可能有很多个 JNIEnv;


JNIEnv 作用:

--调用 Java 函数: JNIEnv 代表 Java 运行环境, 可以使用 JNIEnv 调用 Java 中的代码;

--操作 Java 对象: Java 对象传入 JNI 层就是 Jobject 对象, 需要使用 JNIEnv 来操作这个 Java 对象;


2. JNIEnv 的创建和释放


JNIEnv 创建 和 释放: 从 JavaVM 获得 : 下面是 JavaVM 结构体的代码,

--C语言 中来源: JNIInvokeInterface 是 C 语言环境中的 JavaVM 结构体, 调用 (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*) 方法, 可以获取 JNIEnv结构体;

--C++ 中来源: _JavaVM 是 C++ 中的 JavaVM 结构体, 调用 jint AttachCurrentThread(JNIEnv** p_env, void* thr_args) 方法, 可以获取 JNIEnv 结构体;

--C语言 中释放: 调用 JavaVM结构体 (JNIInvokeInterface) 中的 (*DetachCurrentThread)(JavaVM*)方法, 可以释放本线程中的 JNIEnv;

--C++ 中释放: 调用 JavaVM 结构体 (_JavaVM) 中的 jint DetachCurrentThread(){ return functions->DetachCurrentThread(this); } 方法, 即可释放 本线程中的 JNIEnv ;

/* * JNI invocation interface. */struct JNIInvokeInterface {    void*       reserved0;    void*       reserved1;    void*       reserved2;     jint        (*DestroyJavaVM)(JavaVM*);        /* 创建 JNIEnv , 每个线程创建一个 */    jint        (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);        /* 释放本线程的 JNIEnv */    jint        (*DetachCurrentThread)(JavaVM*);    jint        (*GetEnv)(JavaVM*, void**, jint);    jint        (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);}; /* * C++ version. */struct _JavaVM {    const struct JNIInvokeInterface* functions; #if defined(__cplusplus)    jint DestroyJavaVM()    { return functions->DestroyJavaVM(this); }    /* 创建 JNIEnv , 每个线程创建一个 , 调用的C语言结构提中的方法, C 与 C++ 方法相同 */    jint AttachCurrentThread(JNIEnv** p_env, void* thr_args)    { return functions->AttachCurrentThread(this, p_env, thr_args); }    /* 释放本线程的 JNIEnv , 调用的C语言结构提中的方法, C 与 C++ 方法相同 */    jint DetachCurrentThread()    { return functions->DetachCurrentThread(this); }    jint GetEnv(void** env, jint version)    { return functions->GetEnv(this, env, version); }    jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args)    { return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); }#endif /*__cplusplus*/};



?

3. JNIEnv 体系结构


线程相关 : JNIEnv 是线程相关的, 即 在 每个线程中 都有一个 JNIEnv 指针, 每个JNIEnv 都是线程专有的, 其它线程不能使用本线程中的 JNIEnv, 线程 A 不能调用 线程 B 的 JNIEnv;


JNIEnv 不能跨线程:

--当前线程有效: JNIEnv 只在当前线程有效, JNIEnv 不能在 线程之间进行传递, 在同一个线程中, 多次调用 JNI层方法, 传入的 JNIEnv 是相同的;

--本地方法匹配多JNIEnv: 在 Java 层定义的本地方法, 可以在不同的线程调用, 因此 可以接受不同的 JNIEnv;


JNIEnv 结构: 由上面的代码可以得出, JNIEnv 是一个指针, 指向一个线程相关的结构, 线程相关结构指向 JNI 函数指针 数组, 这个数组中存放了大量的 JNI 函数指针, 这些指针指向了具体的 JNI 函数;





4. 分析 JNIEnv 相关代码


JNIEnv 定义的相关代码:

/* 声明结构体, 以便在下面能够使用 */struct _JNIEnv;struct _JavaVM;/* 声明 C 语言环境中的 JNIEnv 为 C_JNIEnv 指针, 指向 JNINativeInterface 结构体 */typedef const struct JNINativeInterface* C_JNIEnv; #if defined(__cplusplus)/* C++环境下, JNIEnv 是结构体 */typedef _JNIEnv JNIEnv;typedef _JavaVM JavaVM;#else/* C语言环境下, JNIEnv是指针 */typedef const struct JNINativeInterface* JNIEnv;typedef const struct JNIInvokeInterface* JavaVM;#endif


?

--JNINativeInterface 结构体: 该结构体中定义了大量的函数指针, 这些函数指针 指向 与 Java 相关的变量有关的函数, 如果是 C 语言环境中, JNIEnv 就是指向 该结构体的指针;

--_JNIEnv 结构体: C++ 环境中的 JNIEnv 就是该结构体, 该结构体中封装了 一个 JNINativeInterface 结构体指针, 即 C++ 中的 JNIEnv 要比 C 语言中的要多, 并且 完全兼容 C 语言中的 JNIEnv;

--_JavaVM 结构体: 该结构体 是 Java 虚拟机 在 JNI 中的代表, 整个 JNI 层 只存在一个 该 虚拟机映射;


JNINativeInterface源码(删减过): 省略后的, 其中定义了 与Java有关的相关方法, 都是 指向对应函数的函数指针;

--解析 JNIEnv*: C语言环境中的typedef const struct JNINativeInterface* JNIEnv,JNIEnv* env等价于JNINativeInterface** env1 (指向结构体地址的指针), 要想 根据 二级指针 env1 获取 JNINativeInterface 结构体中定义的函数指针, 首先获取 指向结构体的一级指针, 获取方法是 (*env1), 因此调用其中的函数指针指向的方法要这样 : (*env1)->FindClass(JNIEnv*, const char*);

/*  * Table of interface function pointers.  */  struct JNINativeInterface {      void*       reserved0;      void*       reserved1;      void*       reserved2;      void*       reserved3;         jint        (*GetVersion)(JNIEnv *);         ... ...         jobject     (*NewDirectByteBuffer)(JNIEnv*, void*, jlong);      void*       (*GetDirectBufferAddress)(JNIEnv*, jobject);      jlong       (*GetDirectBufferCapacity)(JNIEnv*, jobject);         /* added in JNI 1.6 */      jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject);  };  


_JNIEnv 源码(删减过): 该源码中有一个 JNINativeInterface 结构体指针, 说明 C++ 环境的 JNIEnv 是在 C 语言环境的 JNIEnv 下扩展的;

--解析 JNIEnv*: 定义是这样的typedef _JNIEnv JNIEnv,JNIEnv* env等价于_JNIEnv* env1, 因此调用 _JNIEnv 中定义的函数指针指向的函数的时候, 只需要 使用 env1->FindClass(JNIEnv*, const char*) 即可;

/* * 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); }     ... ...      jlong GetDirectBufferCapacity(jobject buf)    { return functions->GetDirectBufferCapacity(this, buf); }     /* added in JNI 1.6 */    jobjectRefType GetObjectRefType(jobject obj)    { return functions->GetObjectRefType(this, obj); }#endif /*__cplusplus*/};





?

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. android service 广播 更新 activity
  3. Android提高十七篇之多级树形菜单的实现[转]
  4. Android的handler和callback机制
  5. ProgressBar
  6. Android(安卓)SDK目录结构和工具介绍
  7. android 应用的网络请求工具
  8. Android系统文件夹结构
  9. android-async-http使用

随机推荐

  1. Wordpress 外网访问时不显示图片解决办法
  2. Java MySQL数据类型对照
  3. [征集] MySQL交叉表解决方案及散分
  4. VS2013使用EF6通过ADO.NET 连接mySql成功
  5. mysql 批量更新与批量更新多条记录的不同
  6. MySQL第一课(基础、库操作、表操作)
  7. labview使用DSN与数据库的连接包括access
  8. 【文档】五、Mysql Binlog事件结构
  9. g++ 连接 mysql 编译报错 /usr/bin/ld: c
  10. Mysql 查看及设置事物隔离级别