ABI
ABI 即 Application binary interface,是 CPU 与指令集专属的应用程序二进制接口。它定义了一套规定,容许编译好的二进制指标代码能在所有兼容该ABI的操作系统中无需改变就能运行。不同的 Android 设施应用不同的 CPU,而不同的 CPU 反对不同的指令集。
ABI 蕴含以下信息:
- 可应用的 CPU 指令集(和扩大指令集)。
- 运行时内存存储和加载的字节程序。Android 始终是 little-endian。
- 在利用和零碎之间传递数据的标准(包含对齐限度),以及零碎调用函数时如何应用堆栈和寄存器。
- 可执行二进制文件(例如程序和共享库)的格局,以及它们反对的内容类型。Android 始终应用 ELF。
- 如何重整 C++ 名称。
ABI 和指令集
- NDK 以前反对 ARMv5 (armeabi) 以及 32 位和 64 位 MIPS,但 NDK r17 已不再反对。
- APK 在门路
/lib/<abi>/lib<name>.so
中寻找 NDK 生成的库。 - 装置利用时,软件包管理器服务将扫描 APK,依照主辅及偏好程序查找共享库,将它们复制到利用的原生库目录 。
- 强制应用特定 ABI 装置 APK,通过
adb install --abi abi-identifier path_to_apk
。 - armeabi不反对硬件辅助的浮点运算,所有浮点运算都应用编译器的 libgcc.a 动态库中的软件辅助函数。
ABI | 反对的指令集 | 备注 |
---|---|---|
armeabi-v7a | armeabi,Thumb-2,VFPv3-D16 | 与 ARMv5/v6 设施不兼容。 |
arm64-v8a | AArch64 | |
x86 | x86 (IA-32),MMX,SSE/2/3,SSSE3 | 不反对 MOVBE 或 SSE4。 |
x86_64 | x86-64,MMX,SSE/2/3,SSSE3,SSE4.1、4.2,POPCNT |
ABI 与 CPU
- 大多数 CPU 都反对多种 ABI,其中一个为主 ABI,其余为辅助 ABI。
- 获得最佳性能,最好应用 CPU 的主 ABI。
- Android 零碎依据特定的零碎属性来决定主辅 ABI。
- x86设施蕴含ARM模仿层,可能很好地运行ARM类型的so库,但并不保障100%不产生Crash。
- 64位设施(arm64-v8a, x86_64, mips64)可能运行32位的so库。然而以32位模式运行时,会失落专为64位优化过的性能特色(ART, WebView, Media, etc.)。
CPU | 主ABI | 反对的ABI |
---|---|---|
ARMv5 | armeabi | armeabi |
ARMv7 | armeabi-v7a | armeabi ,armeabi-v7a |
ARMv8 | arm64-v8a | armeabi ,armeabi-v7a,arm64-v8a |
x86 | x86 | armeabi ,armeabi-v7a ,x86 |
x86_64 | x86_64 | armeabi ,x86 ,x86_64 |
ABI 的零碎属性
[ro.product.cpu.abilist] : [arm64-v8a, armeabi-v7a, armeabi][ro.product.cpu.abilist32] : [armeabi-v7a, armeabi][ro.product.cpu.abilist64] : [arm64-v8a]
ro.product.cpu.abilist
的值表明以后零碎所反对所有的ABI类型ro.product.cpu.abilist32
和ro.product.cpu.abilist64
别离示意零碎所反对的32位和64位的 ABI 类型。- 这些属性值中 ABI 的排序代表着零碎偏好。比方
ro.product.cpu.abilist
的值里arm64-v8a
排在第一个,就表明如果没有指定,arm64-v8a
就会成为 APP 过程默认启动的关联 ABI。
为利用指定 ABI
利用编译时,默认状况下,Gradle 会为所有 NDK 反对的 ABI 构建独立的 .so 文件,并将这些文件全副打包到您的利用中。如果您心愿 Gradle 仅构建和打包原生库的特定 ABI 配置,能够在模块级 build.gradle 文件中应用 ndk.abiFilters 标记指定这些配置,如下所示:
android { ... defaultConfig { ... externalNativeBuild { cmake {...} // or ndkBuild {...} } // Similar to other properties in the defaultConfig block, // you can configure the ndk block for each product flavor // in your build configuration. ndk { // Specifies the ABI configurations of your native // libraries Gradle should build and package with your app. abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a' } } buildTypes {...} externalNativeBuild {...}}
利用装置时 ABI 的确认
利用装置后,会在 /data/system/packages.xm
中增加记录,其中 primaryCpuAbi
决定了该利用应用的 ABI。 primaryCpuAbi
的具体确认过程见附件文档,总结流程如下:
- 如果 apk 包中 lib 文件夹下有 .so 库,就依据这个 .so 库的架构模式,确定 app 的
primaryCpuAbi
的值。 - 对于 system app, 如果没法通过第一步确定
primaryCpuAbi
的值,PKMS 会依据/system/app/${APP_NAME}/lib64
和/system/app/${APP_NAME}/lib
这两个文件夹是否存在,来确定它的primaryCpuAbi
的值。 - 对于还没有确定的 app, 在最初还会将本人的
primaryCpuAbi
值与和他应用雷同 UID 的 package 的值设成一样。 - 对于到这里还没有确认
primaryCpuAbi
的 app,就会在启动过程时应用ro.product.cpu.abilist
这个 property 的值的第一项作为它关联的 ABI。
ABI 的编译配置
Android.bp 通过 compile_multilib
来决定编译32位还是64位的 ABI。例如,
cc_binary { srcs: ["test.c"], name: "test", compile_multilib: "both", // 同时编译32位和64位 //compile_multilib: "32", // 只编译32位 //compile_multilib: "64", // 只编译64位 //compile_multilib: "first", // 依据主ABI的arch编译 //compile_multilib: "prefer32", // 如果零碎反对32位则编译32位,否则编译64位}
Android.mk 通过 LOCAL_MULTILIB
来管制编译。例如,
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS) LOCAL_MULTILIB := both # 同时编译32位和64位# LOCAL_MULTILIB := 32 # 只编译32位# LOCAL_MULTILIB := 64 # 只编译64位# LOCAL_MULTILIB := first # 依据主ABI的arch编译TARGET_PREFER_32_BIT := true # 如果零碎反对32位则编译32位,否则编译64位LOCAL_SRC_FILES := test.cLOCAL_MODULE := testLOCAL_MODULE_TAGS := optinalinclude $(BUILD_EXECUTABLE)
参考文档:
Android ABI
Android中app过程ABI确定过程