从历史上看,Android 只支持 4 KB 内存页面大小,这优化了系统内存性能,使其适用于 Android 设备通常具有的平均总内存量。从 Android 15 开始,AOSP 支持配置为使用 16 KB 页面大小的设备(16 KB 设备)。如果您的应用直接或间接地通过 SDK 使用任何 NDK 库,则需要重新构建您的应用才能使其在这些 16 KB 设备上运行。
随着设备制造商继续制造具有更大物理内存(RAM)的设备,其中许多设备将采用 16 KB(并最终更大)的页面大小以优化设备的性能。添加对 16 KB 页面大小设备的支持使您的应用能够在这些设备上运行,并帮助您的应用从相关的性能改进中受益。如果不重新编译,当应用在未来的 Android 版本中投入生产时,应用可能无法在 16 KB 设备上运行。
为了帮助您添加对应用的支持,我们提供了有关如何 检查您的应用是否受到影响、如何 重新构建您的应用(如果适用)以及如何 在 16 KB 环境中测试您的应用(包括 Android 模拟器 Android 15 系统映像)的指南。
优势和性能提升
配置了 16 KB 页面大小的设备平均使用略多的内存,但也为系统和应用带来了各种性能改进
- 在系统内存压力下降低应用启动时间:平均降低 3.16%,我们测试的一些应用的改进幅度更大(高达 30%)
- 减少应用启动期间的功耗:平均减少 4.56%
- 更快的相机启动:平均热启动速度提高 4.48%,冷启动速度提高 6.60%
- 改进的系统启动时间:平均提高 8%(大约 950 毫秒)
这些改进基于我们的初步测试,实际设备上的结果可能会有所不同。随着我们继续测试,我们将提供对应用潜在收益的更多分析。
检查您的应用是否受到影响
如果您的应用 使用任何原生代码,则应 使用对 16 KB 设备的支持重新构建您的应用。如果您不确定您的应用是否使用原生代码,您可以 使用 APK 分析器来识别是否存在任何原生代码,然后 检查您找到的任何共享库的 ELF 段的对齐方式。
如果您的应用仅使用用 Java 编程语言或 Kotlin 编写的代码,包括所有库或 SDK,则您的应用已支持 16 KB 设备。但是,我们建议您 在 16 KB 环境中测试您的应用,以验证应用行为中是否存在任何意外的回归。
您的应用是否使用原生代码?
如果以下任何一项适用,则您的应用使用原生代码
- 您的应用使用任何 C/C++(原生)代码。如果您的应用使用 Android NDK,则您的应用使用原生代码。
- 您的应用链接到任何使用原生库或依赖项(如 SDK)的第三方原生库。
- 您的应用由使用设备上原生库的第三方应用构建器构建。
使用 APK 分析器识别原生库
APK 分析器 是一种工具,可让您评估已构建 APK 的各个方面。要识别您的应用是否使用原生代码或库,请执行以下步骤
- 打开Android Studio,然后点击文件 > 打开并选择任何项目。
从菜单栏中,点击构建 > 分析 APK...
选择您要分析的 APK。
查看
lib
文件夹内,如果存在任何共享对象 (.so
) 文件,则该文件夹会托管这些文件。如果存在任何共享对象文件,则您的应用使用原生代码。如果不存在任何共享对象文件或不存在lib
文件夹,则您的应用不使用原生代码。
检查共享库的 ELF 段的对齐方式
对于任何共享库,请使用 16 KB ELF 对齐方式验证共享库的 ELF 段是否已正确对齐。如果您在 Linux 或 macOS 上开发,则可以使用以下部分中描述的 check_elf_alignment.sh
脚本。您也可以 直接使用命令行工具。
使用 check_elf_alignment.sh 脚本(Linux 或 macOS)
请按照以下步骤使用 check_elf_alignment.sh
脚本检查 ELF 段的对齐方式
将
check_elf_alignment.sh
脚本保存到文件中。在您的应用 APK 文件上运行该脚本
check_elf_alignment.sh APK_NAME.apk
该脚本为所有
arm64-v8a
共享库输出ALIGNED
或UNALIGNED
。如果任何
arm64-v8a
或x86_64
共享库是UNALIGNED
,则需要 更新这些库的打包方式,然后 重新编译您的应用 并按照本节中的步骤重新测试。
直接使用命令行工具
按照以下步骤使用命令行工具直接检查 ELF 段的对齐方式
- 确保已安装 Android SDK Build-Tools 35.0.0 或更高版本以及 Android NDK,可以使用 Android Studio 中的 SDK 管理器 或
sdkmanager
命令行工具。 解压应用的 APK 文件
Linux 或 macOS
unzip APK_NAME.apk -d /tmp/my_apk_out
Windows(PowerShell)
Expand-Archive -Path .\APK_NAME.apk -DestinationPath ~\tmp\my_apk_out
在解压 APK 文件的临时目录中,检查
lib
目录中是否存在共享对象(.so
)文件。这些与您在 使用 APK 分析器识别原生库 时看到的共享对象文件相同。在每个共享对象文件上运行以下命令Linux 或 macOS
SDK_ROOT_LOCATION/Android/sdk/ndk/NDK_VERSION/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-objdump -p SHARED_OBJECT_FILE.so | grep LOAD
Windows(PowerShell)
SDK_ROOT_LOCATION\Android\sdk\ndk\NDK_VERSION\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-objdump.exe -p SHARED_OBJECT_FILE.so | Select-String -Pattern "LOAD"
其中
SDK_ROOT_LOCATION
是已安装 Android SDK 的目录的路径,SHARED_OBJECT_FILE
是要检查的共享对象文件的名称,NDK_VERSION
是已安装的 Android NDK 的版本(例如,28.0.12433566
)。对于您检查的每个文件,输出将类似于以下内容LOAD off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**14 LOAD off 0x0000000000042a90 vaddr 0x0000000000043a90 paddr 0x0000000000043a90 align 2**14 LOAD off 0x0000000000046230 vaddr 0x0000000000048230 paddr 0x0000000000048230 align 2**14
检查输出行,确保加载段的值不小于
2**14
。如果任何加载段为2**13
、2**12
或更低的值,则需要 更新这些库的打包方式,然后 重新编译您的应用 并按照本节中的步骤重新测试。接下来,在应用的 APK 文件上运行
zipalign
命令行工具Linux 或 macOS
SDK_ROOT_LOCATION/Android/sdk/build-tools/35.0.0/zipalign -v -c -P 16 4 APK_NAME.apk
Windows(PowerShell)
SDK_ROOT_LOCATION\Android\sdk\build-tools\35.0.0\zipalign.exe -v -c -P 16 4 APK_NAME.apk
其中
SDK_ROOT_LOCATION
是已安装 Android SDK 的目录的路径,APK_NAME
是应用的 APK 文件的名称。如果所有共享库都正确对齐,则输出的最后一行将显示“Verification successful”。如果验证失败,则某些共享库需要重新对齐,因此需要 更新这些库的打包方式,然后 重新编译您的应用 并按照本节中的步骤重新测试。
构建支持 16 KB 设备的应用
为了支持 16 KB 设备,使用原生代码的应用应完成以下各节中概述的步骤。如果您更新到 AGP 8.5.1 或更高版本和 NDK r28 或更高版本,并使用与 16 KB 兼容的预构建依赖项,则应用默认情况下与 16 KB 兼容。
更新共享库的打包方式
建议您升级到 AGP 8.5.1 或更高版本,并使用未压缩的共享库。
AGP 8.5.1 或更高版本
16 KB 设备要求附带未压缩共享库的应用将其对齐到 16 KB zip 对齐边界。为此,您需要升级到 Android Gradle 插件 (AGP) 8.5.1 或更高版本。有关升级过程的详细信息,请参阅 Android Gradle 插件升级助手 部分。
AGP 8.5 或更低版本
如果无法将 AGP 升级到 8.5.1 或更高版本,则可以使用压缩共享库作为替代方案。更新您的 Gradle 配置,使 Gradle 在打包应用时压缩共享库,以避免未对齐的共享库导致应用安装问题。
Groovy
在 build.gradle
文件中,添加以下选项
android {
...
packagingOptions {
jniLibs {
useLegacyPackaging true
}
}
}
Kotlin
在 build.gradle.kts
文件中,添加以下选项
android {
...
packagingOptions {
jniLibs {
useLegacyPackaging = true
}
}
}
使用 16 KB ELF 对齐方式编译应用
16 KB 设备要求共享库的 ELF 段使用 16 KB ELF 对齐方式正确对齐,以便您的应用能够运行。
要使用 16 KB ELF 对齐方式编译应用,请根据您使用的 Android NDK 版本完成以下部分之一中的步骤。
Android NDK r28 及更高版本
NDK r28 及更高版本默认情况下会编译 16 KB 对齐的库。
Android NDK r27
要支持使用 Android NDK r27 或更高版本编译 16 KB 对齐的共享库,您需要更新 ndk-build
、build.gradle
、build.gradle.kts
或链接器标志,如下所示
ndk-build
在 Application.mk
中
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true
Groovy
在 build.gradle
文件中,设置参数 -DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON
android {
...
defaultConfig {
...
// This block is different from the one you use to link Gradle
// to your CMake or ndk-build script.
externalNativeBuild {
// For ndk-build, instead use the ndkBuild block.
cmake {
// Passes optional arguments to CMake.
arguments "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
}
}
}
}
Kotlin
在 build.gradle.kts
文件中,设置参数 -DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON
android {
...
defaultConfig {
...
// This block is different from the one you use to link Gradle
// to your CMake or ndk-build script.
externalNativeBuild {
// For ndk-build, instead use the ndkBuild block.
cmake {
// Passes optional arguments to CMake.
arguments += listOf("-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON")
}
}
}
}
其他构建系统
指定以下链接器标志
-Wl,-z,max-page-size=16384
Android NDK r26 及更低版本
要支持使用 Android NDK r26 或更低版本编译 16 KB 对齐的共享库,您需要更新 ndk-build
或 cmake
配置,如下所示
ndk-build
更新 Android.mk
以启用 16 KB ELF 对齐方式
LOCAL_LDFLAGS += "-Wl,-z,max-page-size=16384"
CMake
更新 CMakeLists.txt
以启用 16 KB ELF 对齐方式
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE "-Wl,-z,max-page-size=16384")
检查引用特定页面大小的代码实例
即使您的应用已对齐到 16 KB,如果代码中的某些位置假定设备使用特定页面大小,您的应用也可能会遇到错误。要避免这种情况,请完成以下步骤
删除任何引用
PAGE_SIZE
常量或代码逻辑中假定设备页面大小为 4 KB(4096
)的实例的硬编码依赖项。查找
mmap()
和其他需要页面对齐参数的 API 的用法,并在必要时替换为替代方案。
在某些情况下,如果您的应用将 PAGE_SIZE
用作与底层页面大小无关的便捷值,则在 16 KB 模式下使用时,这不会导致应用崩溃。但是,如果此值与 mmap
一起传递给内核且未使用 MAP_FIXED
,则内核仍会使用整个页面,从而浪费一些内存。出于这些原因,在 NDK r27 及更高版本上启用 16 KB 模式时,PAGE_SIZE
未定义。
如果您的应用以这种方式使用 PAGE_SIZE
且从未直接将此值传递给内核,则不要使用 PAGE_SIZE
,而是创建一个具有新名称的新变量以反映它是用于其他目的,并且不反映实际的内存页面。
检查 SDK 是否支持 16 KB
许多 SDK 与 16 KB 页面大小兼容,尤其是如果您自己构建它们或获取最新的预构建版本时。但是,由于某些 SDK 预构建版本或 SDK 版本与 16 KB 不兼容,因此您应查看每个 SDK 提供商的网站,以确定要与 16 KB 一起使用的版本。
在 16 KB 环境中测试您的应用
在构建支持 16 KB 设备的应用后,您需要在 16 KB 环境中测试应用,以查看应用是否遇到任何回归。为此,请按照以下步骤操作
设置以下测试环境之一
启动测试设备,然后运行以下命令以验证它是否使用 16 KB 环境
adb shell getconf PAGE_SIZE
该命令应返回
16384
的值。运行以下
zipalign
命令以验证您的应用是否已对齐到 16 KB,其中 APK_NAME 是应用的 APK 文件的名称zipalign -c -P 16 -v 4 APK_NAME.apk
彻底测试您的应用,重点关注可能受更改引用特定页面大小的代码实例影响的任何区域。
使用基于 16 KB 的 Android 15 系统映像设置 Android 模拟器
要使用 Android 模拟器设置 16 KB 环境,请按照以下步骤操作
基于 16 KB 的 Android 15 模拟器系统映像与 Android Studio Jellyfish | 2023.3.1 或更高版本兼容。但是,为了在使用 Android 15 Beta 时获得最佳体验,请下载 Android Studio 的最新预览版本。
请记住,您可以保留您现有的 Android Studio 版本,因为您可以并排安装多个版本。
在 Android Studio 中,点击工具 > SDK 管理器。
在SDK 平台选项卡中,选中显示包详细信息,然后展开Android VanillaIceCream 预览部分,并根据您要创建的虚拟设备选择以下一个或两个模拟器系统映像
- Google APIs Experimental 16k 页面大小 ARM 64 v8a 系统映像
- Google APIs Experimental 16k 页面大小 Intel x86_64 Atom 系统映像
点击应用 > 确定以下载您选择的任何系统映像。
按照步骤为 Android 15 设置虚拟设备,并在提示您选择系统映像时,选择您下载的 16 KB 系统映像。如果未自动推荐,您可以在其他映像选项卡中找到 16 KB 系统映像。
- 在设备管理器中,点击 16 KB 映像旁边的三个点,然后点击在磁盘上显示。
- 在此文件夹中,找到
config.ini
文件。 将以下行添加到
config.ini
文件中并保存更改kernel.parameters = androidboot.page_shift=14
要验证您的更改,请运行以下命令,该命令应返回
16384
adb shell getconf PAGE_SIZE
使用开发者选项在设备上启用 16 KB 模式
从 Android 15 QPR1 开始,您可以使用某些设备上提供的开发者选项以 16 KB 模式引导设备并执行设备上测试。
此开发者选项适用于以下设备
- Pixel 8 和 8 Pro(Android 15 QPR1 Beta 1 或更高版本)
- Pixel 8a(Android 15 QPR1 Beta 2 或更高版本)