Android测试需要get的知识——JNI

发表于:2018-5-15 11:59

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:baiyang    来源:51testing软件测试网采编

  一、前言
  JNI—Java与底层间的桥梁,Android系统中很多的使用了JNI,小编所在项目中核心模块有相关调用。测试中,也有遇到过JNI层的一些问题。理解JNI的调用实现,对于理解Android的代码有帮助。
  二、JNI简介
  1、概念介绍
  JNI是Java Native Interface的简写,可译作Java原生接口。JNI是Java本地调用接口,所谓的Native是调用C/C++的程序。
  2、JNI应用场景
  (1).   调用驱动(Java无法处理):需要用到Java标准平台不具备的依赖于操作系统的特性时。由于操作系统提供的驱动一般都是C接口,Java语言并不具备操作这些驱动的能力;
  (2).   对性能要求比较高或对时间敏感,有必要用更底层的语言:Java可以通过JNI调用C/C++的库,对于计算量比较大,处理数据比较多的模块,Java的效率没有C高,所以希望用C去完成;
  (3).   对于某些功能模块,可能Java和C的效率差不多,已经有现成的,用其他语言已经完成的功能时,需要用Java去直接调用,不用Java重写了。
  三、JNI技术的原理
  在Java程序中调用C/C++程序是通过JNI技术实现的。JNI技术的原理是,在Java源码中声明一个空的特殊函数,Java虚拟机在碰到这个函数时,会加载C/C++程序库,并定位到相应的函数执行其代码。
  1、调用过程示意
  2、通常执行步骤
  (1).   编写带有native声明的方法的java类;
  (2).   使用javac命令编译所编写的java类(class文件),然后使用javah+java类名将上步中的class文件生成扩展名为h的头文件;
  命令:javah–jni×××
  Javah程序统一了Java中的native方法,头文件中的函数名和动态库中的函数实现之间的对应关系。
  (3).   用其他语言(C/C++)实现上述头文件中的函数;生成动态链接库,供Java程序使用;
  (4).   发布Java和动态库;
  JNI对于应用本身来说,可以看作一个代理模式。对于开发者来说,需要使用C/C++来实现一个代理程序(JNI程序)来实际操作目标原生函数,Java程序中则是jvm通过加载并调用此JNI程序来间接地调用目标原生函数。
  四、JNI调用
  JNI技术,它是一种双向的接口,使得开发者可以通过Java代码调用到各种native的库,反之亦然。简单来说,JNI可以实现Java调用C/C++,同时C/C++也可调用Java。
  Java访问C/C++
  Java如何调用C/C++的呢?在调用之前java是不会关心是否已经实现,只有在调用native方法的时候,去找C生成的动态库,如果找不到动态库,那么native方法就会报错。
  java的native函数和C中的函数存在一种映射关系,这个映射关系就是遵循的一种协议或者称为规则。
  比如,Framework中AssetManager类的成员函数init是一个JNI函数:
  private native final void init();
  它是由C++层的函数android_content_AssetManager_init来实现的:
  static void android_content_AssetManager_init(JNIEnv*env,jobject obj){…}
  在C中的规则就是,包名+类名+方法名,并且中间用下划线分割。
  第一个参数env,是JNIEnv对象,该对象代表一个Java虚拟机所运行的环境,通过它可以访问JVM内部的各种对象;
  第二个参数jobject是调用该函数的对象,上面的例子指的就是AssetManager对象;每个这样的C函数的参数至少有这两个参数,如果native函数里有多个参数,依次在后面排列,java的数据类型和JNI中的数据类型对应关系。
  当java调用native函数时,编译器会向native引擎传递调用者的包名,函数名及参数类型,native引擎根据这些信息决定应该调用具体的的哪个函数。
  在android中,native引擎中的AndroidRuntime类提供了一个registerNativeMethods()函数,通过此函数定义java方法和C函数的映射关系。
  C/C++访问java
  C访问java,监听回调中常有使用。
  由于java中的函数在native引擎中并没有直接的函数指针,java函数只能由java引擎去执行,而不是C。所以访问java不能通过指针,只能通过参数接口。
  java访问c的时候,把类名,函数名,参数类型传递给native引擎,然后由native引擎处理C函数,同理,C调用java时,也需要把想要访问的类名、函数名、参数传递给java引擎。
  五、Android中的*.SDK
  Jar包和.so文件(libs目录下)
  .so库
  NDK编译出来的动态链接库,一些重要的加密算法或者核心协议一般都用c写然后给java调用。这样可以避免反编译后查看到应用的源码。
  .so库又该如何存放
  存放.so库,主要针对不同的设备兼容,也可以说是专门针对不同Android手机下CPU架构的兼容。Android系统目前支持以下七种不同的CPU架构:ARMv5,ARMv7,x86,MIPS,ARMv8,MIPS64和x86_64,每一种都关联着一个相应的ABI。项目中主要支持已下四种(libs目录下):
  每个目录下都放置对应的.so(不同构架目录)
  以上是小编对JNI的初步了解,学习过程中对测试项目中sdk调用有了进一步的认识。欢迎小伙伴留言探讨,批评指正,共同进步!



上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号