Android JNI之JNIEnv

转载自:http://blog.csdn.net/shulianghan/article/details/38012515

 

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 ;

  1. /*
  2. * JNI invocation interface.
  3. */ 
  4. struct JNIInvokeInterface { 
  5.     void*       reserved0; 
  6.     void*       reserved1; 
  7.     void*       reserved2; 
  8.  
  9.     jint        (*DestroyJavaVM)(JavaVM*); 
  10.         /* 创建 JNIEnv , 每个线程创建一个 */ 
  11.     jint        (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*); 
  12.         /* 释放本线程的 JNIEnv */ 
  13.     jint        (*DetachCurrentThread)(JavaVM*); 
  14.     jint        (*GetEnv)(JavaVM*, void**, jint); 
  15.     jint        (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*); 
  16. }; 
  17.  
  18. /*
  19. * C++ version.
  20. */ 
  21. struct _JavaVM { 
  22.     const struct JNIInvokeInterface* functions; 
  23.  
  24. #if defined(__cplusplus) 
  25.     jint DestroyJavaVM() 
  26.     { return functions->DestroyJavaVM(this); } 
  27.     /* 创建 JNIEnv , 每个线程创建一个 , 调用的C语言结构提中的方法, C 与 C++ 方法相同 */ 
  28.     jint AttachCurrentThread(JNIEnv** p_env, void* thr_args) 
  29.     { return functions->AttachCurrentThread(this, p_env, thr_args); } 
  30.     /* 释放本线程的 JNIEnv , 调用的C语言结构提中的方法, C 与 C++ 方法相同 */ 
  31.     jint DetachCurrentThread() 
  32.     { return functions->DetachCurrentThread(this); } 
  33.     jint GetEnv(void** env, jint version) 
  34.     { return functions->GetEnv(this, env, version); } 
  35.     jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args) 
  36.     { return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); } 
  37. #endif /*__cplusplus*/ 
  38. }; 
/*
 * 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 定义的相关代码 :

  1. <span style="font-family: Courier New;">/* 声明结构体, 以便在下面能够使用 */ 
  2. struct _JNIEnv; 
  3. struct _JavaVM; 
  4. /* 声明 C 语言环境中的 JNIEnv 为 C_JNIEnv 指针, 指向 JNINativeInterface 结构体 */ 
  5. typedef const struct JNINativeInterface* C_JNIEnv; 
  6.  
  7. #if defined(__cplusplus) 
  8. /* C++环境下, JNIEnv 是结构体 */ 
  9. typedef _JNIEnv JNIEnv; 
  10. typedef _JavaVM JavaVM; 
  11. #else 
  12. /* C语言环境下, JNIEnv是指针 */ 
  13. typedef const struct JNINativeInterface* JNIEnv; 
  14. typedef const struct JNIInvokeInterface* JavaVM; 
  15. #endif</span> 
<span style="font-family:Courier New;">/* 声明结构体, 以便在下面能够使用 */
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</span>

-- 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*);

  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.     ... ... 
  13.  
  14.     jobject     (*NewDirectByteBuffer)(JNIEnv*, void*, jlong); 
  15.     void*       (*GetDirectBufferAddress)(JNIEnv*, jobject); 
  16.     jlong       (*GetDirectBufferCapacity)(JNIEnv*, jobject); 
  17.  
  18.     /* added in JNI 1.6 */ 
  19.     jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject); 
  20. }; 
/*
 * 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*) 即可;

  1. /*
  2. * C++ object wrapper.
  3. *
  4. * This is usually overlaid on a C struct whose first element is a
  5. * JNINativeInterface*.  We rely somewhat on compiler behavior.
  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); } 
  15.  
  16.     ... ...  
  17.  
  18.     jlong GetDirectBufferCapacity(jobject buf) 
  19.     { return functions->GetDirectBufferCapacity(this, buf); } 
  20.  
  21.     /* added in JNI 1.6 */ 
  22.     jobjectRefType GetObjectRefType(jobject obj) 
  23.     { return functions->GetObjectRefType(this, obj); } 
  24. #endif /*__cplusplus*/ 
  25. }; 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值