第3章:分区布局与镜像详解

好,咱们今天聊聊分区布局。说实话,这是OTA升级里最基础也最容易踩坑的地方。我记得刚接触AOSP那会儿,看着一堆分区名就头大——boot、system、vendor、super……每个都长得差不多,但作用天差地别。

你想想看,如果连分区都搞不清楚,后面做差分升级、AB切换肯定要翻车。所以这一章,我带你把这些分区和镜像彻底吃透。

3.1 Boot分区:系统的启动引擎

Boot分区,说白了就是手机开机时第一个加载的东西。它里面装着Linux内核和ramdisk。没有它,系统根本跑不起来。

Boot镜像的结构

+------------------+
|   Boot Header    |  // 头部信息,包含内核大小、ramdisk地址等
+------------------+
|   Kernel         |  // zImage或Image.gz
+------------------+
|   Ramdisk        |  // 根文件系统,包含init.rc等
+------------------+
|   Second Stage   |  // 可选,某些平台用
+------------------+
|   DT (Device Tree)| // 设备树,描述硬件信息
+------------------+

我在项目中遇到过一个问题:某款设备刷了第三方ROM后死活开不了机。查了半天,发现是boot分区里的设备树和硬件不匹配。嗯,这种坑你遇到了就知道有多头疼。

关键点:Boot分区的大小通常由厂商定义,一般在32MB到64MB之间。如果你自己编译内核,记得别超了。

3.2 System分区:系统的核心

System分区装着Android框架、系统应用、库文件等。说白了,它就是Android系统的本体。

不过从Android 10开始,Google强推了动态分区(Dynamic Partition),System分区被合并到了Super分区里。但老设备上,它还是独立存在的。

System镜像的生成

# 编译后生成system.img
make systemimage

# 或者直接生成稀疏格式
make systemimage-sparse

我个人习惯在编译前先检查一下分区大小:

# 查看当前system分区大小
du -sh out/target/product/你的设备/system

# 如果超了,调整BoardConfig.mk中的BOARD_SYSTEMIMAGE_PARTITION_SIZE

注意:System分区不能随便改大。它的大小在分区表里是固定的,改大了会挤占其他分区的空间。我曾经因为没注意这个,导致刷机后vendor分区装不下,折腾了两天。

3.3 Vendor分区:硬件适配的关键

Vendor分区,这是厂商最关心的分区。它装着硬件相关的驱动、HAL(硬件抽象层)、固件等。

为什么要单独分一个Vendor分区?说白了就是为了解耦。系统升级时,vendor分区可以不动,只更新system分区。这样厂商不用每次升级都重新适配驱动。

Vendor镜像的内容

  • lib64/hw/ 下的硬件HAL库(比如gralloc、hwcomposer)
  • etc/ 下的配置文件(比如audio_policy.conf)
  • firmware/ 下的固件文件
  • bin/ 下的硬件相关可执行文件

我记得有一次移植设备,WiFi死活打不开。查log发现是vendor分区里的WiFi固件版本不对。后来把正确的固件放进去,问题就解决了。这种问题在OTA升级里特别常见,因为固件和驱动版本必须匹配。

3.4 Super分区:动态分区的核心

Super分区是Android 10引入的新概念。它把system、vendor、product等分区合并成一个大的逻辑分区。这样做的好处是:分区大小可以动态调整,不用再担心某个分区不够用。

Super分区的布局

+------------------+
|   Super Header   |  // 超级头部,描述逻辑分区信息
+------------------+
|   System         |  // 逻辑分区1
+------------------+
|   Vendor         |  // 逻辑分区2
+------------------+
|   Product        |  // 逻辑分区3
+------------------+
|   ...            |  // 其他逻辑分区
+------------------+

生成Super镜像的命令:

# 编译后生成super.img
make superimage

# 或者生成vendor_boot等
make vendorbootimage

小技巧:如果你在调试阶段,可以用lpdump命令查看Super分区的实际布局:

lpdump /dev/block/by-name/super

这样能清楚看到每个逻辑分区的起始位置和大小。

3.5 DTBO与VBMeta:容易被忽略的配角

这两个分区虽然小,但作用不小。我刚开始做移植时经常忽略它们,结果吃了不少亏。

DTBO(Device Tree Blob Overlay)

DTBO是用来覆盖设备树的。说白了,就是允许你在不修改内核的情况下,调整硬件配置。比如你想换一个显示屏,只需要更新DTBO分区就行。

DTBO镜像的生成

# 编译DTBO
make dtboimage

# 查看DTBO内容
mkdtimg dump out/target/product/你的设备/dtbo.img

VBMeta(Verified Boot Metadata)

VBMeta是Android Verified Boot(AVB)的核心。它存储着各个分区的哈希值和签名信息。系统启动时,会校验这些哈希值,确保分区没有被篡改。

我遇到过一个问题:刷了第三方ROM后,手机一直提示"Your device is corrupt"。查了半天,发现是VBMeta里的哈希值和实际分区不匹配。解决办法是重新生成VBMeta镜像。

生成VBMeta的命令

# 编译时自动生成
make vbmetaimage

# 手动生成(调试用)
avbtool make_vbmeta_image \
  --include_descriptors_from_image boot.img \
  --include_descriptors_from_image system.img \
  --output vbmeta.img

重要提醒:在开发阶段,你可以用--disable_verity参数关闭校验,方便调试。但正式发布时一定要开启,否则设备的安全性会大打折扣。

3.6 分区布局的实战建议

好了,理论知识讲完了。我来总结一下实际移植时的经验:

  1. 先看分区表:拿到一个新设备,第一件事就是看它的分区表。用cat /proc/partitions或者ls -l /dev/block/by-name/查看。
  2. 确认分区大小:每个分区的大小必须和BoardConfig.mk里定义的一致。否则刷机时会报错。
  3. 注意AB分区:如果你的设备支持AB升级,那每个分区都有两份(比如boot_a和boot_b)。OTA升级时,系统会更新非活跃的那一份。
  4. 备份原始镜像:在刷机前,一定要备份原始设备的镜像。万一出了问题,还能恢复。

核心总结:分区布局是OTA升级的地基。地基不稳,后面全是白搭。我建议你花时间把每个分区的作用和生成方式搞清楚,这样后面做差分升级、AB切换时才不会手忙脚乱。

下一章,我们会聊到OTA升级的完整流程。到时候你会看到,这些分区是怎么协同工作的。嗯,做好准备,后面才是真正的硬仗。