SO和CPU架构
.so 文件,ABI 和 CPU 架构
CPU 架构
- ARMv5
早期 - ARMv7
2010 年起 - X86
2011 年起 - MIPS
2012 年起 - ARMv8
2014 年起 - MIPS64
2014 年起 - X86_64
2014 年起
在 Android 系统,每一个 CPU 架构对应一个 ABI,都定义了一种 ABI,ABI 决定了二进制文件如何与系统进行交互:
armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64。
ABI(Application Binary Interface)
应用程序二进制接口 ABI,定义了二进制文件 (尤其是.so 文件) 如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。
ABI 和 CPU 架构关系
- 很多设备都支持多余一种 ABI
- 当一个应用安装在设备上,只有该设备支持的 CPU 架构对应的.so 文件会被安装
最好是针对特定平台提供相应平台的二进制包,这种情况下运行时就少了一个模拟层(例如 x86 设备上模拟 arm 的虚拟层),从而得到更好的性能(归功于最近的架构更新,例如硬件 fpu,更多的寄存器,更好的向量化等)。
我们可以通过 Build.SUPPORTED_ABIS
得到根据偏好排序的设备支持的 ABI 列表。但你不应该从你的应用程序中读取它,因为 Android 包管理器安装 APK 时,会自动选择 APK 包中为对应系统 ABI 预编译好的.so 文件,如果在对应的 src/main/jniLibs
目录中存在.so 文件的话。
CPU 架构支持的(纵向)ABI(横向) | armeabi | armeabi-v7a | arm64-v8a | mips | mips64 | x86 | x86_64 |
---|---|---|---|---|---|---|---|
ARMv5 | 支持 | ||||||
ARMv7 | 支持 | 支持 | |||||
ARMv8 | 支持 | 支持 | 支持 | ||||
MIPS | 支持 | ||||||
MIPS64 | 支持 | 支持 | |||||
x86 | 支持 | 支持 | 支持 | ||||
x86_64 | 支持 | 支持 | 支持 |
解析:
- x86 设备上,libs/x86 目录中如果存在.so 文件的话,会被安装,如果不存在,则会选择 armeabi-v7a 中的.so 文件,如果也不存在,则选择 armeabi 目录中的.so 文件。
- x86 设备能够很好的运行 ARM 类型函数库,但并不保证 100% 不发生 crash,特别是对旧设备。
- 64 位设备(arm64-v8a, x86_64, mips64)能够运行 32 位的函数库,但是以 32 位模式运行,在 64 位平台上运行 32 位版本的 ART 和 Android 组件,将丢失专为 64 位优化过的性能(ART,webview,media 等等)。
- armeabi 的 SO 文件基本上可以说是万金油,它能运行在除了 mips 和 mips64 的设备上,但在非 armeabi 设备上运行性能还是有所损耗;
- 64 位的 CPU 架构总能向下兼容其对应的 32 位指令集,如:x86_64 兼容 X86,arm64-v8a 兼容 armeabi-v7a,mips64 兼容 mips;
参考
关于 Android 的.so 文件你所需要知道的
http://www.jianshu.com/p/cb05698a1968
与 .so 有关的一个长年大坑
https://zhuanlan.zhihu.com/p/21359984
so 的问题
百度地图,三星 s7 加载 so 库失败 log:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
09-26 15:40:15.184 21661-21661/com.useus.cs E/NativeLoader: loadException
java.lang.UnsatisfiedLinkError: dlopen failed: "/data/data/com.useus.cs/files/libs/libBaiduMapSDK_base_v4_0_0.so" is 32-bit instead of 64-bit
at java.lang.Runtime.load(Runtime.java:332)
at java.lang.System.load(System.java:1069)
at com.baidu.platform.comapi.NativeLoader.f(Unknown Source)
at com.baidu.platform.comapi.NativeLoader.a(Unknown Source)
at com.baidu.platform.comapi.NativeLoader.c(Unknown Source)
at com.baidu.platform.comapi.NativeLoader.loadCustomizeNativeLibrary(Unknown Source)
at com.baidu.platform.comapi.NativeLoader.loadLibrary(Unknown Source)
at com.baidu.platform.comapi.a.<clinit>(Unknown Source)
at com.baidu.platform.comapi.c.a(Unknown Source)
at com.baidu.mapapi.SDKInitializer.initialize(Unknown Source)
at com.baidu.mapapi.SDKInitializer.initialize(Unknown Source)
at com.useus.cs.base.BaseApplication.initBaiduMap(BaseApplication.java:129)
at com.useus.cs.base.BaseApplication.init(BaseApplication.java:69)
at com.useus.cs.base.BaseApplication.onCreate(BaseApplication.java:53)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1036)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6324)
at android.app.ActivityThread.access$1800(ActivityThread.java:221)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1860)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7232)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
09-26 15:40:15.184 21661-21661/com.useus.cs E/NativeLoader: BaiduMapSDK_base_v4_0_0 Failed to load.
09-26 15:40:15.184 21661-21661/com.useus.cs E/art: No implementation found for int com.baidu.platform.comjni.engine.JNIEngine.initClass(java.lang.Object, int) (tried Java_com_baidu_platform_comjni_engine_JNIEngine_initClass and Java_com_baidu_platform_comjni_engine_JNIEngine_initClass__Ljava_lang_Object_2I)
分析
ABI 兼容的选择。因为如果全部都适配的话,包很大,这样兼容那些用户数极少的 cpu 就很不划算,所以我只适配了 armeabi
,armeabi-v7a
以及 x86
。但是在三星 S7(ARMv8 架构 CPU) 应该会向下兼容的,但是提示缺报错。由于引入了阿里百川的兼容包 feedbackSdk.aar
,里面有各个平台的.so 文件,也就是阿里百川做了各个平台的兼容,所以它创建了各个兼容的平台目录,因为只要出现了这个目录,系统就只会在这个目录里找.so 文件而不会遍历其他的目录,所以就出现了之前找不到.so 文件的情况(因为其他目录没有我的.so 文件)。
解决
- 在
app/build.gradle
文件中进行 abi 的过滤
1
2
3
4
5
6
7
8
9
10
android {
// ...
defaultConfig {
// 过滤支持的abis
ndk {
abiFilters 'armeabi', 'armeabi-v7a', 'x86'
}
}
// ...
}
- 编译时会报错,在
gradle.properties
添加下面代码
1
android.useDeprecatedNdk=true
错误见:
1
2
Error:(36, 1) A problem occurred evaluating project ':app'.
> Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.