23ABI管理
23.1 ABI簡介
不同Android設備使用不同的CPU,因此支持不同的指令集。CPU與指令集的每種組合都有其自己的應用二進制界面(或 ABI)。 ABI可以非常精確地定義應用的機器代碼在運行時如何與系統交互。開發者必須爲應用要使用的每個 CPU架構指定ABI。
典型的ABI 包含以下信息:
機器代碼應使用的 CPU 指令集。
運行時內存存儲和加載的字節順序。
可執行二進制文件(例如程序和共享庫)的格式,以及它們支持的內容類型。
用於解析內容與系統之間數據的各種約定。這些約定包括對齊限制,以及系統如何使用堆棧和在調用函數時註冊。
運行時可用於機器代碼的函數符號列表 - 通常來自非常具體的庫集。
(Android系統採用小字節序 ARM GNU/Linux ABI)
23.2 支持的ABI
每個 ABI 支持一個或多個指令集,下表是每個 ABI 支持的指令集概:
ABI |
支持的指令集 |
說明 |
armeabi |
ARMV5TE 和更高版本 Thumb-1 |
無硬浮點。 |
armeabi-v7a |
armeabi Thumb-2 VFPv3-D16 其他(可選) |
與 ARMv5、v6 設備不兼容。 |
arm64-v8a |
AArch-64 |
|
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 |
|
mips |
MIPS32r1 及更高版本 |
使用硬浮點 |
mips64 |
MIPS64r6 |
(1)armeabi
此 ABI 適用於基於 ARM、至少支持 ARMv5TE 指令集的 CPU,不支持硬件輔助的浮點計算。相反,所有浮點運算都使用編譯器 libgcc.a 靜態庫中的軟件幫助程序函數。
此ABI 支持 ARM 的 Thumb(亦稱 Thumb-1)指令集。NDK 默認生成 Thumb 代碼,除非在 Android.mk 文件中使用 LOCAL_ARM_MODE 變量指定不同的行爲。
(2)armeabi-v7a
此ABI可擴展 armeabi 以包含多個 CPU 指令集擴展,包括:
Thumb-2 指令集擴展,其性能堪比 32 位 ARM 指令,簡潔性類似於 Thumb-1。
VFP 硬件 FPU 指令。更具體一點,包括 VFPv3-D16,它除了 ARM 核心中的 16 個 32 位寄存器之外,還包含 16 個專用 64 位浮點寄存器。
v7-a ARM 規格描述的其他擴展,包括 高級 SIMD(亦稱 NEON)、VFPv3-D32 和 ThumbEE,都是此 ABI 可選的。
(3)arm64-v8a
此 ABI 適用於基於 ARMv8、支持 AArch64 的 CPU。它還包含 NEON 和 VFPv4 指令集。
(4)x86
此ABI 適用於支持通常稱爲“x86”或“IA-32”的指令集的 CPU。
(5)x86_64
此ABI 適用於支持通常稱爲“x86-64”的指令集的 CPU。
(6)mips
此ABI 適用於基於 MIPS、至少支持 MIPS32r1指令集的 CPU。
(7)mips64
此ABI 適用於 MIPS64 R6。
23.3 爲特定ABI生成代碼
默認情況下,NDK 爲 armeabi ABI生成機器代碼。但可以通過向 Application.mk文件添加以下行生成 ARMv7-a 兼容的機器代碼:
APP_ABI := armeabi-v7a
要爲兩個或更多不同的 ABI 構建機器代碼,請使用空格作爲分隔符。例如:
APP_ABI := armeabi armeabi-v7a
此設置指示 NDK 爲機器代碼構建兩個版本:此行中所列的每個 ABI 一個。
構建多個機器代碼版本時,構建系統會將庫複製到應用項目路徑,並最終將它們封裝到 APK 中,從而創建一個胖二進制文件。 胖二進制文件大於只包含一個系統的機器代碼的二進制文件;權衡方式是兼容性更廣,但 APK 更大。
在安裝時,軟件包管理器只解包最適合目標設備的機器代碼。
23.4 Android平臺上的ABI管理
Android的軟件包管理器預期在 APK中符合以下模式的文件路徑上查找 NDK 生成的庫:
/lib/<abi>/lib<name>.so
這裏的 <abi> 是支持的ABI 下面列出的 ABI 名稱之一,<name> 是爲 Android.mk文件中的 LOCAL_MODULE 變量定義庫時使用的庫名稱。 由於 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
/lib/mips/libfoo.so
/lib/mips64/libfoo.so
23.5 Android平臺ABI支持
Android 系統在運行時知道它支持哪些 ABI,因爲版本特定的系統屬性會指示:
設備的主要ABI,與系統映像本身使用的機器代碼對應。
可選的輔助ABI,與系統映像也支持的另一個ABI 對應。
此機制確保系統在安裝時從軟件包提取最佳機器代碼。
爲實現最佳性能,應直接針對主要 ABI 進行編譯。例如,基於 ARMv5TE 的典型設備只會定義主要 ABI:armeabi。相反,基於 ARMv7 的典型設備將主要ABI定義爲 armeabi-v7a,而將輔助ABI定義爲 armeabi,因爲它可以運行爲每個 ABI 生成的應用原生二進制文件。
許多基於 x86 的設備也可運行 armeabi-v7a 和 armeabi NDK 二進制文件。對於這些設備,主要 ABI將是 x86,輔助ABI是 armeabi-v7a。
基於 MIPS 的典型設備只定義主要 ABI:mips。
23.6 安裝時自動解壓縮原生代碼
安裝應用時,軟件包管理器服務將掃描 APK,查找以下形式的任何共享庫:
lib/<primary-abi>/lib<name>.so
如果未找到,並且已定義輔助 ABI,該服務將掃描以下形式的共享庫:
lib/<secondary-abi>/lib<name>.so
找到所需的庫時,軟件包管理器會將它們複製到應用的 data 目錄 (data/data/<package_name>/lib/)下的 /lib/lib<name>.so。
如果根本沒有共享對象文件,應用也會構建並安裝,但在運行時會崩潰。