《深入理解Android 卷I》- JNI

翻译:https://developer.android.com/training/articles/perf-jni.html
参阅:《深入理解Android 卷I》

博文是对一些概念的总结,还需参阅着上述书籍来看。

JNI是Java Native Interface。它定义了一种托管代码(以Java编程语言编写)与本地代码交互(以C / C ++编写)的方式。它是供应商中立的,支持从动态共享库加载代码,虽然麻烦但是是有效的。

它是一座Native世界与Java世界链接的桥梁。
这里写图片描述

如果您还不熟悉它,请阅读Java Native Interface Specification以了解JNI的工作原理以及可用的功能。

JavaVM and JNIEnv

JNI定义了两个的关键数据结构“JavaVM”和“JNIEnv”。这两个都是指向函数表的指针。 JavaVM提供了“调用接口”功能,允许您创建和销毁JavaVM。理论上讲,每个进程可以有多个JavaVM,但Android只允许一个。

JNIEnv提供了许多JNI系统函数。Native函数第一个参数就是JNIEnv。

JNIEnv用于线程本地存储,是一个与线程相关的代表JNI环境的结构体。因此,您不能在线程之间共享JNIEnv。如果代码中无法来获取其JNIEnv,则应该共享JavaVM,并使用GetEnv来获取线程的JNIEnv。
这里写图片描述

Threads

所有线程都是Linux线程,被内核调度执行。它们通常从托管代码(使用Thread.start)启动,但也可以在其他地方创建,然后依附在JavaVM上。例如,使用pthread_create启动的线程可以通过JNI的 AttachCurrentThread或AttachCurrentThreadAsDaemon函数依附在JavaVm上。在线程被依附之前,它没有JNIEnv,不能进行JNI调用。

Android不会挂起正在执行Native代码的线程。如果正在进行垃圾收集,或调试器发出挂起请求,Android将在下一次进行JNI调用时暂停线程。

通过JNI附加的线程必须在退出之前调用DetachCurrentThread函数。

jclass, jmethodID, and jfieldID

如果要从Native代码访问对象的字段,则应该执行以下操作:

  • 使用FindClass方法获取该类的类对象引用
  • 使用GetFieldID方法获取该字段的field ID
  • 使用恰当的方法获取该字段的内容,例如GetIntField

注意:

如果每次操作jobject前都去查询jmethodID和jfieldID,那么将会影响程序运行的效率,所以 我们可以在初始化后可以取出这些id并保存以供后续使用。

注册JNI函数

  • 静态注册
    1. 编写java代码,编译生成class文件
    2. javah生成头文件
  • 动态注册

    1. 实现JNI_OnLoad函数
    2. 维护JNINativeMethod结构体,存储Java中的Native函数名、此函数的签名信息(由参数和返回值组成)、JNI层对应的函数指针(Void * 类型)
      这里写图片描述

      3.注册方法执行如下操作
      这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
第1章 阅读前的准备工作 1.1 系统架构 1.1.1 Android系统架构 1.1.2 本书的架构 1.2 搭建开发环境 1.2.1 下载源码 1.2.2 编译源码 1.3 工具介绍 1.3.1 Source Insight介绍 1.3.3 Busybox的使用 1.4 本章小结 第2章 深入理解JNI 2.1 JNI概述 2.2 学习JNI的实例:MediaScanner 2.3 Java层的MediaScanner分析 2.3.1 加载JNI库 2.3.2 Java的native函数和总结 2.4 JNI层MediaScanner的分析 2.4.1 注册JNI函数 2.4.2 数据类型转换 2.4.3 JNIEnv介绍 2.4.4 通过JNIEnv操作jobject 2.4.5 jstring介绍 2.4.6 JNI类型签名介绍 2.4.7 垃圾回收 2.4.8 JNI中的异常处理 2.5 本章小结 第3章 深入理解init 3.1 概述 3.2 init分析 3.2.1 解析配置文件 3.2.2 解析service 3.2.3 init控制service 3.2.4 属性服务 3.3 本章小结 第4章 深入理解zygote 4.1 概述 4.2 zygote分析 4.2.1 AppRuntime分析 4.2.2 Welcome to Java World 4.2.3 关于zygote的总结 4.3 SystemServer分析 4.3.1 SystemServer的诞生 4.3.2 SystemServer的重要使命 4.3.3 关于 SystemServer的总结 4.4 zygote的分裂 4.4.1 ActivityManagerService发送请求 4.4.2 有求必应之响应请求 4.4.3 关于zygote分裂的总结 4.5 拓展思考 4.5.1 虚拟机heapsize的限制 4.5.2 开机速度优化 4.5.3 Watchdog分析 4.6 本章小结 第5章 深入理解常见类 5.1 概述 5.2 以“三板斧”揭秘RefBase、sp和wp 5.2.1 第一板斧--初识影子对象 5.2.2 第二板斧--由弱生强 5.2.3 第三板斧--破解生死魔咒 5.2.4 轻量级的引用计数控制类LightRefBase 5.2.5 题外话-三板斧的来历 5.3 Thread类及常用同步类分析 5.3.1 一个变量引发的思考 5.3.2 常用同步类 5.4 Looper和Handler类分析 5.4.1 Looper类分析 5.4.2 Handler分析 5.4.3 Looper和Handler的同步关系 5.4.4 HandlerThread介绍 5.5 本章小结 第6章 深入理解Binder 6.1 概述 6.2 庖丁解MediaServer 6.2.1 MediaServer的入口函数 6.2.2 独一无二的ProcessState 6.2.3 时空穿越魔术-defaultServiceManager 6.2.4 注册MediaPlayerService 6.2.5 秋风扫落叶-StartThread Pool和join Thread Pool分析 6.2.6 你彻底明白了吗 6.3 服务总管ServiceManager 6.3.1 ServiceManager的原理 6.3.2 服务的注册 6.3.3 ServiceManager存在的意义 6.4 MediaPlayerService和它的Client 6.4.1 查询ServiceManager 6.4.2 子承父业 6.5 拓展思考 6.5.1 Binder和线程的关系 6.5.2 有人情味的讣告 6.5.3 匿名Service 6.6 学以致用 6.6.1 纯Native的Service 6.6.2 扶得起的“阿斗”(aidl) 6.7 本章小结 第7章 深入理解Audio系统 7.1 概述 7.2 AudioTrack的破解 7.2.1 用例介绍 7.2.2 AudioTrack(Java空间)分析 7.2.3 AudioTrack(Native空间)分析 7.2.4 关于AudioTrack的总结 7.3 AudioFlinger的破解 7.3.1 AudioFlinger的诞生 7.3.2 通过流程分析AudioFlinger 7.3.3 audio_track_cblk_t分析 7.3.4 关于AudioFlinger的总结 7.4 AudioPolicyService的破解 7.4.1 AudioPolicyService的创建 7.4.2 重回AudioTrack 7.4.3 声音路由切换实例分析 7.4.4 关于AudioPol
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青菜小王子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值