什么是JNI?为什么会有Native层?如何使用?
itomcoil 2025-06-13 14:09 6 浏览
什么是JNI?
JNI是Java Native Interface的缩写,通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植;从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互
本地代码与 Java 虚拟机之间是通过 JNI 函数实现相互操作的;JNI 函数通过接口指针来获得,本地方法将 JNI 接口指针当作参数来接受;虚拟机保证在从相同的 Java 线程中对本地方法进行多次调用时,传递给本地方法的接口指针是相同的,本地方法被不同的 Java 线程调用时,它接受不同的 JNI接口指针
使用JNI和算法进行交互,主要是为了提高算法的性能,最大化的利用机器硬件资源
Android 中的语言层
可以将语言层分成Java层和Native层;为什么会有Native层呢?是因为在Java出现之前,很多的功能和系统都是由Native语言写的,所以Java出现之后就不必重复造轮子,直接调用这些方法就行了,而且Native层更接近汇编语言,所以性能更优
所以代码中就出现了Java层调用Native层的方法,而这个跨语言的调用过程就是 JNI
当Java语言无法处理一些任务的时候,就可以使用JNI来完成
下面是几个 JNI 的应用场景:
需要调用Java语言不支持的依赖于操作系统平台特性的一些功能
● 需要调用当前UNIX系统的某个功能,而Java不支持这个功能的时候,就要用到JNI
● 在程序对时间敏感或对性能要求特别高时,有必要用到更底层的语言来提高运行效率
● 音视频开发涉及到的音视频编解码需要更快的处理速度,这就需要用到JNI
● 为了整合一些以前的非Java语言开发的系统
● 需要用到早期实现的C/C++语言开发的一些功能或者系统,将这些功能整合到当前的系统或者新的版本中
JNI是完善Java的一个重要功能,它让Java更加全面、封装了各个平台的差异性
jni异常处理
在android ndk开发过程中,调用java对象方法可能会抛异常,如果在ndk层中不做任何处理,那么程序就会直接崩溃;例如我们要在jni层获取apk的签名,代码如下:
**jclass native_class = env->GetObjectClass(const_cast<jobject>(contextObject));
jmethodID pm_id = env->GetMethodID(native_class, "getPackageManager", "()Landroid/content/pm/PackageManager;");
jobject pm_obj = env->CallObjectMethod(const_cast<jobject>(contextObject), pm_id);
jclass pm_clazz = env->GetObjectClass(pm_obj);
jmethodID package_info_id = env->GetMethodID(pm_clazz, "getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
// 获得应用包的信息
jobject pi_obj = NULL;
//GET_SIGNATURES 64
pi_obj = env->CallObjectMethod(pm_obj, package_info_id, package_name, 64);
...**
上述代码如果package_name查找不到就会报如下异常
捕获异常
释放资源
Native 提供了 ExceptionOccurred 和 ExceptionCheck 方法来检测是否有异常发生,前者返回的是 jthrowable 类型,后者返回的是 jboolean 类型;如果有异常,会通过 ExceptionDescribe 方法来打印异常信息,方便我们在 LogCat 中看到对应的信息
而 ExceptionClear 方法则是关键的不会让应用直接崩溃的方法,类似于 Java 的 catch 捕获异常处理,它会消除这次异常;这样就把由 Native 调用 Java 时的一个异常进行了处理,当处理完异常之后,别忘了释放对应的资源
不过,我们这样仅仅是消除了这次异常,还应该让调用者有异常的发生,那么就需要通过 Native 来抛出一个异常告诉 Java 调用者了
void throwByName(JNIEnv *env, const char *name, const char *msg) {
jclass cls = env->FindClass(name);
if (cls != NULL) {
env->ThrowNew(cls, msg);
}
env->DeleteLocalRef(cls);
}
// 调用抛出异常
extern "C"
JNIEXPORT void JNICALL
Java_com_glumes_cppso_jnioperations_ExceptionOps_nativeThrowException(JNIEnv *env, jobject instance) {
throwByName(env, "java/lang/IllegalArgumentException", "native throw exception");
}
jni错误日志分析
ndk发生崩溃的时候会在/data/tombstones文件夹下生成一个墓碑文件,形如tombstone_xx。谷歌也提供了addr2line/ objdump/ndk-stack工具
一个典型的墓碑文件内容如下
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'Android-x86/android_x86/x86:5.1.1/LMY48W/woshijpf04211939:eng/test-keys'
Revision: '0'
ABI: 'x86'
pid: 1019, tid: 1019, name: surfaceflinger >>> /system/bin/surfaceflinger <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4
eax a6265c06 ebx b7467d88 ecx b7631a22 edx a6265c06
esi 00000000 edi b6867140
xcs 00000073 xds 0000007b xes 0000007b xfs 00000000 xss 0000007b
eip b745a639 ebp bfcfc1e8 esp bfcfc150 flags 00010282
backtrace:
#00 pc 00006639 /system/lib/libui.so (android::Fence::waitForever(char const*)+41)
#01 pc 00034b86 /system/lib/libsurfaceflinger.so
#02 pc 0003229e /system/lib/libsurfaceflinger.so
#03 pc 0002cb9c /system/lib/libgui.so (android::BufferQueue::ProxyConsumerListener::onFrameAvailable(android::BufferItem const&)+652)
#04 pc 000342f4 /system/lib/libgui.so (android::BufferQueueProducer::queueBuffer(int, android::IGraphicBufferProducer::QueueBufferInput const&, android::IGraphicBufferProducer::QueueBufferOutput*)+2580)
#05 pc 0004eafb /system/lib/libgui.so (android::Surface::queueBuffer(ANativeWindowBuffer*, int)+411)
#06 pc 0004ce06 /system/lib/libgui.so (android::Surface::hook_queueBuffer(ANativeWindow*, ANativeWindowBuffer*, int)+38)
#07 pc 00014bc6 /system/lib/egl/libGLES_android.so
#08 pc 00017f73 /system/lib/egl/libGLES_android.so (eglSwapBuffers+163)
#09 pc 00015fdb /system/lib/libEGL.so (eglSwapBuffers+203)
#10 pc 000013ea /system/lib/hw/hwcomposer.x86.so
#11 pc 00034730 /system/lib/libsurfaceflinger.so
#12 pc 000256d4 /system/lib/libsurfaceflinger.so
#13 pc 00024bf4 /system/lib/libsurfaceflinger.so
#14 pc 000236fb /system/lib/libsurfaceflinger.so
#15 pc 0002338a /system/lib/libsurfaceflinger.so
#16 pc 0001e0ff /system/lib/libsurfaceflinger.so
#17 pc 0001d9ce /system/lib/libutils.so (android::Looper::pollInner(int)+926)
#18 pc 0001db73 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+67)
#19 pc 0001e561 /system/lib/libsurfaceflinger.so
#20 pc 00022ce7 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::run()+39)
#21 pc 00000ca3 /system/bin/surfaceflinger
#22 pc 0001365a /system/lib/libc.so (__libc_init+106)
#23 pc 00000da8 /system/bin/surfaceflinger
stack:
bfcfc110 00000000
bfcfc114 b6839270
bfcfc118 00000000
bfcfc11c 00000000
bfcfc120 b68394e0
bfcfc124 00000002
bfcfc128 00000002
bfcfc12c b75d8185 /system/lib/libutils.so (android::RefBase::incStrong(void const*) const+53)
bfcfc130 b6839270
bfcfc134 bfcfc1e8 [stack]
bfcfc138 00000002
bfcfc13c a6265c06
bfcfc140 b7467d88 /system/lib/libui.so
bfcfc144 00000000
bfcfc148 b6867140
bfcfc14c b745a639 /system/lib/libui.so (android::Fence::waitForever(char const*)+41)
#00 bfcfc150 b683af18
bfcfc154 bfcfc1e8 [stack]
bfcfc158 00000000
bfcfc15c 00000000
bfcfc160 00000000
bfcfc164 b683af18
bfcfc168 b75ec9c4 /system/lib/libutils.so
bfcfc16c b75d8285 /system/lib/libutils.so (android::RefBase::weakref_type::decWeak(void const*)+37)
bfcfc170 00000000
bfcfc174 00000000
bfcfc178 00000000
bfcfc17c 00000000
bfcfc180 b7642968 /system/lib/libsurfaceflinger.so
bfcfc184 bfcfc1e8 [stack]
bfcfc188 b6867140
bfcfc18c b7622b87 /system/lib/libsurfaceflinger.so
文件结构
定位工具
- addr2line
qinqundeMacBook-Pro% ./aarch64-linux-android-addr2line -C -f -e ~/Documents/DProtect2/mylibrary/build/intermediates/cmake/debug/obj/arm64-v8a/libnative-lib.so 0000000000157efc
Java_com_dofun_dprotect_lib_LocalWork_start
/Users/qinqun/Documents/DProtect2/mylibrary/src/main/cpp/native-lib.cpp:147
- ndk-stack
有需要完整代码的同学 可以 私信 发送 “底层源码” 即可 免费获取
现在发送还可以获得更多《Android 学习笔记+源码解析+面试视频》
JNI 特点:
二进制兼容
● 本地方法库与同一平台上所有Java 虚拟机之间实现二进制兼容,即对于给定平台开发人员只需要维护一种版本的本地方法库
效率高
为了实现实时系统,JNI 在效率与虚拟机无关性之间进行了优化,以保障高效运行
功能强
● JNI 提供了大量的函数及接口让本地方法与Java 虚拟机内核相互操作,增强两者的功能
本地代码与 Java 虚拟机之间是通过 JNI 函数实现相互操作的;JNI 函数通过接口指针来获得,本地方法将 JNI 接口指针当作参数来接受;虚拟机保证在从相同的 Java 线程中对本地方法进行多次调用时,传递给本地方法的接口指针是相同的,本地方法被不同的 Java 线程调用时,它接受不同的 JNI接口指针
尾述
有需要完整代码的同学 可以 私信 发送 “底层源码” 即可 免费获取
现在发送还可以获得更多《Android 学习笔记+源码解析+面试视频》
技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面
Android 架构师之路还很漫长,与君共勉
PS:有问题欢迎指正,可以在评论区留下你的建议和感受;
欢迎大家点赞评论,觉得内容可以的话,可以转发分享一下
相关推荐
- C++ 详解 to_string 与 stoi 函数
-
to_string与stoi函数std::to_string和std::stoi是C++标准库中的两个非常有用的函数,它们分别用于将整数转换为字符串和将字符串转换为整数。std::to...
- 合并单元格内容,除了“&”,三个函数一个比一个厉害
-
在EXCEL表格里有多种方法可以合并多列单元格的内容,最常见的就是使用连接符号“&”和各种函数公式,下面我们一起来看看。使用连接符号公式:=A2&"-"&B2&"-"&...
- C语言模拟实现字符串操作函数(c语言字符串用法)
-
1.strlenstrlen是用来求字符串长度的函数,字符串长度就是字符串中包含的字符的个数,但是不包含字符串结尾的‘\0’实现strlen有三种方法:(1)定义一个计数器size_t ...
- JS函数参数的arguments对象,你理解了吗?
-
前言在Javascript中,arguments是所有函数都具有的一个内置局部变量,表示的是函数实际接收的参数对象。Javascript中的arguments对象arguments是一个类数组对象,之...
- C/C++编程笔记:C语言字符串比较函数,超详细,值得收藏
-
void*memset(void*dest,intc,size_tcount);将dest前面count个字符置为字符c.返回dest的值.void*memmove(void*dest...
- Excel表格中11个常用的字符串函数
-
今天和大家聊聊常用的字符串函数,在不同的条件下,如何选择字符串函数很关键。下面我为大家列举了11个关于字符串的函数公式。一、EXACT(两个字符串进行结果比较)比较两个字符串是否完全相同(这里是要区分...
- C语言每日一练:连接字符串(c语言 连接字符串)
-
题目描述:写一函数,将两个字符串连接。输入两行字符串,例如123abc,输出连接后的字符串123abc。代码如下:#include<stdio.h>#include<st...
- C语言编程二级——如何连接3个字符串
-
今天C语言编程实践给大家带来的是不使用库函数,实现3个字符串的链接。本例用到了指针方法,下面是源代码。本例用到了函数声明,一个字符串连接函数。将s1,s2,s3连接在一起,组成s,并且函数最终返回指向...
- 快速合并字符串,除了用&外,还有这些必备技能
-
字符串的合并操作,在Excel中也是非常常见的,最常见的操作方法就是逐个复制合并或者用&符号连接合并。其实,除了这2个方法外,还有其他更实用的技巧哦!一、&符号法。目的:合并指定的字符串。方法:在目标...
- 什么是安全函数?(什么是安全函数模型)
-
公司的大佬说之前某大厂为了安全函数的替换耗资10亿美金。可想安全很重要,安全函数很重要,对于我们做系统软件的来说很重要。为什么要替换成安全函数,这里面就涉及到了一种漏洞攻击,缓冲区溢出攻击。缓冲区溢出...
- Excel如何合并字符串?CONCAT/PHONETIC/TEXTJOIN函数功能对比
-
多个单元格的内容如何合并到一个单元格?Excel一共提供四个函数,可以实现字符串的合并,但是会受到Excel版本的限制,且功能各有优异。PHONETIC函数PHONETIC存在于2016及以上版本中,...
- 「零基础学C语言」带你解析字符串连接函数:strcat_s 函数
-
目录一.strcat_s函数简介二.strcat_s函数原理三.strcat_s函数实战一.strcat_s函数简介strcat_s函数和strcat函数一样,主要用于字符串拼接;strcat...
- 强烈推荐!284页《python编程从入门到实践》完整版,PDF开放下载
-
大佬整理的python学习笔记,大家有需要的可以在文末获取。PDF获取方式:...
- 无需安装python程序,推荐6个靠谱网站在线学习编写python代码
-
对于python编程爱好者来说,并不是所有爱好者都已经安装了python程序(比如python3.12版本的exe程序),或者一些IDE(比如pycharm等),大家无需担心,马上推荐几个国内可用的靠...
- 《Python从入门到项目实践》PDF开放下载,建议收藏
-
Python从入门到项目实践》一书从入门学习者的角度出发,通过简洁有趣的语言、丰富多彩的实例、挑战大脑的任务、贴近开发实战的项目,循序渐进地让读者在实践中学习,在实践中提升实际开发能力。...
- 一周热门
- 最近发表
- 标签列表
-
- ps图案在哪里 (33)
- super().__init__ (33)
- python 获取日期 (34)
- 0xa (36)
- super().__init__()详解 (33)
- python安装包在哪里找 (33)
- linux查看python版本信息 (35)
- python怎么改成中文 (35)
- php文件怎么在浏览器运行 (33)
- eval在python中的意思 (33)
- python安装opencv库 (35)
- python div (34)
- sticky css (33)
- python中random.randint()函数 (34)
- python去掉字符串中的指定字符 (33)
- python入门经典100题 (34)
- anaconda安装路径 (34)
- yield和return的区别 (33)
- 1到10的阶乘之和是多少 (35)
- python安装sklearn库 (33)
- dom和bom区别 (33)
- js 替换指定位置的字符 (33)
- python判断元素是否存在 (33)
- sorted key (33)
- shutil.copy() (33)