早期的Android系统差点儿仅仅支持ARMv5的CPU架构,你知道如今它支持多少种吗?7种。

Android系统眼下支持以下七种不同的CPU架构:ARMv5。ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8,MIPS64和x86_64 (从2014年起),每一种都关联着一个相应的ABI。

应用程序二进制接口(Application Binary Interface)定义了二进制文件(尤其是.so文件)怎样执行在相应的系统平台上。从使用的指令集,内存对齐到可用的系统函数库。

在Android系统上。每一个CPU架构相应一个ABI:armeabi,armeabi-v7a,x86。mips,arm64-v8a,mips64,x86_64。

1.为什么你须要重点关注.so文件

假设项目中使用到了NDK,它将会生成.so文件,因此显然你已经在关注它了。假设仅仅是使用Java语言进行编码,你可能在想不须要关注.so文件了吧,由于Java是跨平台的。

但其实,即使你在项目中仅仅是使用Java语言,非常多情况下,你可能并没有意识到项目中依赖的函数库或者引擎库里面已经嵌入了.so文件,并依赖于不同的ABI。

比如,项目中使用RenderScript支持库,OpenCV。Unity,android-gif-drawable,SQLCipher等,你都已经在生成的APK文件里包括.so文件了。而你须要关注.so文件。

Android应用支持的ABI取决于APK中位于lib/ABI文件夹中的.so文件。当中ABI可能是上面说过的七种ABI中的一种。

Native Libs Monitor 这个应用能够帮助我们理解手机上安装的APK用到了哪些.so文件,以及.so文件来源于哪些函数库或者框架。

当然。我们也能够自己对app反编译来获取这些信息,只是相对麻烦一些。

非常多设备都支持多于一种的ABI。比如ARM64和x86设备也能够同一时候执行armeabi-v7a和armeabi的二进制包。

但最好是针对特定平台提供相应平台的二进制包。这样的情况下执行时就少了一个模拟层(比如x86设备上模拟arm的虚拟层),从而得到更好的性能(归功于近期的架构更新,比如硬件fpu。很多其它的寄存器,更好的向量化等)。

我们能够通过Build.SUPPORTED_ABIS得到依据偏好排序的设备支持的ABI列表。但你不应该从你的应用程序中读取它,由于Android包管理器安装APK时,会自己主动选择APK包中为相应系统ABI预编译好的.so文件,假设在相应的lib/ABI文件夹中存在.so文件的话。

2.App中可能出错的地方

处理.so文件时有一条简单却并不知名的重要法则。

你应该尽可能的提供专为每一个ABI优化过的.so文件,但要么全部支持。要么都不支持:你不应该混合着使用。你应该为每一个ABI文件夹提供相应的.so文件。

当一个应用安装在设备上。仅仅有该设备支持的CPU架构相应的.so文件会被安装。

在x86设备上,libs/x86文件夹中假设存在.so文件的话。会被安装,假设不存在,则会选择armeabi-v7a中的.so文件。假设也不存在,则选择armeabi文件夹中的.so文件(由于x86设备也支持armeabi-v7a和armeabi)。

3.其它地方也可能出错

当你引入一个.so文件时,不止影响到CPU架构。我从其它开发人员那里能够看到一系列常见的错误,当中最多的是"UnsatisfiedLinkError","dlopen: failed"以及其它类型的crash或者低下的性能:

使用android-21平台版本号编译的.so文件执行在android-15的设备上

使用NDK时。你可能会倾向于使用最新的编译平台,但其实这是错误的,由于NDK平台不是后向兼容的,而是前向兼容的。推荐使用app的minSdkVersion相应的编译平台。

这也意味着当你引入一个预编译好的.so文件时,你须要检查它被编译所用的平台版本号。

4.混合使用不同C++执行时编译的.so文件

.so文件能够依赖于不同的C++执行时,静态编译或者动态载入。混合使用不同版本号的C++执行时可能导致非常多奇怪的crash,是应该避免的。

作为一个经验法则。当仅仅有一个.so文件时,静态编译C++执行时是没问题的,否则当存在多个.so文件时。应该让全部的.so文件都动态链接同样的C++执行时。

这意味着当引入一个新的预编译.so文件,并且项目中还存在其它的.so文件时。我们须要首先确认新引入的.so文件使用的C++执行时是否和已经存在的.so文件一致。

5.没有为每一个支持的CPU架构提供相应的.so文件

这一点在前文已经说到了,但你应该真的特别注意它,由于它可能发生在根本没有意识到的情况下。

比如:你的app支持armeabi-v7a和x86架构。然后使用Android Studio新增了一个函数库依赖,这个函数库包括.so文件并支持很多其它的CPU架构,比如新增android-gif-drawable函数库:

compile ‘pl.droidsonroids.gif:android-gif-drawable:1.1.+’

公布我们的app后,会发现它在某些设备上会发生Crash,比如Galaxy S6,终于能够发现仅仅有64位文件夹下的.so文件被安装进手机。

解决方式:又一次编译我们的.so文件使其支持缺失的ABIs,或者设置

ndk.abiFilters

显示指定支持的ABIs。

最后一点: 假设你是一个SDK提供者,但提供的函数库不支持全部的ABIs。那你将会搞砸你的用户,由于他们能支持的ABIs必将仅仅能少于你提供的。

将.so文件放在错误的地方

我们往往非常easy对.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文件夹中。

仅仅提供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等等)。

以降低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
}
}
}

关于Android的.so文件所须要知道的的更多相关文章

  1. Linux内核:关于中断你须要知道的

    1.中断处理程序与其它内核函数真正的差别在于,中断处理程序是被内核调用来对应中断的,而它们执行于中断上下文(原子上下文)中,在该上下文中执行的代码不可堵塞. 中断就是由硬件打断操作系统. 2.异常与中 ...

  2. 在Linux终端管理文件你要知道的11个命令

    LS - 列表文件 ls命令列出目录中的文件. 默认情况下,使用ls列出当前目录下的文件. 2 你也可以列出文件递归-也就是说,列出所有文件在当前目录中的目录-使用ls -R.LS还可以列出在其他目录 ...

  3. 每一个JavaScript开发者都应该知道的10道面试题

    JavaScript十分特别.而且差点儿在每一个大型应用中起着至关关键的数据.那么,究竟是什么使JavaScript显得与众不同,意义非凡? 这里有一些问题将帮助你了解其真正的奥妙所在:   1.你能 ...

  4. Android AndroidManifest 清单文件以及权限具体解释

    每一个Android应用都须要一个名为AndroidManifest.xml的程序清单文件,这个清单文件名称是固定的而且放在每一个Android应用的根文件夹下.它定义了该应用对于Android系统来 ...

  5. android 上传文件

    android对于上传文件,还是非常easy的,和java里面的上传都是一样的,基本上都是熟悉操作输出流和输入流!另一个特别重要的就是须要一些content-type这些參数的配置!  假设这些都弄好 ...

  6. Android 程序员必须知道的 53 个知识点

    1. android 单实例运行方法 我们都知道 Android 平台没有任务管理器,而内部 App 维护者一个 Activity history stack 来实现窗口显示和销毁,对于常规从快捷方式 ...

  7. 为什么 Android Studio 工程文件夹占用空间这么大?我们来给它减减肥

    偶然中发现Android Studio的工程文件夹比ADT Bundle的大很多.用Android Studio新建一个空工程,工程文件夹大小为30M,运行一次后大小为40M.同样用ADT Bundl ...

  8. android 打开各种文件(setDataAndType)转:

    android 打开各种文件(setDataAndType) 博客分类: android-->非界面 android 打开各种文件 setDataAndType action动作  转自:htt ...

  9. 如何查看Android的Keystore文件的SHA1值

    像使用百度地图api时候,一般需要获取keystore的SHA1值,这里就手把手教大家如何查看Android的keystore文件中的SHA1值. 第一步: 打开cmd,切换到keystore所在的文 ...

随机推荐

  1. Android 开发最佳实践

    原文地址:https://github.com/futurice/android-best-practices/blob/master/translations/Chinese/README.cn.m ...

  2. Qt on Android:资源文件系统qrc与assets

    使用 Qt 为 Android 开发应用时,有时我们的应用会携带一些资源文件,如 png . jpg 等,也可能有一些配置文件,如 xml 等.这些文件放在哪里呢? 有两种方式: qrc assets ...

  3. 2014.04.17,转帖,关于FFT的结果为什么要除以N

    http://www.chinavib.com/forum/viewthread.php?tid=23665&highlight= 关于这个问题,我看到的书好像都没有进行解释,这里我试着解释下 ...

  4. kentico在使用局域网ip访问的时候提示Missing license或者Invalid website

    Missing license Requested URL: http://172.31.212.20/kentico10/ License status: Missing license If yo ...

  5. 利用CSS3中的clac()实现按照屏幕分辨率自适应宽度

    1.简介 calc()看其外表像个函数.平时在制作页面的时候,总会碰到有的元素是100%的宽度(例如body元素).如果元素宽度为100%时,其自身不带其他盒模型属性设置还好,要是有别的,那将导致盒子 ...

  6. firefox工具

    1.XPath 查看元素的xpath https://addons.mozilla.org/zh-CN/firefox/addon/xpath-checker/ 2. Tamper Data 查看页面 ...

  7. Grand Central Dispatch-thread pool pattern

    Grand Central Dispatch (GCD) is a technology developed by Apple Inc. to optimize application support ...

  8. leetcode525. 连续数组 python

    给定一个二进制数组, 找到含有相同数量的 0 和 1 的最长连续子数组. 示例 1: 输入: [0,1] 输出: 2 说明: [0, 1] 是具有相同数量0和1的最长连续子数组. 示例 2: 输入: ...

  9. sublime text3安装js提示的插件

    今天安装Sublime Text3的js插件,在网上查了很多资料,为了方便以后看,写一个安装插件的总结和方法. 要安装js相关的插件,就要先安装一个Package Control(插件管理器)的插件, ...

  10. LD_DEBUG

    LD_DEBUG 是 glibc 中的 loader 为了方便自身调试而设置的一个环境变量.通过设置这个环境变量,可以方便的看到 loader 的加载过程. LD_DEBUG=help ./main ...