.

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

【Android 系统开发】Android JNI 之 JNIEnv 解析相关推荐

  1. Android系统开发 默认壁纸的定制 主题风格的开发及定制 DDMS 常用adb 命令 抓取Log

    Android系统开发             Android系统本身的功能在增加和完善过程中.在系统开发中如果涉及系统API的改动,则一定要慎重,系统的API的改动可能涉及Android应用程序的不 ...

  2. Android系统开发和性能优化——查漏补缺【建议收藏】

    做了这么久性能相关的工作,也接触了不少模块,说实话要做好性能这一块,真心不容易.为什么这么说? 是因为需要接触的知识实在是太多了, Android 是一个整体,牵一发而动全身,不是说只懂一个模块就可以 ...

  3. Android菜鸟如何学习Android系统开发?

    如何做好Android学习前的准备? 如果你已经确定了学习Android的目标,那么,应该提前做好哪些工作.先打下哪些基础呢? 首先,你最好先熟悉一门编程语言,现在大学里面和计算机相关的专业甚至理工类 ...

  4. Android系统开发 ----- 系统服务开发

    系列文章目录 Android系统启动 ---- 主要流程类_MrDarly的博客-CSDN博客Android系统启动Zygote关系主要的类https://blog.csdn.net/weixin_6 ...

  5. Android菜鸟如何学习Android系统开发?(

    如何做好Android学习前的准备? 如果你已经确定了学习Android的目标,那么,应该提前做好哪些工作.先打下哪些基础呢? 首先,你最好先熟悉一门编程语言,现在大学里面和计算机相关的专业甚至理工类 ...

  6. Android系统开发(移植)和应用开发

    Android是个开源的操作系统,所以可以选择的开发方式主要有两种: Android系统开发(移植): Android应用开发 1.Android系统开发(移植) Android系统开发(移植)属于底 ...

  7. 《Android系统开发》笔记

    <Android系统开发>笔记1:Android系统概述 Android四层架构: 1. Linux Kernel&driver层 a.依赖于Linux 2.6内核,包括安全性,内 ...

  8. Android NDK开发之 Android系统开发中LOG的使用

    浅谈Android系统开发中LOG的使用 转自:http://blog.csdn.net/luoshengyang/article/details/6581828

  9. Android系统开发:短信的号码拦截

    Android系统开发:短信的号码拦截 Code:Android源码 功能要求:针对某号码,短信的接收与发送的监听与拦截. 设备对该号码发送短信的拦截 实现思路 : 应用发送短信(无论是否是默认短信) ...

  10. android 服务端技术,移动应用服务器端开发(基于JSP技术)-2017 Android系统构架 Android系统构架.docx...

    Android系统构架 PAGE 1 目 录 TOC \o "1-3" \h \z \u 一.Android系统构架 1 二.Linux内核层 2 三.系统运行库层 3 (一)系统 ...

最新文章

  1. 比较Spring AOP与AspectJ
  2. 详解linux系统的启动过程及系统初始化
  3. mxnet:mx.sym.BlockGrad理解
  4. python操作RabbitMQ
  5. window如何将CMD以管理员身份添加到右键菜单?
  6. 《C++ Primer》7.2.1节练习
  7. 具有可执行Tomcat的独立Web应用程序
  8. Java中的使用了未经检查或不安全的操作
  9. angularjs封装bootstrap官网的时间插件datetimepicker
  10. 汽车上有哪些很难发现却非常实用的配置?
  11. mysql双向复制_MySQL 双向复制
  12. [Machine Learning]朴素贝叶斯(NaiveBayes)
  13. cloudera-agent启动File not found : /usr/sbin/cmf-agent解决办法(图文详解)
  14. tp框架 中的时间 查询范围
  15. 【转】java注解-最通俗易懂的讲解
  16. openbsd_仔细看一下OpenBSD
  17. 北京邮电大学计算机专业考研复试经验分享
  18. windows11 这个男神到底值得用吗?——一个男神的传奇
  19. 海洋cms宝塔定时linux,海洋cms设置宝塔自动采集教程
  20. SyntaxError: Non-UTF-8 code starting with ‘\xe6‘ in file C:/Users/0moyi0/Desktop/DeepLearningExample

热门文章

  1. 使用JDBC连接SQL Server 2000 命名实例(Named Instance)
  2. [2010国家集训队]Crash的旅游计划
  3. c++ static 存储类
  4. 架构漫谈读后感之软件架构师如何工作
  5. 【 转 】Keepalived工作原理
  6. 树莓派(Raspberry Pi)修改时区
  7. 如何计算数据集均值和方差
  8. T-SQL基础(三)之子查询与表表达式
  9. MES系统实施4大关键点,您都知道吗?
  10. JavaScript基础——Date对象