一、介绍
ARM:
是嵌入式中的一种架构,全称为Advanced RISC Machine,可以理解为ARM处理器(也就是cpu)。
ABI(Application Binary Interface):
应用程序二进制接口 描述了应用程序和操作系统之间,一个应用和它的库之间,或者应用的组成部分之间的低接口
通俗一点说就是: 不同android设备对应的cpu指令集不同,架构也不同,这样当我们需要使用cpu的时候就要寻找适合的指集、和架构.
Android目前支持以下7种ABIs: mips, mips64, X86, X86–64, arm64-v8a, armeabi, armeabi-v7a
Android设备的ABI:
通常设备的ABI有两种一种是主ABI,一种是辅ABI。
在系统选择ABI时会优先选择主ABI,如果不存在对应的则会选择辅的ABI:
总的来说,就是一个Android设备可以支持多种ABI,设备主ABI和辅助ABI,以arm64-v8a为主ABI的设备,辅助ABI为armeabi-v7a和armeabi,以armeabi-v7a为主ABI的设备,辅助ABI为armeabi。
ABI的作用:
我们在想使用c/c++的native库的时候,需要提供不同的编译包对应不同的cpu架构,也就是.so文件, 一般来说编译包.so提供的是全套的cpu架构,但是我们打包apk不需要全部都打包,因为这样会很大程度增大apk体积,所以ABI作用就在这里了,只提供对应的架构的编译包,也就是选择最合适、最兼容、性能最好的包,只需要在app下的build.gradle添加如下配置:
android{
defaultConfig{
ndk{ //指定 64位CPU使用32位so库(其他类型如v8a、x86等会被过滤掉)
abiFilters"armeabi-v7a"
}
}
}
在对应的jnilibs中配置好二、ABI与CPU关系
首先了解下不同ABI的简介:
armeabi: 仅支持ARMv5架构、仅支持软浮点运算,支持所有ARM*设备
armeabi-v7a: 支持ARMv7并向下兼容(辅ARMv5),支持硬浮点运算,目前大部分机型都为v7a.
arm64-v8a: 支持ARMv8并向下兼容(辅ABI:ARMv5、ARMv7), 同时包含32位(v7a)以及64位框架(v8a)
x86: 英特尔推出的32位框架 ,硬浮点运算,同时支持ARMv5架构以及ARMv7(同为32位),不过在ARMv5中会有性能损耗.
x86_64: 英特尔推出的64位框架,向下兼容x86、ARMv5,通样在性能上有所损耗
mips和mips_64: MIPS是一种高性能的嵌入式CPU构架,其出发点是高性能,主要用于路由器、猫等
可以看到不同CPU架构对应不同ABI支持情况
ABI支持情况ARMv5 设备:只支持armeabi
ARMv7 设备:支持 armeabi 和 armeabi-v7a
ARMv8 设备:支持 armeabi-v7a、armeabi 和 arm64-v8a
X86 设备:支持 armeabi(性能有所损耗) 和 x86
x86_64 设备:支持 x86 和 x86_64
mips 设备: 支持 mips
mips_64 设备:支持 mips 和 mips_64
三、ABI适配
前面了解了不同设备的支持情况,但是这些不同ABI是如何进行加载的呢?
ABI加载策略:
首先要明确,当前设备支持的ABI架构(主、辅架构)、以及当前项目配置的ABI
其次再看我们的加载流程:
以ARMv8的cpu框架为例也就是支持v8a的设备为例:
加载.so流程想要了解适配方案就要先了解软浮点运算(ARMv5)和硬浮点运算(ARMv7以上)
软浮点是通过浮点库去实现浮点运算的,效率低;硬浮点是通过浮点运算单元(FPU)来完成的,效率高。
(1)硬浮点(hard-float)
编译器将代码直接编译成硬件浮点协处理器(浮点运算单元FPU)能识别的指令,这些指令在执行的时候ARM核直接把它转给协处理器执行。FPU 通常有一套额外的寄存器来完成浮点参数传递和运算。使用实际的硬件浮点运算单元(FPU)会带来性能的提升。
(2)软浮点(soft-float)
编译器把浮点运算转成浮点运算的函数调用和库函数调用,没有FPU的指令调用,也没有浮点寄存器的参数传递。浮点参数的传递也是通过ARM寄存器或者堆栈完成。现在的Linux系统默认编译选择使用hard-float,如果系统没有任何浮点处理器单元,这就会产生非法指令和异常。因而一般的系统镜像都采用软浮点以兼容没有VFP的处理器。
了解了.so的加载策略,下面说下具体如何去适配.
适配方案:
1. 适配armeabi-v7a,市场上主流机型,可兼容大部分设备除非过老机型,android2.2以下版本一般会采用老的CPU架构,
这种适配方式,除去ARMv5架构的机型都可以适配.
2. 适配armeabi, 这种适配方式会兼容所有类型的CPU,但是需要注意的是如果你的.SO包含使用CPU核心或者说对CPU使用过大的话,不建议此种方式, 原因就是:目前主流为ARM7,上面也说了ARMv5架构为软浮点运算,而这种低效率算法在CPU使用上效率不如硬浮点算法,也就是ARMv7对应armeabi-v7a类型ABI。
3. 适配arm-v8a, 这种方式适配了ARMv8(64位)的机型,也就是说这种机型会向下兼容ARMv7(32位)以及ARMv5架构,但是忽略了部分使用ARMv7的机型。
目前的主流配置基本就这3中,你也可以同时适配多种,但是会增大apk体积, 还有一类问题就是第三方的库只支持armeabi,而我们的项目需要v7a这类去适配,这样2个库没有交集,我们该如何去选择适配?
第三方适配方案:
1. 首先要确定一个问题, 你在使用CPU中哪个库对CPU的使用需求量更大或者更主要,由于两种库冲突,我们必须合并适配,我们模拟v7a的这类库对CPU需求更大,那我们可以这样: 保留armeabi-v7a的库,将第三方的armeabi中的.so放入v7a中,这样我们统一了适配方案,前提是第三方库支持这样做.
2. 那如果第三方不支持这样,那我们需要用到另一个方案 : 将v7a库中的.so放入第三方的armeabi中, 这样也是将v7a合并到了armeabi中,但是由于咱们v7a对CPU需求大,不排除这样配置会导致cpu使用效率下降.
以上就是关于ABI适配的一些方案和问题有错误之处还望指教!
四、市场占有度
知道了适配方案,我们更要了解下市场上各个CPU类型的占有率,更容易让我们确定我们适配的方向:
ARMv5 设备:目前几乎遇不到这类机型,不排除特殊机型
ARMv7 设备:支持 armeabi 和 armeabi-v7a, 目前来说也是相对比较老的机型,一般是android 7.0以下的设备。
ARMv8 设备:支持 armeabi-v7a、armeabi 和 arm64-v8a,目前主流的类型,基本上主流机型,android10左右都是使用这类架构。
X86 设备:支持 armeabi(性能有所损耗) 和 x86
x86_64 设备:支持 x86 和 x86_64
mips 设备: 支持 mips
mips_64 设备:支持 mips 和 mips_64
网友评论