Android 系统开发Android JNI 之 JNIEnv 解析

与天地兮比寿,与日月兮齐光。这篇文章主要讲述Android 系统开发Android JNI 之 JNIEnv 解析相关的知识,希望能为你提供帮助。
.


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 结构体;
【Android 系统开发Android JNI 之 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 函数;  


Android 系统开发Android JNI 之 JNIEnv 解析

文章图片






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*/ };





    推荐阅读