Google 开始正式强制 Android 适配 16 K Page Size,你准备好了吗?

去年中旬我就分享过几篇关于 Android 适配 16K Page Size 的文章,当时就提及了 2025 Google 将会强制要求,而现在 Google 给出了明确时间:自 2025 年 11 月 1 日起,所有提交到 Google Play 且面向 Android 15+ 设备的新应用和现有应用的更新都必须支持 16 KB 的页面大小

❕❕❕注意,如何适配和查看调试的文章放在了最后面

对于兼容,最简单的判断就是你是否使用了动态链接库 so ,如果用了陈年老库,那么你大概率是必须去做适配支持,同步的还有 Flutter 和 React Native 版本,升级到对应支持 16K 的版本是必须的:

如果你的应用已经上架了 Google Play ,可以通过访问 Play 管理中心内的 app bundle 资源管理器页面查看:

image-20250509145711207

那什么是 Page Size ?一般意义上,页面(Page)指的就是 Linux 虚拟内存管理中使用的最小数据单位,页面大小(Page Size)就是虚拟地址空间中的页面大小, Linux 中进程的虚拟地址空间是由固定大小的页面组成:

因为 Android 用的是 Linux 内核,所以在这部分逻辑一直以来都是遵循 Linux 的实现,只是 Android 由于「历史因素」限制,一直只支持 4 KB 内存页面大小,现在想要支持 16K 了而已:

而简单说,16k 是 4k 的整数倍,所以 16K 的 so 也可以跑在 4k 上,但是 4k 因为不是 16k 的整数倍,所以 4k 跑不了 16k 的系统。

另外,目前来说 Android 继承了 Linux 的特点,不支持混合 Page Size,也就是在 16k 设备上,你的 4k so 就是跑不了,当然,不是系统层面就一定做不了,比如 :

关于这一点,其实 Apple Silicon 的 MacOS 其实是有混合 16K/4K 支持,事实上 macOS 本身始终以 16K 页面运行,只有 Rosetta 模式下应用会以 4K 模式运行。

从目前官方的信息看,Android 16 添加了兼容模式 ,让一些针对 4 KB 内存页面构建的应用可以在配置为 16 KB 内存页面的设备上运行:
在这里插入图片描述

在 AndroidManifest.xml 中设置 android:pageSizeCompat 属性以启用向后兼容模式,将会阻止应用启动时显示对话框,如果需要使用 android:pageSizeCompat 属性,需使用 Android 16 SDK 编译应用

另外,关于查看 so 是否适配 16K,还可以通过 readelf 工具,对比编译前后两个 so 的 elf 对齐情况,工具一般位于 /Users/guoshuyu/Library/Android/sdk/ndk/21.4.7075529/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin,通过以下命令可以输出对应参数:

./aarch64-linux-android-readelf -l /Users/guoshuyu/workspace/android/******/libs/arm64-v8a/libijkffmpeg.so

如下两种图所示:

  • 图 1 LOAD 段在 Align 栏目显示 1000 (16进制,即 4096) ,也就是还没增加 16K 对齐的状态
  • 图 2 LOAD 段在 Align 栏目显示 4000 (16进制,即 16384) ,是增加 16K 对齐的状态

如果是 10000 ,也就是 65536 ,那就是64K 对齐,属于 16K 的 4倍,那「理论上」应该是对齐的

还有更简单的办法,就是直接下载一个 libchecker,就可以看到你的 app 里的 so 是否是 16k page size 分页

在这里插入图片描述

但是, so 分页是 16k ,不代表了它就一定能在 16k 设备上正常,这是血和泪的教训

所以,除了 app bundle 资源管理器和查看分页信息之后,最重要是确保在 16 KB 的环境中测试你的应用 ,在之前的文章我就分享过,很多 so 查看时虽然分页是 16K 或者 64K ,但是它还是有问题的,跑在 16K 上是会崩溃的,具体原因有 NDK 工具可能过老,以 IJK 为例:

IJK 的 NDK10e 等版本,编译出来的 so 都是两个 LOAD 段的 Align 是 10000(65536) , 也就是 64K 对齐,属于 16K 的 4倍,那「理论上」应该是对齐的,但是跑在 16K 上会 crash ,不过 crash 提示也不是 so 不对齐,而是在某段代码执行时出现 crash,并且你定位到的地址代码会很奇葩。

具体解决办法也有,就是强制除了 max-page-size 之外,再配置上 common-page-size 也可以支持:

LOCAL_LDFLAGS += -Wl,-z,max-page-size=65536
LOCAL_LDFLAGS += -Wl,-z,common-page-size=65536

如果是需要 cmake 支持的,则可以:

target_link_libraries(a4ijkplayer  "-Wl,-z,max-page-size=65536")
target_link_libraries(a4ijkplayer  "-Wl,-z,common-page-size=65536")。

当然,还可以升级到 NDK r22 解决,例如 NDK r21 就只需要 max-page-size=16384 ,从分页上更合理,至于为什么 NDK r22 可以,这就涉及 llvm 和 GUN 的版本和兼容问题 ,详细可见末尾的填坑思路。

目前 GSYVideoPlayer 的 IJK 内核已经在去年提供了 16K 的支持,具体的 git patch 和支持方式也提交在 Github ,需要的可以参考:https://github.com/CarGuo/GSYVideoPlayer/tree/master/16kpatch

最后,如果你还没适配或者了解 16K,可以参考一下文章

参考链接

  • https://android-developers.googleblog.com/2025/05/prepare-play-apps-for-devices-with-16kb-page-size.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值