17、Android 11 新特性:虚拟 A/B 分区、构建系统优化、模块化构建

Android 11 这个版本,说实话,在构建系统这块算是憋了个大招。我当年从 Android 10 切到 11 的时候,第一感觉就是「嗯,Google 终于开始认真收拾那些历史遗留问题了」。今天咱们就聊聊三个最核心的变化:虚拟 A/B 分区、构建系统本身的优化,还有模块化构建。

17.1 虚拟 A/B 分区:OTA 体验的质变

先说说虚拟 A/B 分区。这玩意儿说白了,就是 Google 把 A/B 分区机制和动态分区合并了。

传统 A/B 分区大家应该不陌生——系统有两套分区,A 槽和 B 槽。OTA 升级时,后台往空闲槽写数据,写完了重启切换。好处是升级失败还能回滚,坏处是……你得预留整整一套分区的空间。对于 64GB 甚至 32GB 的低端设备,这太奢侈了。

虚拟 A/B 分区的思路很巧妙:它不再保留完整的 B 槽副本,而是只保留一个「增量快照」。升级时,系统把新数据写到动态分区的空闲区域,同时用 COW(Copy-on-Write)机制记录修改。说白了,就是「用多少,占多少」。

核心优势:

  • 节省磁盘空间:相比传统 A/B,可节省 50% 以上的分区预留空间
  • 回滚能力保留:升级失败依然能退回旧版本
  • 后台升级体验:用户几乎无感知

我记得第一次在项目中适配虚拟 A/B 时,踩了个坑——super.img 的大小计算。如果你把 super 分区设得太小,COW 空间不够,升级就会失败。我当时调试了一整天,最后发现是 board-info.txt 里的 super_partition_size 少算了 256MB。嗯,这个细节大家一定要注意。

虚拟 A/B 的构建配置

要在构建系统中启用虚拟 A/B,你需要修改 BoardConfig.mk

# 启用虚拟 A/B
AB_OTA_UPDATER := true
PRODUCT_VIRTUAL_AB_OTA := true

# 动态分区必须开启
PRODUCT_USE_DYNAMIC_PARTITIONS := true

# COW 空间大小,建议至少 256MB
PRODUCT_VIRTUAL_AB_OTA_PARTITION_SIZE := 268435456

这里有个坑:PRODUCT_VIRTUAL_AB_OTA 这个变量在 Android 11 才引入。如果你从老版本移植代码,记得检查所有依赖项。我见过有人直接把 Android 10 的 BoardConfig 拿过来用,结果编译出来的镜像根本没法 OTA。

17.2 构建系统优化:Soong 的进一步成熟

Android 11 对构建系统本身的优化,主要集中在 Soong 和 Make 的混合使用上。说白了,Google 在逐步淘汰 Make,把更多逻辑迁移到 Soong(基于 Blueprint 和 Bazel 的构建系统)。

我个人最直观的感受是:增量构建速度变快了。以前改一个底层库,重新编译可能要等 5 分钟;Android 11 下,同样的改动,Soong 能更精确地分析依赖,只重新编译受影响的部分,时间缩短到 1-2 分钟。

Android.bp 的新特性

Android 11 的 Android.bp 支持了一些新字段,比如 vendor_availableproduct_available。这些字段让模块的可见性控制更精细。

cc_library {
    name: "libmyutils",
    srcs: ["myutils.cpp"],
    vendor_available: true,
    product_available: true,
    // 表示这个库可以被 vendor 和 product 分区使用
}

你想想看,以前我们怎么控制模块可见性?要么用 LOCAL_MODULE_TAGS,要么在 Makefile 里写一堆条件判断。现在一个字段就搞定了,清晰多了。

我的建议:新项目尽量全部用 Android.bp 写构建规则。Makefile 虽然还能用,但 Google 已经明确表示未来会移除。早点迁移,后面少折腾。

17.3 模块化构建:分而治之的艺术

模块化构建,说白了就是把整个系统拆成一个个独立的模块,每个模块可以单独编译、单独测试、单独发布。Android 11 在这方面做了不少工作,尤其是引入了 com.android.apexcom.android.art 这样的 APEX 模块。

APEX 是什么?你可以把它理解成「升级版的 APK」。它不仅能包含 Java 代码,还能包含原生库、配置文件,甚至整个运行时环境。最关键的是,APEX 模块可以独立于系统镜像进行更新。

举个例子:以前要更新 ART 运行时,你得等整个系统 OTA。现在 Google 把 ART 做成了一个 APEX 模块,直接通过 Google Play 商店推送更新就行。用户重启一下,ART 就升级了,系统镜像完全不用动。

如何构建一个 APEX 模块

构建 APEX 模块需要用到 apex 模块类型:

apex {
    name: "com.example.myapex",
    manifest: "apex_manifest.json",
    native_shared_libs: ["libmyengine"],
    java_libs: ["my-java-lib"],
    // 指定 APEX 的密钥
    key: "com.example.myapex.key",
}

对应的 apex_manifest.json 文件:

{
    "name": "com.example.myapex",
    "version": 1
}

编译完成后,你会得到一个 .apex 文件。这个文件本质上是一个 ext4 镜像,里面打包了所有依赖的库和文件。

注意:APEX 模块的签名非常重要。如果密钥丢失,已经部署的 APEX 模块将无法更新。我曾经在项目中遇到过密钥管理混乱的情况,最后不得不重新刷全量镜像。所以,密钥一定要妥善保管,最好纳入公司的密钥管理系统。

17.4 知识体系总览

下面这张图总结了 Android 11 构建系统三大新特性的核心逻辑和相互关系:

Android 11 构建系统三大新特性 虚拟 A/B 分区 • 合并 A/B + 动态分区 • COW 增量快照 • 节省 50%+ 空间 • 保留回滚能力 关键配置: PRODUCT_VIRTUAL_AB_OTA AB_OTA_UPDATER COW 空间 ≥ 256MB 构建系统优化 • Soong 逐步替代 Make • 增量构建速度提升 • 精确依赖分析 • Android.bp 新字段 新字段示例: vendor_available product_available 模块可见性控制 模块化构建 • APEX 模块机制 • 独立编译/测试/发布 • 无需全量 OTA • 包含原生库+配置 构建示例: apex { name: "..." } apex_manifest.json 密钥管理 三者共同目标:更省空间、更快构建、更灵活更新

从这张图可以看出来,这三个特性虽然各自独立,但目标是一致的:让 Android 系统的构建、部署和更新变得更高效、更灵活。虚拟 A/B 分区解决了存储空间的问题,构建系统优化解决了编译效率的问题,模块化构建解决了更新灵活性的问题。

我个人觉得,模块化构建是这三个里面最有长远价值的。你想啊,以后系统组件都能像 App 一样独立更新,那 OTA 的压力就小多了。Google 在 Android 12 和 13 里继续强化了 APEX 机制,把更多核心组件(如 Wi-Fi、蓝牙、媒体框架)都模块化了。这个趋势,做构建的同学一定要跟上。

避坑指南:如果你要在项目中同时启用虚拟 A/B 和 APEX 模块,记得检查分区大小。APEX 模块会占用 /system 分区的空间,而虚拟 A/B 的 COW 空间也需要从 super 分区里划。我见过一个项目,两个特性都开了,结果 super 分区设得太小,编译出来的镜像刷进去就报空间不足。建议 super 分区至少留 512MB 的余量。

好了,Android 11 的这三个新特性就聊到这儿。它们不是孤立的技术点,而是 Google 对 Android 构建体系长期演进的一部分。理解它们背后的设计思路,比死记硬背配置参数重要得多。


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