当前位置: 首页 > 科技观察

Android架构师之路——JNI和NDK编程知识基础详解(C++音视频编码基础)

时间:2023-03-12 10:29:54 科技观察

前沿笔记1.Android架构师需要学习的知识点很多。后面我会总结一下Android开发中的jni和NDK。ndk开发的知识点,目前基础越扎实越好,以后学起来也不会太累,一点就懂;2、今天我们总结一下jni和ndk的基础知识点;3.Android平台从一开始就已经支持C/C++。我们知道AndroidSDK主要是基于Java的,所以使用AndroidSDK进行开发的工程师必须使用Java语言。不过谷歌一开始就声明Android也支持JNI编程,即第三方应用可以通过JNI调用自己的C动态;一、什么是ndkNDK提供了一系列工具帮助开发者快速开发C(或C++)动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者有很大的帮助;NDK集成了交叉编译器,并提供相应的mk文件隔离CPU、平台、ABI等差异,开发者只需简单修改mk文件即可(指出“需要编译哪些文件”、“编译特性要求”、等),你可以这样创建;NDK可以自动将so和Java应用打包在一起,大大减少了开发者的打包工作;NDK提供稳定的API头文件,功能有限Disclaimer;Google明确表示此API是稳定的,当前发布的API将在所有后续版本中得到稳定支持。从这个版本的NDK可以看出,这些API支持的功能非常有限,包括:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog);NDK发布,“Java+C”开发方式终于成为正向开发方式;使用NDK,我们可以使用C来开发对性能要求很高的应用逻辑,从而提高应用的执行效率;使用NDK,我们可以将需要的机密应用逻辑用C开发,毕竟Java包是可以反编译的;NDK推动专业so组件厂商的出现:如视频库编译、音频库、图片库滤镜等;NDK将使Android平台支持C开发的开始;NDK提供了一组开发工具,使开发者可以方便地开发和发布C组件。同时,Google承诺在NDK的后续版本中提高“可调”能力,即提供远程gdb工具,方便我们调试C源代码;2、为什么要用NDK跨平台移植应用;复用已有的库,或者提供自己的库进行复用;在某些情况下提高性能,特别是对于游戏等计算密集型应用程序;使用第三方库,现在很多第三方库都是用C/C++库写的,比如Ffmpeg这个库;不依赖于DalvikJava虚拟机的设计;代码保护。由于APK的Java层代码容易反编译,反编译C/C++库比较困难;三、jni详解1、什么是jni?以及与ndkJNI的关系,全称是JavaNativeInterface,即Java本地接口,JNI是Java调用Native语言的一种特性。Java可以通过JNI与C/C++模型进行交互。即Java代码中可以调用C/C++等语言的代码或者C/C++代码中可以调用Java代码。由于JNI是JVM规范的一部分,我们可以在任何实现了JNI规范的Java虚拟机中运行我们编写的JNI程序;在AndroidFramework中,需要提供一个媒介或桥梁,将Java层(上层)与C/C++层(下层)有机地联系起来,使它们相互协调,共同完成某些任务。充当这个媒介的是Java本地接口(JNI,JavaNativeInterface);JNI提供了一系列接口,可以让Java类以C/C++等本地编辑语言(在JNI中,这些语言被称为本地语言)应用程序、模块、库之间进行交互.例如,在Java类中使用C语言库中的函数,或者在C语言中使用Java类库,都需要JNI的帮助;AndroidNDK是一个开发工具集,提供了一系列快速开发C/C++动态库的工具,并且可以自动将.so/.dll和Java应用程序打包成Apk;NDK提供了方便JNI调用C/C++的工具,提供了交叉编译器,可以修改.mk文件生成针对特定CPU平台的动态库,并可以将so与java应用一起打包成apk;简而言之,JNI负责Java和C/C++之间的互操作,NDK提供工具方便JNI在Android平台上的使用;2、JNI开发过程的步骤首先在Java中声明一个native方法;compile从Java源文件javac中获取.class文件;通过javah-jni命令导出JNI的.h头文件;使用需要与Java交互的native代码实现Java中声明的Native方法;将native代码编译成动态库(Windows系统下是.dll文件,Linux系统下是.so文件,Mac系统下是.jnilib);通过Java命令执行Java程序,最终实现Java调用本地代码;3.JNI数据结构的组成JNI函数表类似于C++的虚函数表。一个虚拟机可以运行多个函数表,例如一个调试函数表和一个调用函数表。JNI接口指针只在当前线程中起作用。这意味着指针不能从一个线程传递到另一个线程,但是,可以在不同的环境中调用本地方法;jdoubletest(JNIEnv*env,jobjectobj,jinti,jstrings){constchar*str=(*env)->GetStringUTFChars(env,s,0);(*env)->ReleaseStringUTFChars(env,s,str);return10;}JNI有自己的原始数据类型和数据引用类型如下四、jni交互原理详解1、JavaVMJavaVM是Java虚拟机代表JNI层,JNI全局只封装了一些函数指针(或函数表结构)在一个JavaVM结构中,而封装在JavaVM中的这些函数指针主要是为JVM操作接口。另外,C和C++中JavaVM的定义是不一样的。在C中,JavaVM是一个JNIInvokeInterface_类型的指针,而在C++中,JNIInvokeInterface_被封装了一次,比C少了一个参数,这也是为什么JNI代码推荐用C++编写的原因;2、JNIEnvJNIEnv是一个线程相关的结构体,代表Java在该线程中的执行环境。JNIEnv是当前Java线程的执行环境。一个JVM对应一个JavaVM结构,一个JVM中可能会创建多个Java线程,每个线程对应一个JNIEnv结构,保存在线程本地存储TLS中。因此,不同线程的JNIEnv是不同的,不能相互共享。JNIEnv结构也是一个函数表,可以在本地代码中通过JNIEnv函数表来操作Java数据或者调用Java方法。也就是说只要在本地代码中获取到JNIEnv结构体,就可以在本地代码中调用Java代码;调用Java函数:JNIEnv代表Java执行环境,可以使用JNIEnv调用Java中的代码;操作Java代码:Java对象JNI层传入的是jobject对象,需要使用JNIEnv来操作这个Java对象;3、JNIEnv与JavaVM的区别JavaVM:JavaVM是Java虚拟机在JNI层的代表,全球只有一个JNI;JNIEnv:JavaVM中线程代码,每个线程都有一个,JNI可能有多个JNIEnv;4、JNIEnv与线程JNIEnv是线程相关的,即每个线程中都有一个JNIEnv指针,每个JNIEnv都是线程专有的。其他线程不能在本线程使用JNIEnv,即线程A不能调用线程B的JNIEnv,所以JNIEnv不能跨线程;JNIEnvisonlyvalidinthecurrentthread:JNIEnvisonlyvalidinthecurrentthread;JNIEnv不能在线程之间传递。在同一个线程中,方便多次调用JNI层,传入的JNIEnv都是一样的;localmethodsmatchmultipleJNIEnv:定义在Java层的localmethods可以在不同的线程调用,所以可以接受不同的JNIEnv;5、JNIEnv结构体6、JNIEnv相关的常用函数createobjectsinJavajobject(*NewObject)(JNIEnv*,jclass,jmethodID,...);jobject(*NewObjectV)(JNIEnv*,jclass,jmethodID,va_list);jobject(*NewObjectA)(JNIEnv*,jclass,jmethodID,constjvalue*);字符串相关jstring(*NewString)(JNIEnv*,constjchar*,jsize);jsize(*GetStringLength)(JNIEnv*,jstring);constjchar*(*GetStringChars)(JNIEnv*,jstring,jboolean*);无效(*ReleaseStringChars)(JNIEnv*,jstring,constjchar*);jstring(*NewStringUTF)(JNIEnv*,constchar*);jsize(*GetStringUTFLength)(JNIEnv*,jstring);/*JNIspec说这返回constjbyte*,butthat'sinconsistent*/constchar*(*GetStringUTFChars)(JNIEnv*,jstring,jboolean*);GetarrayrelatedjsizeGetArrayLength(jarrayarray){returnfunctions->GetArrayLength(this,array);}jobjectGetObjectArrayElement(JNIEnv*env,jobjectArrayarray,jsizeindex);总结:以上是学习jni的基础知识点,必须了解,如果你不懂,就问,学;jni还有很多知识点,比如动态注册,静态注册等等;学习一点c语言和c++的基础知识,后面再说总结。转载本文请联系Android开发编程公众号。