| RFC-0170:从更新软件包中移除二进制映像 | |
|---|---|
| 状态 | 已接受 |
| 区域 |
|
| 说明 | 在 OTA 期间重新排序映像写入,以节省空间。 |
| 问题 | |
| Gerrit 更改 | |
| 作者 | |
| 审核人 | |
| 提交日期(年-月-日) | 2022-05-12 |
| 审核日期(年-月-日) | 2022-06-22 |
摘要
为了回收系统上的空间,我们必须拆分更新软件包。在至少一个空间受限的产品上,我们将节省约 14MiB。这是一项非微不足道的更改,需要过渡版本。根据 RFC 103,所有过渡版本都需要有自己的 RFC。此 RFC 详细介绍了新的更新软件包格式。
设计初衷
无线下载 (OTA) 更新是一种用于升级正在运行的设备上的 Fuchsia 版本的机制。如果有可用更新,系统更新程序将提取更新软件包。提取软件包是指将软件包的内容写入 BlobFS 并防止其被垃圾回收。更新软件包包含映像(例如 recovery 映像和 Zircon 启动映像),这些映像在 Zircon 分区上也有预留空间,此外还包含要下载的其他软件包的列表,以便完成更新。
目前,Fuchsia 设备必须存储每个映像的两个副本:
- 一份位于设备在运行时使用的目标分区(例如 ZIRCON_A)中。
- blobfs 中的一个副本,因为映像作为更新软件包中的 blob 交付给设备。
通过保护映像免受垃圾回收的影响,更新可保证在中断时向前推进。对于更新系统而言,向前进度是一项非常重要的保证属性。不过,在空间受限的产品上,将映像写入磁盘分区和 BlobFS 都是次优的预算分配方式。
映像写入是 OTA 过程中的倒数第二步,之后会切换哪个分区是活动分区,并重新启动到新的系统映像。在下一次更新之前,内核、固件和恢复映像不会被垃圾回收和删除。通过在 OTA 期间重新排序映像写入,我们可以在下载 OTA 中的大多数软件包之前从 BlobFS 中回收映像,并回收空间预算以供其他软件包使用。更改 SWD 设计以移除重复的映像副本,有望节省大量空间,这对于某些 Fuchsia 设备来说非常重要。
为了在 OTA 期间对二进制映像进行垃圾回收,同时仍能保证向前进度,我们需要更改更新软件包的格式。
利益相关方
教员:hjfreyer@google.com
审核者:
- 软件交付:wittrock@google.com、jsankey@google.com
- MOS: gtsai@google.com
- 安全性:ampearce@google.com
- Product Assembly:awolter@google.com
- 发布者:billstevenson@google.com
设计
目前,更新软件包是一种还包含映像的软件包,当提取更新软件包时,这些映像会被提取并写入到 blobfs。
我们建议将映像从更新软件包中提取出来,并将每个映像放入其自己的软件包中。
这与我们当前的 OTA 流程和软件包格式完美契合,但确实需要更改更新软件包格式。
为了引用这些新软件包,我们将向更新软件包添加一个名为 images.json 的文件,其中包含描述图片软件包的元数据。该文件的一个示例如下:
{
"version": "1",
"contents": {
"partitions": [
{
"type": "zbi",
"slot": "fuchsia",
"size": 1,
"hash": "0a",
"url": "fuchsia-pkg://fuchsia.com/fuchsia-zbi/0?hash={merkle_hash}#path/to/fuchsia.zbi"
},
{
"type": "vbmeta",
"slot": "fuchsia",
"size": 2,
"hash": "0b",
"url": "fuchsia-pkg://fuchsia.com/fuchsia-vbmeta/0?hash={merkle_hash}#path/to/fuchsia.vbmeta"
},
{
"type": "zbi",
"slot": "recovery",
"size": 3,
"hash": "0c",
"url": "fuchsia-pkg://fuchsia.com/recovery-zbi/0?hash={merkle_hash}#path/to/recovery.zbi"
},
{
"type": "vbmeta",
"slot": "recovery",
"size": 4,
"hash": "0d",
"url": "fuchsia-pkg://fuchsia.com/recovery-vbmeta/0?hash={merkle_hash}#path/to/recovery.vbmeta"
}
],
"firmware": [
{
"type": "",
"size": 5,
"hash": "0e",
"url": "fuchsia-pkg://fuchsia.com/update-images-firmware/0?hash={merkle_hash}#path/to/firmware"
},
{
"type": "bl2",
"size": 6,
"hash": "0e",
"url": "fuchsia-pkg://fuchsia.com/update-images-firmware/0?hash={merkle_hash}#path/to/firmware"
}
]
}
}
版本属性定义了应如何解读内容属性。 使用此 RFC 定义的格式时,版本必须始终为“1”,但现在引入版本属性可简化未来可能需要的其他更改。此模式已在 SWD 堆栈的清单中其他位置使用,并且与 serde 集成良好。
系统更新程序将解析清单,以确定是否需要提取映像(根据相应哈希值的文件是否已位于相应 slot 中)。对于每个已更改的映像,系统会先提取该映像,将其写入相应分区,然后从 BlobFS 中对其进行垃圾回收。如果 images.json 中没有图片,则我们不会覆盖 zircon 分区中已有的内容。
系统会包含图片的大小和哈希值,以供验证检查。哈希是图片文件的 SHA256 哈希,以十六进制表示。由于分区在不同设备上各不相同,我们还需要知道映像的大小以便进行比较。网址具有 Merkle 哈希值。Merkle 哈希的计算较为复杂,因此选择 SHA256 哈希是为了更快地进行比较。
我们建议的 OTA 流程如下:
- 下载更新软件包
- 解析包含更新图片软件包引用的新元数据文件
- 对于该文件中列出的每个映像,如果该映像与非活动分区上指定 Zircon 分区中的映像相同,则继续。元数据文件包含映像的哈希和大小(因为映像大小不等于分区大小),我们可以快速将其与非活动分区上映像的哈希进行比较。否则:
- 获取包含映像的软件包,该软件包会将映像写入 BlobFS 并处理完整性检查。将软件包添加到保留的索引中。
- 写入分区。
- 通过从保留的索引中移除软件包来从 BlobFS 中进行垃圾回收,以回收空间。
- 继续下载更新软件包中指定的其余软件包,并完成 OTA。
更改更新软件包的结构有助于我们解决空间限制问题。写入 BlobFS 然后进行垃圾回收,可让我们利用当前存储架构提供的全面安全保障。
实现
为了对更新软件包进行此更改,我们必须进行三阶段发布:首先处理当前更新软件包格式和新更新软件包格式的超集,其次发布仅生成新格式的版本,最后发布停止处理旧版更新软件包的逻辑。
在第一阶段,系统更新程序将进行修改,以成功解析原始更新软件包格式和此 RFC 中提出的修改后格式。MOS 仍将使用原始格式生成更新软件包。包含此工作的版本将被标记为过渡版本,以确保所有 Fuchsia 设备在收到使用新格式的更新软件包之前,都收到能够解析新格式的 system_updater。
在第二阶段,MOS 将开始使用此 RFC 提议的新格式生成更新软件包。
在第三阶段,一旦我们确信没有设备需要回滚到使用原始更新软件包格式的版本,我们将修改 system_updater 以移除对原始更新软件包格式的支持。
如果我们不分阶段发布,那么只能解读当前版本更新软件包的设备在收到更新后的更新软件包时,就会出现故障。我们需要将第一阶段版本标记为“垫脚石” build,以确保所有设备都通过该 build。
更新软件包的用户需要了解分阶段发布。已知用户包括 Security vis a vis Scrutiny、MOS、Product Assembly 和 Software Delivery。
性能
预计不会有明显变化。
我们需要获取图片的哈希值并进行比较。在最佳情况下,哈希值匹配,我们无需花费时间来提取或写入它们。在所有图片都发生变化的最坏情况下,我们仍然需要下载和写入相同数量的字节。
安全注意事项
Scrutiny(我们的 build 时安全分析工具)会分析更新软件包,从中提取 ZBI。我们需要更新 Scrutiny 测试,以反映更新软件包中 ZBI 的新位置。
映像的完整性检查不会发生变化。我们将继续使用相同的方法来获取更新软件包,并且更新软件包包含映像软件包的哈希值,当设备重启进入新系统时,经过验证的启动会强制执行所有其他安全属性。
隐私保护注意事项
此 RFC 不会更改图片的创建或内容,只会更改图片的传送顺序,因此不会影响隐私。
测试
我们已经针对更新软件包和系统更新程序进行了单元测试和端到端集成测试。我们需要扩展这些测试,以涵盖从当前版本的更新软件包到第一个过渡版本的中间版本。对于第二个版本,我们需要有测试来处理更新软件包的中间版本和新版本。工作完成后,我们将移除中间测试,并测试采用旧格式的更新软件包的降级 OTA 是否始终会失败。
文档
如果此更改获得批准,我们将需要更新更新软件包文档和 OTA 文档。
缺点、替代方案、未知因素
替代方案是不将图片写入 BlobFS 的设计。
一种简单的方法是将映像直接铺设到其分区,从 blobfs 中回收更新软件包,最后下载保留的索引中包含的新软件包 blob。此替代方案易于实现,可避免重复写入,并且不需要过渡版本。不过,我们无法再保证取得进展。如果更新中断,设备可能会完全无法更新。
还有一种替代方案,即我们保留更新软件包中的映像,但将更新软件包视为比现在更特殊的软件包:我们可以完全避免将映像保存到 blobfs。此设计无需更改更新软件包的格式,但需要对系统更新程序逻辑进行广泛的更改,并使更新软件包的处理方式与“正常”软件包的处理方式不同。我们认为,提议的设计只是重构了更新软件包,而没有引入特殊的处理逻辑。
现有技术
更新软件包的设计之前已在 fuchsia.dev 上记录。