Android NDK 编程 - 架构和CPU

文章目录[x]
  1. 1:Android ABI
  2. 1.1:支持的ABI
  3. 2:为特定的ABI生成代码
  4. 3:Android 平台上的 ABI 管理
  5. 3.1:应用软件包中的原生代码
  6. 3.2:Android平台ABI支持
  7. 3.3:安装时自动解压缩原生代码

    在编写c/c++代码时,硬件很重要。NDK 提供各种 ABI 供我们选择,可确保针对正确的架构和 CPU 进行编译。

Android ABI

    不同的 Android 设备使用不同的 CPU,而不同的 CPU 支持不同的指令集。CPU 与指令集的每种组合都有专属的应用二进制接口 (ABI)。ABI 包含以下信息:

  • 可使用的 CPU 指令集(和扩展指令集)。
  • 运行时内存存储和加载的字节顺序。Android 始终是 little-endian
  • 在应用和系统之间传递数据的规范(包括对齐限制),以及系统调用函数时如何使用堆栈和寄存器。
  • 可执行二进制文件(例如程序和共享库)的格式,以及它们支持的内容类型。Android 始终使用 ELF
  • 如何重整 C++ 名称。

    ABI 还可以指平台支持的原生 API

支持的ABI

支持的ABI 支持的指令集 备注
armeabi-v7a   armeabi,Thumb-2,VFPv3-D16 与ARMv5/v6设备不兼容
arm64-v8a AArch64
 x86和x86_64 x86,x86-64,MMX等

    注意:ndk以前支持ARMv5(armeabi)以及32位和64位MIPS,但ndk r17已经不再支持。

armeabi-v7a

    ABI 适用于基于 32 位 ARMCPUAndroid 变体包含 Thumb-2VFP 硬件浮点指令(具体而言就是 VFPv3-D16),其中包含 16 个专用 64 位浮点寄存器。

    armeabi-v7a ABI 使用 -mfloat-abi=softfp 来强制实施以下规则:虽然系统可以执行浮点代码,但编译器在调用函数时必须传递整数寄存器中的所有 float 值以及整数寄存器对中的所有 double 值。

arm64-v8a

    ABI 适用于基于 ARMv8-ACPU,支持 64 位 AArch64 架构。它包含高级 SIMD (Neon) 架构扩展指令集。

x86

    ABI 适用于支持通常称为“x86”、“i386”或“IA-32”的指令集的 CPU

x86_64

    ABI 适用于支持通常称为“x86-64”的指令集的 CPU

为特定的ABI生成代码

    默认情况下,Gradle会针对所有非弃用 ABI 进行构建。要限制应用支持的 ABI 集,可以使用 abiFilters。例如,要仅针对 64 位 ABI 进行构建,可以在 build.gradle 中设置以下配置:

android {
 defaultConfig {
 ndk {
     abiFilters 'arm64-v8a', 'x86_64'
 }
 }
}

    构建系统的默认行为是将每个 ABI 的二进制文件包括在单个 APK内。与仅包含单个 ABI 的二进制文件的 APK 相比, 要大得多;要权衡的是兼容性更广,但 APK 更大。同时仍保持最大限度的设备兼容性,一般armeabi-v7a就支持了大部分机型。

Android 平台上的 ABI 管理

应用软件包中的原生代码

    Android系统可以在 APK 中符合以下格式的文件路径上找到 NDK 生成的库:

/lib/<abi>/lib<name>.so

    其中,<abi> 是上面列出的 ABI 名称之一,<name> 是定义库时使用的库名称。由于 APK 文件只是 zip 文件。如果系统在预期位置找不到原生共享库,便无法使用它们。在这种情况下,应用本身必须复制这些库,然后执行 dlopen()

    在不过滤ABI的情况下,一般会包含如下库:

/lib/armeabi/libfoo.so
/lib/armeabi-v7a/libfoo.so
/lib/arm64-v8a/libfoo.so
/lib/x86/libfoo.so
/lib/x86_64/libfoo.so

Android平台ABI支持

Android系统在运行时知道它支持某种ABI,因为构建特定的系统属性会指示:

  • 设备的主要 ABI,与系统映像本身使用的机器代码对应。
  • 可选)与系统映像也支持的其他 ABI 对应的辅助 ABI。

    此机制确保系统在安装时从软件包提取最佳机器代码。

    为实现最佳性能,应直接针对主要 ABI 进行编译。例如,基于 ARMv5TE 的典型设备只会定义主 ABI:armeabi。相反,基于 ARMv7 的典型设备将主 ABI 定义为 armeabi-v7a,并将辅助 ABI 定义为 armeabi,因为它可以运行为每个 ABI 生成的应用原生二进制文件。

     64 位设备也支持其 32 位变体。以 arm64-v8a 设备为例,该设备也可以运行 armeabi 和 armeabi-v7a 代码。但注意,如果应用以 arm64-v8a 为目标,而非依赖于运行 armeabi-v7a 版应用的设备,则应用在 64 位设备上的性能要好得多。

    许多基于 x86 的设备也可运行 armeabi-v7a 和 armeabi NDK 二进制文件。对于这些设备,主 ABI 将是 x86,辅助 ABI 是 armeabi-v7a。

安装时自动解压缩原生代码

    安装应用时,软件包管理器服务将扫描 APK,并查找以下形式的任何共享库:

lib/<primary-abi>/lib<name>.so

    如果未找到,并且已定义辅助 ABI,该服务将扫描以下形式的共享库:

lib/<secondary-abi>/lib<name>.so

    找到所需的库时,软件包管理器会将它们复制到应用的原生库目录 (<nativeLibraryDir>/) 下的 /lib/lib<name>.so

    如果根本没有共享对象文件,应用也会构建并安装,但在运行时会崩溃。

 

点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像

Title - Artist
0:00