从历史上看,Android 只支持 4 KB 内存页面大小,这优化了系统内存性能,因为 Android 设备通常具有的总内存量。从 Android 15 开始,AOSP 支持配置为使用 16 KB 页面大小的设备(16 KB 设备)。如果您的应用直接或间接通过 SDK 使用任何 NDK 库,则需要重新构建您的应用才能在这些 16 KB 设备上运行。
随着设备制造商继续制造具有更大物理内存(RAM)的设备,许多这些设备将采用 16 KB(并最终更大)的页面大小来优化设备的性能。添加对 16 KB 页面大小设备的支持使您的应用能够在这些设备上运行,并帮助您的应用受益于相关的性能改进。如果不重新编译,应用在未来的 Android 版本中投入生产时可能无法在 16 KB 设备上运行。
为了帮助您添加对应用的支持,我们提供了有关如何检查您的应用是否受影响、如何重建您的应用(如果适用)以及如何使用模拟器(包括 Android Emulator 的 Android 15 系统镜像)在 16 KB 环境中测试您的应用的指南。
优势和性能提升
配置为 16 KB 页面大小的设备平均使用略多内存,但也为系统和应用带来了各种性能改进。
- 在系统内存压力下降低应用启动时间:平均降低 3.16%,我们测试的一些应用的改进幅度更大(高达 30%)。
- 减少应用启动期间的功耗:平均减少 4.56%。
- 更快的相机启动:热启动平均加快 4.48%,冷启动平均加快 6.60%。
- 改进系统启动时间:平均提高 1.5%(大约 0.8 秒)。
这些改进基于我们的初步测试,实际设备上的结果可能会有所不同。随着我们继续测试,我们将提供对应用潜在收益的更多分析。
检查您的应用是否受影响
如果您的应用使用任何原生代码,则您应该使用支持 16 KB 设备的功能重建您的应用。如果您不确定您的应用是否使用原生代码,您可以使用 APK Analyzer 来识别是否存在任何原生代码。
如果您的应用仅使用 Java 编程语言或 Kotlin 编写的代码,包括所有库或 SDK,则您的应用已支持 16 KB 设备。但是,我们建议您在 16 KB 环境中测试您的应用,以验证应用行为中是否存在任何意外的回归。
您的应用是否使用原生代码?
如果以下任何一项适用,则您的应用使用原生代码。
- 您的应用使用任何 C/C++(原生)代码。如果您的应用使用Android NDK,则您的应用使用原生代码。
- 您的应用链接到任何使用它们的第三方原生库或依赖项。
- 您的应用由使用设备上原生库的第三方应用构建器构建。
使用 APK Analyzer 识别原生库
APK Analyzer 是一种工具,可让您评估构建的 APK 的各个方面。要识别您的应用是否使用原生代码或库,请按照以下步骤操作。
- 打开Android Studio,然后点击文件 > 打开并选择任何项目。
从菜单栏中,点击构建 > 分析 APK...
选择您要分析的 APK。
查看
lib
文件夹内,如果存在任何共享对象(.so
)文件,则该文件夹会托管这些文件。如果存在任何共享对象文件,则您的应用使用原生代码。如果不存在任何共享对象文件或没有lib
文件夹,则您的应用不使用原生代码。
使用支持 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 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")
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
检查引用特定页面大小的代码实例
即使您的应用已进行 16 KB 对齐,如果代码中的某些位置假定设备正在使用特定页面大小,您的应用也可能会遇到错误。为避免这种情况,请完成以下步骤。
在某些情况下,如果您的应用使用PAGE_SIZE
作为与底层页面大小无关的便捷值,则这不会导致您的应用在 16 KB 模式下使用时中断。但是,如果此值通过mmap
传递给内核而没有MAP_FIXED
,内核仍然会使用整个页面,从而浪费一些内存。出于这些原因,在 NDK r27 及更高版本上启用 16 KB 模式时,PAGE_SIZE
未定义。
如果您的应用以这种方式使用PAGE_SIZE
并且从未直接将此值传递给内核,则不要使用PAGE_SIZE
,而是创建一个具有新名称的新变量以反映它用于其他目的并且不反映真实的内存页面。
在 16 KB 环境中测试您的应用
使用支持 16 KB 设备的功能构建您的应用后,您需要在 16 KB 环境中测试您的应用,以查看您的应用是否遇到任何回归。为此,请按照以下步骤操作。
设置以下测试环境之一。
启动您的测试设备,然后运行以下命令以验证它是否正在使用 16 KB 环境。
adb shell getconf PAGE_SIZE
该命令应返回
16384
的值。对于任何共享库,请验证共享库的 ELF 段是否使用 16 KB ELF 对齐正确对齐。您可以使用此脚本帮助完成此过程。
#!/bin/bash # usage: alignment.sh path to search for *.so files dir="$1" RED="\e[31m" GREEN="\e[32m" ENDCOLOR="\e[0m" matches="$(find $dir -name "*.so" -type f)" IFS=$'\n' for match in $matches; do res="$(objdump -p ${match} | grep LOAD | awk '{ print $NF }' | head -1)" if [[ $res =~ "2**14" ]] || [[ $res =~ "2**16" ]]; then echo -e "${match}: ${GREEN}ALIGNED${ENDCOLOR} ($res)" else echo -e "${match}: ${RED}UNALIGNED${ENDCOLOR} ($res)" fi done
将脚本保存到一个文件,例如
alignment.sh
。提取应用的 APK 文件。
unzip APK_NAME.apk -d /tmp/my_apk_out
在
/tmp/my_apk_out
目录中提取的文件上运行脚本。alignment.sh /tmp/my_apk_out | grep "arm64-v8a"
该脚本会为所有
arm64-v8a
共享库输出ALIGNED
或UNALIGNED
。如果任何
arm64-v8a
共享库为UNALIGNED
,则您需要更新这些库的打包方式,然后重新编译您的应用并按照本节中的步骤重新测试。
运行以下
zipalign
命令以验证您的应用是否已进行 16 KB 对齐,其中APK_NAME是应用的 APK 文件的名称。zipalign -c -P 16 -v 4 APK_NAME.apk
彻底测试您的应用,重点关注可能受更改引用特定页面大小的代码实例影响的任何区域。
使用基于 16 KB 的 Android 15 系统镜像设置 Android Emulator。
要使用 Android Emulator 设置 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 实验版 16k 页面大小 ARM 64 v8a 系统镜像
- Google APIs 实验版 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