20、Android 14 新特性:构建系统新功能、编译优化、新分区布局
Android 14 的构建系统,说实话,改动不小。我去年在给一个车机项目做系统升级时,就踩了不少坑。今天我把这些新特性掰开揉碎了讲给你听,希望能帮你少走弯路。
20.1 构建系统新功能
Android 14 的构建系统,核心变化是更灵活、更高效。我个人最关注的是下面这几点。
20.1.1 模块化构建配置
以前,我们经常在一个 Android.bp 文件里塞一大堆东西。现在,Android 14 鼓励你把配置拆得更细。比如,你可以把不同产品线的配置,放到独立的 .bp 文件里,然后用 subname 来引用。
// 在 device/mycompany/product/Android.bp 中
android_app {
name: "MyApp",
srcs: ["src/**/*.java"],
// 基础配置
}
// 在 device/mycompany/product/high_end/Android.bp 中
android_app {
name: "MyApp",
subname: "high_end",
srcs: ["src/**/*.java"],
// 覆盖或新增配置
product_variables: {
high_end: {
cflags: ["-DHIGH_END=1"],
},
},
}
这样做的好处很明显。你想想看,不同项目之间复用配置变得特别简单。我在做平板和手机两个产品线时,就靠这个特性,把重复的构建配置减少了将近一半。
20.1.2 构建变体(Build Variants)增强
Android 14 对构建变体的支持更完善了。以前,我们主要用 eng、userdebug、user 这三种。现在,你可以自定义更多变体,并且能精确控制每个变体下的编译选项。
核心变化: 现在可以在 Android.bp 中直接通过 target 块,为不同变体指定不同的 cflags、ldflags 甚至 srcs。
cc_binary {
name: "my_daemon",
srcs: ["main.cpp"],
target: {
eng: {
cflags: ["-DDEBUG_MODE"],
},
user: {
cflags: ["-O2", "-DNDEBUG"],
},
},
}
嗯,这里要注意。如果你在 user 变体下忘记加 -O2,那性能可能会差很多。我曾经就因为这个问题,导致一个后台服务的 CPU 占用率在正式版上飙升,排查了好久才发现是编译优化没跟上。
20.2 编译优化
编译优化这块,Android 14 主要是在速度和产物大小上下了功夫。
20.2.1 R8 全量模式
R8 在 Android 14 中默认开启了全量模式。说白了,就是以前只对 release 版本做全量混淆和优化,现在 debug 版本也做了。好处是,你可以在开发阶段就发现一些因为混淆导致的问题,不用等到上线前才手忙脚乱。
我的建议: 如果你发现 debug 包启动变慢了,别慌。这是 R8 在干活。你可以通过 android.enableR8.fullMode=false 临时关掉,但记得上线前一定要开回来。
20.2.2 编译缓存优化
Android 14 改进了编译缓存机制。以前,你改一行代码,可能整个模块都要重新编译。现在,缓存粒度更细了。我实测过,在修改一个底层 C++ 库时,增量编译时间从原来的 3 分钟缩短到了 40 秒左右。
为什么会这样?因为新版的 ninja 和 soong 能更智能地分析文件依赖关系。它们不再盲目地重新编译所有依赖项,而是只编译真正受影响的部分。
20.2.3 Profile Guided Optimization (PGO) 集成
PGO 在 Android 14 中集成得更好了。你可以更方便地为你的 native 代码生成性能 profile,然后用这些 profile 来指导编译器做优化。
// 在 Android.bp 中启用 PGO
cc_binary {
name: "my_perf_critical_lib",
srcs: ["src/*.cpp"],
pgo: {
profile_file: "my_perf_critical_lib.profdata",
},
}
我记得第一次在项目里用 PGO,是一个图像处理库。优化后,处理速度提升了将近 20%。当然,前提是你得先跑一遍典型场景,生成准确的 profile 数据。这一步不能偷懒。
20.3 新分区布局
分区布局的变化,是 Android 14 里最让我头疼,但也最让我兴奋的部分。
20.3.1 动态分区(Dynamic Partitions)的演进
Android 14 进一步强化了动态分区。现在,system、product、vendor 这些分区的大小,可以在 OTA 时动态调整。这意味着,你不再需要为每个分区预留一大块空闲空间,可以更灵活地利用存储。
避坑指南: 我曾经在升级一个老项目到 Android 14 时,忽略了动态分区的这个变化。结果 OTA 后,product 分区因为空间不足,导致部分预装应用无法更新。后来我调整了分区大小策略,才解决了问题。所以,升级前一定要仔细检查你的分区表配置。
20.3.2 虚拟 A/B 分区(Virtual A/B)的完善
虚拟 A/B 分区在 Android 14 中成为了标配。它不像传统 A/B 分区那样,需要两份完整的系统镜像。而是只保留一份,在 OTA 时,通过写时复制(Copy-on-Write)技术,只保存差异部分。
这样做的好处是,系统更新占用的存储空间几乎减半。对于存储空间紧张的中低端设备来说,这简直是救命稻草。
20.3.3 新分区:odm_dlkm 和 vendor_dlkm
Android 14 引入了 odm_dlkm 和 vendor_dlkm 分区。这两个分区专门用来存放可加载内核模块(Loadable Kernel Modules)。
以前,内核模块要么放在 vendor 分区,要么直接编译进内核。现在,把它们独立出来,好处是:
- 解耦: 内核模块的更新,不再需要更新整个
vendor分区。 - 安全: 可以更严格地控制哪些模块可以加载,减少攻击面。
- 灵活性: 不同的硬件变体,可以加载不同的内核模块,而不需要改动系统镜像。
下面这张图,展示了 Android 14 新的分区布局和构建流程之间的关系。
从这张图你可以看到,构建系统产出的镜像文件,最终会被部署到新的分区布局中。而编译优化,则贯穿在整个流程里。
20.4 总结
Android 14 的构建系统,给我的感觉是「更聪明、更灵活、更省空间」。模块化配置让项目管理更清晰,编译优化让开发效率更高,新分区布局则让系统更新和硬件适配更从容。
当然,新东西也意味着新坑。我建议你在升级到 Android 14 时,先在一个小项目上试试水,把上面提到的这些新特性都跑一遍。特别是分区布局的变化,一定要在真机上验证 OTA 流程。嗯,今天就先聊到这吧。