9、动态分区与GSI:Generic System Image对动态分区的要求
聊到GSI,也就是通用系统镜像,很多做ROM开发的朋友应该不陌生。Google搞出这个东西,初衷是为了解决碎片化问题——你想想看,一台手机能不能跑原生的AOSP,跑起来之后功能正不正常,这本来是个很基础的事情。但实际项目中,我见过太多因为分区布局不标准,导致GSI刷进去直接变砖的案例。
GSI说白了就是一个纯的system镜像,它不包含vendor、product这些分区的内容。那问题来了——动态分区架构下,system分区本身都是逻辑卷了,GSI要怎么适配?
GSI对动态分区的核心要求
我个人习惯把GSI对动态分区的要求归纳为三点:
- 必须支持super分区:GSI要求设备必须使用super分区来管理system、system_ext、product等逻辑分区。老式的块设备映射方式,GSI根本不认。
- 逻辑卷大小必须足够:GSI的system镜像通常比厂商自带的system要大,因为包含了完整的AOSP框架。如果super分区里给system预留的空间不够,GSI刷进去就会报错。
- 分区命名必须规范:GSI要求逻辑分区的命名必须符合
标准,比如system、system_ext、product。你改成my_system、my_product,GSI启动时直接找不到分区。
核心要点:GSI本质上是一个“通用”的system镜像,它假设所有设备都遵循同样的分区布局规则。动态分区架构恰好提供了这种灵活性——只要super分区足够大,GSI就能自适应。
分区大小:一个容易被忽略的坑
我在项目中遇到过这样一个情况:某款设备super分区总共给了4GB,厂商自己的system只有1.2GB,product占800MB,system_ext占300MB。看起来挺合理对吧?但GSI的system镜像普遍在2GB以上,加上product和system_ext,直接超出super分区容量。
结果就是——刷完GSI,设备卡在开机动画,log里报“insufficient space in super partition”。
为什么会这样?因为GSI不会去压缩自己,它要求你的super分区必须能装下完整的AOSP镜像。我建议做GSI兼容性测试时,先算一笔账:
| 分区 | 厂商镜像大小 | GSI镜像大小 | 差值 |
|---|---|---|---|
| system | 1.2 GB | 2.4 GB | +1.2 GB |
| system_ext | 300 MB | 500 MB | +200 MB |
| product | 800 MB | 1.2 GB | +400 MB |
| 总计 | 2.3 GB | 4.1 GB | +1.8 GB |
你看,如果super分区只有4GB,GSI刷进去就只剩-0.1GB了,这还没算metadata开销。所以,想要支持GSI,super分区至少得留出5GB以上的空间,这是硬性门槛。
分区命名与布局规范
GSI对分区命名的要求非常严格。我记得有一次调试GSI启动失败,折腾了半天,最后发现是product分区被命名成了“my_product”。GSI在init阶段会按固定名称查找逻辑卷,找不到就直接跳过,导致product挂载失败。
正确的命名应该是这样的:
# 标准动态分区布局
super分区包含以下逻辑卷:
- system_a / system_b
- system_ext_a / system_ext_b
- product_a / product_b
- vendor_a / vendor_b(可选,GSI通常不包含vendor)
# 注意:GSI只使用system、system_ext、product
# vendor由设备厂商提供,GSI不覆盖
嗯,这里要注意一点:GSI虽然不包含vendor,但它会依赖vendor提供的接口。如果vendor分区里的HAL实现不标准,GSI照样跑不起来。这属于另一个话题了,我们后面再细聊。
动态分区与GSI的兼容性矩阵
为了方便判断设备是否支持GSI,我整理了一个简单的对照表:
| 设备条件 | GSI兼容性 | 说明 |
|---|---|---|
| 支持动态分区,super≥5GB | ✅ 完全兼容 | 可直接刷入标准GSI |
| 支持动态分区,super<5GB | ⚠️ 部分兼容 | 可能需要裁剪GSI或调整分区大小 |
| 不支持动态分区(传统分区) | ❌ 不兼容 | GSI要求必须使用super分区 |
| 动态分区但命名不规范 | ❌ 不兼容 | GSI无法挂载非标准分区名 |
避坑指南:我曾经遇到过一台设备,super分区容量足够,命名也规范,但GSI刷进去还是启动失败。最后发现是vbmeta分区没有禁用AVB验证。GSI是未签名的镜像,如果设备强制校验系统分区完整性,就会直接拒绝启动。解决方案是:fastboot --disable-verity --disable-verification flash vbmeta vbmeta.img
GSI对动态分区的底层要求
从实现层面看,GSI对动态分区还有几个隐藏要求:
- 逻辑块大小必须对齐:GSI镜像的块大小通常是4K,如果super分区的逻辑块大小不匹配,刷写时会报错。
- 必须支持COW(写时复制):GSI在OTA升级时依赖COW机制来保存增量数据。如果设备不支持COW,GSI的OTA更新会失败。
- metadata版本要兼容:GSI使用的lpmake工具生成的metadata版本,必须和设备端的liblp库版本匹配。版本不匹配会导致逻辑卷无法挂载。
说白了,GSI就像是一个“外来者”,它要求你的设备必须遵循一套标准化的分区管理协议。动态分区架构本身就是这套协议的核心载体。
一张图看懂GSI与动态分区的关系
下面这张图是我画的,展示了GSI在动态分区架构下的加载流程:
从这张图可以看得很清楚:GSI本质上只关心super分区里的system、system_ext和product这三个逻辑卷。只要这三个分区存在且大小足够,GSI就能正常工作。vendor和其他分区,GSI一概不管——这也是它“通用”二字的由来。
警告:千万不要在GSI刷入后尝试修改vendor分区里的内容。GSI和vendor之间通过HAL接口通信,一旦vendor的接口实现与GSI不匹配,轻则功能异常,重则直接不开机。我见过有人刷了GSI后手痒去改vendor下的so库,结果设备变砖,只能重刷全量包。
好了,关于GSI对动态分区的要求,核心就是这几点:super分区容量要够、分区命名要规范、metadata要兼容。你想想看,GSI之所以能“通用”,正是因为动态分区提供了标准化的逻辑卷管理能力。没有动态分区,GSI就失去了生存的土壤。
公众号:蓝海资料掘金营,微信deep3321