写点什么

Android C++ 系列:认识 JNI

作者:轻口味
  • 2021 年 11 月 10 日
  • 本文字数:1596 字

    阅读完需:约 5 分钟

Android C++系列:认识JNI

1. 什么是 JNI

JNI 是 Java Native Interface 的缩写,通过使用 Java 本地接口书写程序,可以确保代码在不同的平台上方便移植。


JNI 不仅仅是 Android 特有的,它是属于 Java 平台的,它允许在 Java 虚拟机内运行的 java 代码与其他编程语言(如 c, c++和汇编语言)编写的程序和库进行交互。Java1.1 开始,JNI 标准成为 java 平台的一部分,它允许 Java 代码和其他语言写的代码进行交互。JNI 一开始是为了本地已编译语言,尤其是 C 和 C++而设计的,但是并不是说不能使用其他编程语言,只要调用约定受支持就可以了。不同语言编写的程序之间调用也不是 Java 和 C++特有的,Java 可以调用 C++,python、go 语言都可以。


JNI 使得在 Java 虚拟机内运行的 Java 代码能够与其它编程语言互相操作,包括创建本地方法、更新 Java 对象、调用 Java 方法,引用 Java 类,捕捉和抛出异常等,也允许 Java 代码调用 C/C++或汇编语言编写的程序和库。作为一个标准程序接口,它没有对底层 Java 虚拟机的实现施加任何限制,并具有以下特点:


  • 二进制兼容。本地方法库与同一平台上所有 Java 虚拟机之间实现二进制兼容,即对于给定平台开发人员只需要维护一种版本的本地方法库。但是同时也丧失了跨平台性,想想我们 Android 只编译 arm 平台的 so 库,就会导致无法在 x86 平台运行。

  • 效率高。为了实现实时系统,JNI 在效率与虚拟机无关性之间进行了优化,以保障高效运行。

  • 功能强。JNI 提供了大量的函数及接口让本地方法与 Java 虚拟机内核相互操作,增强两者的功能。

2. 为什么会有 JNI

JNI 产生的原因和背景是什么呢?我们熟练掌握一门语言后为什么还要再用另一门语言去写呢?它是出于以下几方面的考虑:


  1. 历史程序复用:很多已经使用其他语言实现的功能,我们可以直接拿来主义,编译完直接使用,比如音视频领域强大的 ffmpeg 就是用纯 c 语言实现的,如果再用 java 实现一遍就是完全重复造轮子;

  2. 跨平台代码复用:我们想写一份代码 Android、iOS、Mac、Linux 公用,他们不同平台使用不同语言,怎么办呢?使用 C/C++实现核心功能,然后不同平台使用不同语言的本地接口进行调用;

  3. 弥补 Java 平台无关性的不足:Java 平台无关性导致访问系统底层或者驱动方面存在缺陷,因为我们知道操作系统都是 C/C++实现,如果要访问底层硬件能力,必须要能调用 C/C++接口。在 Android 中,我们的摄像头、麦克风、显示屏、硬件编解码器等能力在底层都是由 C/C++封装;

  4. 性能考虑:有些 CPU 密集型操作可以使用 JNI 调用 C/C++或者汇编实现,来提高效率。

3. JNI 接口介绍

JNI 对外暴露的接口主要是我们jni.h头文件,头文件里面为我们封装了 JNIEnv 环境变量结构和 JavaVM 结构体。任何方法的调用都离不开 JNIEnv 变量,C 和 C++接口还有一些差异:在 C 的定义中,env 是一个两级指针,而在 C++的定义中,env 是个一级指针。C 形式需要对 env 指针进行双重 deferencing,而且须将 env 作为第一个参数传给 jni 函数,举个简单的例子:


  • 对于 demo.c:JNI 函数调用由(*env)->作前缀,目的是为了取出函数指针所引用的值,如:return (*env)->NewStringUTF(env,"HelloJNI!");

  • 对于 demo.cpp:JNIEnv 类拥有处理函数指针查找的内联成员函数,如:return env->NewStringUTF("HelloJNI!");


但是其实本质没有什么区别,一个是 JNI 调 C,一个是 JNI 调 C,C 再调 C++。

4. 经常与我们打交道的 JNI

下面介绍下我们日常接触的一些使用了 JNI 能力的开源库:


  1. ijkplayer:做移动端播放器的对 ijkplayer 不会陌生,它是哔哩哔哩推出的跨平台开源播放器,由于它底层是 ffmpeg 实现,用到了 C 代码,所以需要通过 JNI 做包装;

  2. webrtc:谷歌开源的跨平台实时通信库,包括 3A,弱网对抗等核心能力使用 C/C++实现,平台层做少量包装适配;

  3. mars:微信开源的一个跨平台长连接信令库,里面还有一个高性能日志库,核心代码用 C/C++实现,然后在上层不同平台做少量适配;

  4. tenforflow lite:机器学习库,C 语言实现,可以一份代码编译成不同平台库。

5. 总结

本介绍了 JNI 概念以及 JNI 的作用、JNI 提供的接口,以及我们常用到的一些使用了 JNI 的开源程序。

发布于: 12 小时前阅读数: 7
用户头像

轻口味

关注

🏆2021年InfoQ写作平台-签约作者 🏆 2017.10.17 加入

Android、音视频、AI相关领域从业者。 邮箱:qingkouwei@gmail.com

评论

发布
暂无评论
Android C++系列:认识JNI