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

    发布:51Code 时间: 2018-05-16 10:12

  • 一、前言 JNIJava与底层间的桥梁,Android系统中很多的使用了JNI,小编所在项目中核心模块有相关调用。测试中,也有遇到过JNI层的一些问题。理解JNI的调用实现,对于理解Android的代码有...

  • 一、前言

    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调用有了进一步的认识。欢迎小伙伴留言探讨,批评指正,共同进步!

    原文作者:baiyang
    来源:51testing软件测试网采编
    上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编caoxiaoyan@51testing.com,我们将立即处理

  • 上一篇:对混淆的Android应用进行渗透测试

    下一篇:Android测试——性能指标

网站导航
Copyright(C)51Code软件开发网 2003-2018 , 沪ICP备05003035号