16、Android 10 新特性:Soong 配置、产品配置变化、系统分区动态化

Android 10 这个版本,说实话,对构建系统来说是个分水岭。我当年从 Android 9 升级到 10 的时候,第一感觉就是「嗯,Makefile 那套东西真的要退休了」。Google 在 Android 7 引入了 Soong,但到了 10 才真正把 Soong 推到前台,让它成为构建系统的绝对主角。

今天咱们就聊聊三个核心变化:Soong 配置怎么玩、产品配置有哪些坑、以及那个听起来很唬人的「系统分区动态化」到底是个啥。

16.1 Soong 配置:从 Android.mk 到 Android.bp

如果你之前写过 Android.mk,那你应该知道那玩意儿有多啰嗦。LOCAL_ 开头的一大堆变量,稍不注意就拼错。Soong 的 Android.bp 文件,说白了就是用 JSON 风格的语法来定义模块。

举个例子,一个简单的 native 库,在 Android.mk 里是这样:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libhello
LOCAL_SRC_FILES := hello.cpp
LOCAL_SHARED_LIBRARIES := liblog
include $(BUILD_SHARED_LIBRARY)

换成 Android.bp 呢?简洁多了:

cc_library_shared {
    name: "libhello",
    srcs: ["hello.cpp"],
    shared_libs: ["liblog"],
}

我个人习惯是,新项目一律用 .bp,老项目能迁移就迁移。为什么?因为 Soong 的依赖解析比 Make 快得多,而且错误提示更友好。我在项目中遇到过好几次,Android.mk 里漏了个依赖,编译半天才报错,换成 .bp 后,编译前就能检测出来。

小技巧: 如果你不确定某个模块怎么写,可以看看系统自带的 .bp 文件。比如 external/ 目录下有很多开源库的 .bp 示例,直接抄作业就行。

16.2 产品配置变化:BoardConfig 和 ProductConfig 分家

Android 10 之前,产品配置都堆在 BoardConfig.mk 里。你想想看,一个文件里既要管硬件相关的配置(比如 kernel、分区大小),又要管产品相关的配置(比如预装应用、系统属性),多乱啊。

Android 10 把这个拆成了两块:

  • BoardConfig.mk:只放硬件相关的东西。比如 TARGET_BOARD_PLATFORM、BOARD_SYSTEMIMAGE_PARTITION_SIZE 这些。
  • ProductConfig.mk(或者 .bp):放产品相关的。比如 PRODUCT_PACKAGES、PRODUCT_PROPERTY_OVERRIDES。

为什么要这么分?说白了,就是为了让硬件平台和产品定制解耦。同一个硬件平台,可以出多个产品变体,不用重复写 BoardConfig。

举个例子,我做过一个项目,同一块高通芯片,要出国内版和海外版。以前我得复制整个 BoardConfig.mk,然后改几个变量。现在呢?BoardConfig 共享一份,ProductConfig 各写各的,清爽多了。

注意: 虽然 Google 推荐用 ProductConfig.mk,但很多厂商还在用旧方式。如果你看到某个项目的 BoardConfig.mk 里混着 PRODUCT_ 开头的变量,别奇怪,那是历史遗留问题。

16.3 系统分区动态化:dynamic partitions

这个特性,嗯,我得说它改变了 Android 分区的玩法。以前系统分区是固定的,比如 system 分区 2GB,vendor 分区 1GB,product 分区 500MB。你想想看,如果 system 分区不够用了,vendor 那边还有空闲,但你就是用不了——因为分区大小是编译时定死的。

动态分区就是解决这个问题的。它把 system、vendor、product 这些分区合并成一个 super 分区。这个 super 分区有多大,由你定。里面的子分区可以动态调整大小。

我画个图帮你理解:

Android 10 动态分区 vs 传统分区 传统分区(固定大小) system 分区(2GB) vendor 分区(1GB) product 分区(500MB) → 空间浪费,无法灵活调整 动态分区(super 分区) super 分区(4GB) system(动态分配,如 2.5GB) vendor(动态分配,如 1GB) product(动态分配,如 500MB) → 空间按需分配,灵活高效 动态分区 = 一个 super 分区,内部子分区大小可在线调整 需要内核支持(Linux 4.9+)和 A/B 分区配合使用

动态分区的好处很明显:

  • 空间利用率高:哪个分区需要更多空间,就给哪个。不用再纠结「system 分区设多大合适」这种问题了。
  • OTA 升级更安全:配合 A/B 分区,升级失败可以回滚。动态分区在 OTA 时能自动调整大小,不用重新烧录整个分区表。
  • 产品定制更灵活:不同产品可以有不同的分区大小组合,不用改 BoardConfig。
核心配置: 启用动态分区需要在 BoardConfig.mk 里设置:
BOARD_SUPER_PARTITION_SIZE := 4294967296  # 4GB
BOARD_SUPER_PARTITION_GROUPS := group1
BOARD_SUPER_PARTITION_GROUP_group1_SIZE := 4294967296
BOARD_SUPER_PARTITION_GROUP_group1_PARTITION_LIST := system vendor product

我曾经踩过一个坑:动态分区的大小必须和实际镜像大小匹配。有次我改了 system 分区内容,但忘了更新 BOARD_SUPER_PARTITION_SIZE,结果编译出来的 super 镜像烧不进去。嗯,从那以后我养成了习惯,每次改分区内容都检查一下这个值。

16.4 总结一下

Android 10 这三个变化,其实都指向同一个方向:让构建系统更灵活、更高效。Soong 配置让模块定义更简洁,产品配置分家让硬件和产品解耦,动态分区让存储空间利用更合理。

如果你还在用 Android 9 或更早的版本,我建议你尽快升级。虽然迁移过程有点痛苦,但长期来看,这些新特性真的能省不少事。

避坑指南: 我曾经在迁移到动态分区时,忘记在 kernel 配置里打开 CONFIG_LPAM_DYNAMIC_PARTITIONS,结果系统启动时找不到 super 分区。记得检查内核配置!

好了,这一章就聊到这儿。动态分区这块内容比较多,如果你在实际项目中遇到问题,欢迎交流。


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