RFC-0071:OTA 停止

RFC-0071:OTA 支持
状态已接受
领域
  • 系统
说明

阻止设备跨版本边界进行反向 OTA。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2021-02-03
审核日期(年-月-日)2021-02-24

摘要

本文档提出了防止设备安装无线下载 (OTA) 更新的计划 可跨版本边界向后提供

设计初衷

当存储堆栈对文件系统格式进行破坏性更改时, 格式的数量,这可防止在旧版系统上运行的驱动程序尝试 以新格式装载并使用映像。

在系统更新堆栈中提供等效版本号可防止用户尝试 通过 OTA 回退到其设备不支持文件系统映像的驱动程序版本 包含。换句话说:它将使“向后 OTA”失败操作之前 都是砖块

这会带来更多价值,因为:

  • 它对于任何保持状态的应用非常有用。例如, 维护 sqlite 数据库(其架构可能会随时间变化)的应用。
  • 具体而言,这对存储团队非常有用,因为过去他们必须 我们投入了大量时间来对问题进行分类,这些问题最终是由 版本边界。
  • 这将强调 Fuchsia 不支持向后 OTA;他们绝对是尽力而为

请务必注意,此方案不会更改支持的 OTA 序列以及 。它只是让这项支持变得明确。OTA 支持的主要目的是 防止开发者设备进入无效状态。对于正式版设备, 无后向 OTA 不变性应主要通过版本管理来强制执行。

如果不使用此方案,尝试跨越不兼容边界的向后 OTA 将会导致 (例如,文件系统格式可能 由驱动程序支持)。通过这项方案,开发者可以在实施 OTA(并且错误会更清晰),这是更好的开发者体验。

背景

术语

OTA 是一种升级底层操作系统的机制。OTAFuchsia 设备可以接收 以及为系统和应用软件安装 OTA 更新。

Stepping Stone build 是指在 OTA 中无法跳过的 build。例如,假设有三种 依序版本 A、B 和 C。传统上,我们需要支持来自 A->BB->CA->C。如果我们将 B 声明为跳石版本,则会移除 A->C 边缘,因此 让 A 升级到 C 的先后顺序是 OTA A->B,然后是 B->C。在实际使用中,这对于存在风险的迁移非常有用 为减少正向 OTA 数量,我们需要测试。

OTA 支持与跳板之间的关系

OTA 后备版本和阶梯版本都是我们执行安全迁移时必须用到的原语 (例如存储格式迁移)。有关 OTA 支持和 应使用的阶梯石版本不在此 RFC 的讨论范围内。在这里,我们只提供 有关如何使用这些原语来支持安全迁移的示例。

考虑迁移存储格式。我们可能会采取的步骤如下:

  1. 添加对新格式的支持,但先不要启用/迁移新格式。增强 OTA 支持。
  2. 请稍等片刻。
  3. 请使用上述迁移策略之一启用新格式。

对于我们实际迁移设备的情况,可以再执行两个步骤来启用 清理:

  1. 剪切包含 (3) 的分步版本。
  2. 移除迁移代码和对旧格式的支持。

通过“跳石”版本,我们可以假设设备经过的版本 迁移代码,这样我们以后就可以取消对旧格式的读取支持。

提升 (1) 中的 OTA 回避算法可确保设备不会降级到 对新格式的支持

与先进后援有关的政策

应根据需要一次性冲击倒退。绝大多数更改不应该要求 逆流撞击。如果此 RFC 获得批准,则应发布官方手册文档来说明 从而达到阻止退休的具体步骤同时,我们在这里简要介绍一下 此政策。

在建议通过 CL 来增强支持性时,作者应:

  • 提供 bug.fuchsia.dev 上问题的链接,说明为什么必须进行提升,以及如何进行提升 如果开发者确实需要跨支持性地降级其设备,可以继续操作 (例如,答案可能是“flash”或“pave”)。
  • 获得 //src/sys/pkg/OWNERS 批准。

设计

我们来引入一个 epoch.json 文件,使其同时存在于 更新软件包和系统上的软件包。 它应该是包含两个字符串键的 JSON 文件:

  • “version”,该参数应为 epoch.json 架构版本的单个字符串值。在 练习时,在执行更新时不会检查此项 - 此键的存在只是为了使其 在生产环境中进行 epoch.json 架构更改时。
  • “epoch”,应为 OTA 倒退的单个整数值。如果更新周期 软件包 <系统周期,我们应该使用 UNSUPPORTED_DOWNGRADE 在准备阶段使 OTA 失败。

例如,epoch.json 可能如下所示:

{
  "version": "1",
  "epoch": 5
}

为了安全地提升周期,我们还引入了一个经过编译的 epoch_history 文件 通过构建系统导入到 epoch.json 中。epoch_history 文件可以采用以下格式:

0=Initial epoch (https://fxbug.dev/42144857)
1=Storage format migration (https://fxbug.dev/XXXXX)
...
N=Most recent change (https://fxbug.dev/YYYYY)

每次出现向后不兼容的更改时,都应手动提升 epoch_history 文件 推出

虽然中间 epoch_history 文件增加了另一层复杂性,但此方法 优势,因为:

  • 它提供所有版本递增更改的日志(强制文档!)
  • 如果两个人出于不同的原因试图达到新纪元,则会产生合并冲突。

实现

这些更改将完全在平台(特别是系统更新堆栈)中进行。

要进行此更改,我们需要执行以下操作:

  • epoch_history 添加到 //src/sys/pkg/bin/system-updater。
    • 此外,编写一个将 epoch_history 转换为 epoch.json 的脚本。
    • 让构建系统使用此脚本将 epoch.json 添加到 system-updater 的 out 目录下。
  • 修改 BUILD 以便将 epoch.json 也放入更新软件包。
  • 系统更新程序应在 Prepare 阶段结束时检查 epoch.json
    • 如果更新软件包中没有 epoch.json,或者反序列化时出现问题, 假设周期为 0。我们会刻意忽略错误,以便在 epoch.json 架构更改。
    • 如果系统更新程序的输出目录中没有 epoch.json,或者 反序列化存在问题,由于这是意外情况而失败。 您可以考虑使用 include_str 宏 从 out 目录中读取。
    • 如果更新软件包中的周期小于或等于system-updater 中的周期,准备失败 原因:UNSUPPORTED_DOWNGRADE。我们需要创建一个新的 PrepareFailureReason 价格为 UNSUPPORTED_DOWNGRADE

安全

这不是安全功能。不过,它可能会与安全功能交互,以改进开发者 工作流。例如,假设回滚保护功能拒绝启动以下映像 版本 N。如果在发布映像版本 N 时递增周期数,就会阻止开发者 因为在 OTA 支持时这些降级会失败。

除此之外,我们还选择将 epoch.json 嵌入到系统更新程序二进制文件中(而不是 config-data)来使 OTA 能够灵活应对 config-data 损坏。

隐私权和性能方面的注意事项

不适用

测试

我们可以使用 //src/sys/pkg 中现有的系统更新测试框架,该框架混合了广告单元 和集成测试

此外,OTA e2e 测试将确保两个逆转 格式有效。例如:

  • 如果 build N 降低 OTA 支持,则在从 build N-1N 的 CI 中,将无法进行 OTA 更新。
  • 如果 build N 在系统更新程序中生成无效的 epoch.json,则从 CI 到 OTA 的操作将会失败
  • N 构建为 N'

文档

我们需要创建一个文档来说明用于更新 epoch_history 的政策。

此外,我们还需要修改以下内容:

缺点、替代方案和未知问题

实施此提案的费用是多少?

实施此提案的主要成本是增加平台的复杂性,因为我们会增加 向平台传递另一个版本标识符。

还有哪些策略有可能解决同样的问题?

另一种策略是正式支持所有向后 OTA。这是不切实际的 我们不知道如何从容应对未来变化。

另一种策略是明确禁止所有向后 OTA(即使是 )。例如,我们可以在每次构建新 build 时自动提升后备值。我们决定不 因为在实践中,一些开发者确实依赖于这些后向 OTA,我们希望 不会破坏这些开发者

另一种方法是直接集成 Fuchsia 平台版本控制(请参阅 RFC-0002)。不过, 一些含糊不清的问题例如,某个 API 级别的所有向后 OTA 都应是 还是应该选择特定的级别?我们要摧毁谁?由于在 Fuchsia,用于为系统的不同部分(例如,文件 系统都有自己的版本标识符),看来这个选择更为简单。

先验技术和参考资料

Android 提供了有关 OTA 的更多信息。

致谢

James Sullivan 为创作的动力和层层搭建的阶梯式贡献了力量。扎克·基尔申鲍姆写道 原始设计文档,由 Dan Johnson 审核。