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 对构建变体的支持更完善了。以前,我们主要用 enguserdebuguser 这三种。现在,你可以自定义更多变体,并且能精确控制每个变体下的编译选项。

核心变化: 现在可以在 Android.bp 中直接通过 target 块,为不同变体指定不同的 cflagsldflags 甚至 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 秒左右。

为什么会这样?因为新版的 ninjasoong 能更智能地分析文件依赖关系。它们不再盲目地重新编译所有依赖项,而是只编译真正受影响的部分。

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 进一步强化了动态分区。现在,systemproductvendor 这些分区的大小,可以在 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_dlkmvendor_dlkm

Android 14 引入了 odm_dlkmvendor_dlkm 分区。这两个分区专门用来存放可加载内核模块(Loadable Kernel Modules)。

以前,内核模块要么放在 vendor 分区,要么直接编译进内核。现在,把它们独立出来,好处是:

  • 解耦: 内核模块的更新,不再需要更新整个 vendor 分区。
  • 安全: 可以更严格地控制哪些模块可以加载,减少攻击面。
  • 灵活性: 不同的硬件变体,可以加载不同的内核模块,而不需要改动系统镜像。

下面这张图,展示了 Android 14 新的分区布局和构建流程之间的关系。

Android 14 构建系统与分区布局 构建系统层 (Soong + Ninja) 模块化配置 | 构建变体增强 | R8全量模式 | PGO集成 编译优化层 增量编译 | 缓存优化 | 编译产物 (镜像文件) 分区布局层 (动态分区 + 虚拟A/B) system product vendor odm_dlkm vendor_dlkm ...

从这张图你可以看到,构建系统产出的镜像文件,最终会被部署到新的分区布局中。而编译优化,则贯穿在整个流程里。

20.4 总结

Android 14 的构建系统,给我的感觉是「更聪明、更灵活、更省空间」。模块化配置让项目管理更清晰,编译优化让开发效率更高,新分区布局则让系统更新和硬件适配更从容。

当然,新东西也意味着新坑。我建议你在升级到 Android 14 时,先在一个小项目上试试水,把上面提到的这些新特性都跑一遍。特别是分区布局的变化,一定要在真机上验证 OTA 流程。嗯,今天就先聊到这吧。

公众号:蓝海资料掘金营,微信 deep3321