共计 3172 个字符,预计需要花费 8 分钟才能阅读完成。
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.c
LOCAL_MODULE := test
LOCAL_MODULE_TAGS := optinal
include $(BUILD_EXECUTABLE)
参考文档:
Android ABI
Android 中 app 过程 ABI 确定过程
正文完