Android jniLibs下目录详解(.so文件)

作者: d26168ad953a | 来源:发表于2016-08-31 21:41 被阅读11452次

    最近又研究了一下,参考了一下:
    三星/联发科等处理器规格表  更新时间:2017年5月
    手机CPU架构体系分类及各大厂商 PS:我摘抄的
    分析:
    CPU:MIPS、ARM、X86三大架构
    armeabi系列:属于ARM (A7、A9、A15、A53、A57) 包含:高通、麒麟(华为海思)、澎湃(小米)、联发科、猎户座(三星Exynos)
    mips系列:属于MIPS ,多用在网关、猫、机顶盒等。代表:中国“龙芯”
    x86系列:pc模拟器、Intel Atom系列处理器(英特尔放弃应用于手机、PC、平板以及可穿戴设备的Atom处理器)
    综上所述(个人总结)
    时间:2017.5.19
    结果:"armeabi", "armeabi-v7a", "arm64-v8a"

    //代码:
    android {
        defaultConfig { 
            //Nuance自动生成的库文件夹中没有我们所需的so文件,所以按照上面的逻辑,
            //就应该是阻止自动生成我们不需要的文件夹或者下载相关的so文件放到对应的文件夹下面。
            //加入需要生成的文件夹//armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64
            ndk { abiFilters "armeabi", "armeabi-v7a", "arm64-v8a" }// 其他忽略
        }
    }
    

    有兴趣可以看一下:
    armeabi-v7a、armeabi、arm64-v8a 之间的区别

    .
    PS:如果只要结果,以下可以忽略,如果要深入,请继续。

    国际管理上图说明


    一图诠释Android的.so文件

    1、了解.so文件的原因:

    上周末参加AndroidBus开发者论坛[上海站],《小红书Android演进之路》(主讲:桑明明)提到.so文件,保留jniLibs下armeabi-v7a就可以了,这样就大大降低app的大小。这话是对的,因为我开发中也出现过这样的情况,jniLibs下所有的文件丢失了,app就小了两三兆(就一个友盟社会化分享)。but有bug(有的手机会崩溃)。保留一个试了,没有崩溃,然后再网上各种恶补.so文件的知识,cpu架构。


    2、Android开发中常见的指令集体系?

     指令集         厂商    位数 
    x86(x86)            Intel    32
    x86_64(Intel 64)       Intel    64
    arm64-v8a(ARMV8-A)    AMR    64
    armeabi(ARM v5)        ARM    32
    armeabi-v7a(ARM v7)     ARM    32
    mips             MIPS    32
    mips64           MIPS    64
    

    • Intel 64 指令集在 x86基础上扩展的
    • armabi 是针对旧的或者普通的ARM v5 CPU
    • armabi-v7a 是针对ARM v7 CPU
    • arm64-v8a 是针对最新的 ARM v8a CPU的。

    特别注意:x86指令集有两种CPU位,既有32位的,也有64位的。

    更多指令集知识

    3、以下概念是整理加工出来的

    我的参考

    4、Android系统每一个CPU架构对应一个ABI

    如上图【一图诠释Android的.so文件】
      Android系统目前支持以下七种不同的CPU架构,每一种都关联着一个相应的ABI。应用程序二进制接口(Application Binary Interface)定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。

    5、为什么你需要重点关注.so文件

    如果项目中使用到了NDK(类似于JDK,因为版权问题谷歌自行开发了NDK),它将会生成.so文件,因此显然你已经在关注它了。如果只是使用Java语言进行编码,你可能在想不需要关注.so文件了吧,因为Java是跨平台的。但事实上,即使你在项目中只是使用Java语言,很多情况下,你可能并没有意识到项目中依赖的函数库或者引擎库里面已经嵌入了.so文件,并依赖于不同的ABI。例如,项目中使用RenderScript支持库,OpenCV,Unity,android-gif-drawable,SQLCipher等,你都已经在生成的APK文件中包含.so文件了,而你需要关注.so文件。

    6、查看手机cpu架构

    adb device  查看连接的设备,
        adb -s 192.168.56.101:5555 shell  进入手机的shell设置模式,
        cat /proc/cpuinfo  查看手机CPU信息


    查看手机CPU信息的命令)

    或者搜:本地库监视器Native Libs Monitor(其包名:com.xh.nativelibsmonitor.app

    Android应用支持的ABI取决于APK中位于lib/ABI目录中的.so文件,其中ABI可能是上面说过的七种ABI中的一种。
      很多设备都支持多于一种的ABI。例如ARM64和x86设备也可以同时运行armeabi-v7a和armeabi的二进制包。但最好是针对特定平台提供相应平台的二进制包,这种情况下运行时就少了一个模拟层(例如x86设备上模拟arm的虚拟层),从而得到更好的性能(归功于最近的架构更新,例如硬件fpu,更多的寄存器,更好的向量化等)。
      我们可以通过Build.SUPPORTED_ABIS得到根据偏好排序的设备支持的ABI列表。但你不应该从你的应用程序中读取它,因为Android包管理器安装APK时,会自动选择APK包中为对应系统ABI预编译好的.so文件,如果在对应的lib/ABI目录中存在.so文件的话。

    7、由于.so文件出错的情况

    7.1、处理.so法则和系统的选择

    处理.so文件时有一条简单却并不知名的重要法则:你应该尽可能的提供专为每个ABI优化过的.so文件,但要么全部支持,要么都不支持:你不应该混合着使用。你应该为每个ABI目录提供对应的.so文件。
      当一个应用安装在设备上,只有该设备支持的CPU架构对应的.so文件会被安装。在x86设备上,libs/x86目录中如果存在.so文件的话,会被安装,如果不存在,则会选择armeabi-v7a中的.so文件,如果也不存在,则选择armeabi目录中的.so文件(因为x86设备也支持armeabi-v7a和armeabi)。

    7.2、常见crash(崩溃)系列

    当你引入一个.so文件时,不止影响到CPU架构。我从其他开发者那里可以看到一系列常见的错误,其中最多的是"UnsatisfiedLinkError","dlopen: failed"以及其他类型的crash或者低下的性能:使用android-21平台版本编译的.so文件运行在android-15的设备上,使用NDK时,你可能会倾向于使用最新的编译平台,但事实上这是错误的,因为NDK平台不是后向兼容的,而是前向兼容的。推荐使用app的minSdkVersion对应的编译平台。这也意味着当你引入一个预编译好的.so文件时,你需要检查它被编译所用的平台版本。

    7.3、混合使用不同C++运行时编译的.so文件

    .so文件可以依赖于不同的C++运行时,静态编译或者动态加载。混合使用不同版本的C++运行时可能导致很多奇怪的crash,是应该避免的。作为一个经验法则,当只有一个.so文件时,静态编译C++运行时是没问题的,否则当存在多个.so文件时,应该让所有的.so文件都动态链接相同的C++运行时。这意味着当引入一个新的预编译.so文件,而且项目中还存在其他的.so文件时,我们需要首先确认新引入的.so文件使用的C++运行时是否和已经存在的.so文件一致。

    7.4、如果没有为每个支持的CPU架构提供对应的.so文件

    这一点在前文已经说到了,但你应该真的特别注意它,因为它可能发生在根本没有意识到的情况下。例如:你的app支持armeabi-v7a和x86架构,然后使用Android Studio新增了一个函数库依赖,这个函数库包含.so文件并支持更多的CPU架构。如友盟社会化分享jar包带有各种.so文件,放在jniLibs下的对应文件夹中。

    7.5、在我们发布app后

    会发现它在某些设备上会发生Crash,最终可以发现只有64位目录下的.so文件被安装进手机。
      解决方案:重新编译我们的.so文件使其支持缺失的ABIs,或者设置:ndk.abiFilters 显示指定支持的ABIs。(最后一点:如果你是一个SDK提供者,但提供的函数库不支持所有的ABIs,那你将会搞砸你的用户,因为他们能支持的ABIs必将只能少于你提供的。)

    7.6、将.so文件放在错误的地方
    我们往往很容易对.so文件应该放在或者生成到哪里感到困惑,下面是一个总结:
    • Android Studio工程放在jniLibs/ABI目录中(当然也可以通过在build.gradle文件中的设置jniLibs.srcDir属性自己指定)
    • Eclipse工程放在libs/ABI目录中(这也是ndk-build命令默认生成.so文件的目录)
    • AAR压缩包中位于jni/ABI目录中(.so文件会自动包含到引用AAR压缩包的APK中)
    • 最终APK文件中的lib/ABI目录中
    • 通过PackageManager安装后,在小于Android 5.0的系统中,.so文件位于app的nativeLibraryPath目录中;在大于等于Android 5.0的系统中,.so文件位于app的nativeLibraryRootDir/CPU_ARCH目录中。
    7.7、只提供armeabi架构的.so文件而忽略其他ABIs的

    所有的x86/x86_64/armeabi-v7a/arm64-v8a设备都支持armeabi架构的.so文件,因此似乎移除其他ABIs的.so文件是一个减少APK大小的好技巧。但事实上并不是:这不只影响到函数库的性能和兼容性。x86设备能够很好的运行ARM类型函数库,但并不保证100%不发生crash,特别是对旧设备。64位设备(arm64-v8a, x86_64, mips64)能够运行32位的函数库,但是以32位模式运行,在64位平台上运行32位版本的ART和Android组件,将丢失专为64位优化过的性能(ART,webview,media等等)。

    6.7、以减少APK包大小为由是一个错误的借口

    因为你也可以选择在应用市场上传指定ABI版本的APK,生成不同ABI版本的APK可以在build.gradle中如下配置:

    android {
    
        ... 
    
        splits {
            abi {
                enable true
                reset()
                include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //select ABIs to build APKs for
                universalApk true //generate an additional APK that contains all the ABIs
            }
        }
    
        // map for the version code
        project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]
    
        android.applicationVariants.all { variant ->
            // assign different version code for each output
            variant.outputs.each { output ->
                output.versionCodeOverride =
                        project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode
            }
        }
     }
    

    .
    .
    .

    .
    纯纯干货兴味索然
    感谢阅读收获归你
    不妥之处敬请指教

    加我微信 共同探讨

    相关文章

      网友评论

      • 很正直的人:先赞一下:frowning:
      • 老山羊Shawn:x86_64 应该是AMD64
      • captainary:楼主在不,看了你的文章几遍,还是不是我懂,我的理解:

        因为每个ABI的目录的.so的数量都必须一样,假设其中一个SDK提供了三个目录的ABI,另外一个SDK只提供了两个,那我就删掉第三个目录,因为要保证每一个目录的.so都一样的.

        然后这么多也不能保证百分百不能crash,特别是一些比较旧的机器

        那问题来了,因为第一个SDK的第三个目录被删除了,出现这个Crash,要怎么解决呢?
        captainary: @鸿鹄之志_8395 这种情况就没办法了,毕竟机型是少数的,倘若一定要解决,可以添加那个包的文件,但是可能导致其他没有的第三方闪退。
        所以最好详细分析利弊,跟技术负责人报告做决定
        f1d9e34a17b0:请问您的问题解决了吗?我也遇到了这个问题
      • Jaycee88:不错,学到不少!

      本文标题:Android jniLibs下目录详解(.so文件)

      本文链接:https://www.haomeiwen.com/subject/xuqcettx.html