RFC-0115:build 类型

RFC-0115:build 类型
状态已接受
领域
  • 系统
说明

产品 build 类型的规范定义。

Gerrit 更改
  • 552446
作者
审核人
提交日期(年-月-日)2021-07-06
审核日期(年-月-日)2021-07-21

总结

本文档介绍了 Fuchsia 的不同产品 build 类型:enguserdebuguser

Fuchsia 中的 build 类型是指产品配置的构建时间和运行时设置:

  • 构建时设置包括软件包、工具、签名配置和定义系统行为的标志。

  • 运行时设置包括传递给正在运行的内核或软件根据 build 类型调整运行时行为的标志。

本文档旨在正式批准针对已在使用这些 build 类型的 Fuchsia 产品制定的设计决策。它还可用作 Fuchsia 平台中不同 build 类型的正式定义。

设计初衷

Fuchsia 定义了几种 build 类型,供各种用户(包括开发者、测试人员和最终用户)使用。其中每个用户组都对正在运行的紫色系统的行为都有特定预期。

特定的 build 类型针对不同用例(如开发或向最终用户交付的产品)编写并保证了某些 Fuchsia 系统行为。

此外,还可以根据产品 build 类型做出构建时决策(例如添加特定软件包变种)。如需了解详情和查看示例,请参阅软件包变种部分。

因此,不同的 build 类型为 Fuchsia 平台及其用户提供必要的灵活性,以支持 Fuchsia 产品的整个生命周期。

设计

本部分概述了紫色上目前常用的 build 类型惯例。其中会详细说明每种类型的不同属性以及运行时限制(如果适用)。

由于复杂性和实现成本,还需要注意与定义的 build 类型数量相关的限制条件。如需了解详情,请参阅缺点部分。

根据 Fuchsia 的当前要求,有三种 build 类型:

  • user
  • userdebug
  • eng

下面的定义部分进一步说明了 build 类型。

其他 build 类型需要一个通过 RFC 流程并经过 Fuchsia 工程委员会 (FEC) 批准的提案。

目标

设计的主要目标是:

  • 为支持开发者需求以及最终产品交付要求的 build 类型制定通用惯例。
  • 实现 build 类型时应尽可能相似,以免产品的行为出现额外的差异。
  • build 类型会发布,并以相同的标准和频率进行资格认证。

定义

user

user build 类型用于交付给最终用户的正式版设备。

对于 user build,平台会在运行时强制执行最高的安全保证,并且在构建期间仅包含产品所需的组件。

userdebug

默认情况下,userdebug build 类型的行为与 user 相同,但允许其他调试和插桩行为。

userdebug build 主要用于开发设备,用于最终用户的产品测试和资格认证。

eng

eng build 类型主要面向开发者和测试人员,旨在启动到产品会话所定义的完整产品体验。

各种产品配置的 eng build 可在树内找到,并可作为预构建系统映像与 Fuchsia SDK 一起提供。

产品配置

build 类型被定义为产品专用配置。为了保持不同 build 类型之间的相似性,这些配置会从 Fuchsia 的核心产品继承和包含,并有选择地添加或移除软件包和配置。

build 类型关系总结如下:

build 类型。请注意以下事项。

图 1:作为产品配置的 build 类型。

注意:

  • eng build 类型继承 core,可以包含产品专用的其他软件包。

  • “user”build 类型会直接继承 core,但会移除任何额外的软件包、调试功能和其他插桩属性。

  • 然后,userdebug 会继承 user,并且略有不同,以便启用调试和插桩所需的其他功能。

  • userdebuguser 之间的反向继承可确保最终用户产品所需的 user 所做的任何更改都会自动反映在 userdebug build 中。

  • 设计大致反映了产品周期,其中 eng 是基于 core 紫红色产品构建的首个产品配置。然后,当产品沿其生命周期进一步发展时,系统会定义 userdebuguser,以反映这些用例和要求。

实现

以下部分按照平台的主要区域整理了每种 build 类型的实现详情。

断言

Zircon 是为 Fuchsia 提供支持的核心平台,由内核以及一小部分用户空间服务、驱动程序和库组成。

在整个代码库中,有几种不同的类似断言的机制。内核和用户模式断言可以启用或停用,具体取决于 build 类型。例如,ZX_ASSERT 对所有 build 类型始终处于开启状态,并且必须降低费用以免影响性能。

再举一个例子,assert_leveleng build 中是 2,并且会启用所有断言;而对于 userdebuguser build,这是 0,这会停用标准 C assert()ZX_DEBUG_ASSERT

下表概述了内核中的断言:

属性 eng userdebug、user
评估 开启 开启
DEBUG_ASSERT 开启 关闭
assert() 开启 关闭

恢复分区

Fuchsia 最终用户产品使用 A/B/R 更新和恢复方案。

总而言之,通过无线下载 (OTA) 机制进行的系统更新会利用 A/B 更新方案,其中存在两个系统副本(一个处于活动状态,另一个处于非活动状态)。这样可以确保系统在更新失败时具有回退机制。不过,如果回退无法启动,系统会使用存储在恢复分区中的恢复映像来尝试恢复系统。

每个产品都可以定义自己的恢复映像。默认情况下,eng build 会使用 zedboot。由于 zedboot 用于铺砌 Fuchsia 系统,因此它可以提供调试端口和其他工具来恢复系统。

userdebuguser 中,使用的是不同的恢复映像,该映像最小且符合最终用户产品的安全要求。

属性 eng userdebug、user
恢复 (R) Zedboot 最小恢复映像

软件包和更新

自动更新软件包

eng build 类型中,auto_update_packages 默认处于启用状态。因此,在解析组件(即通过运行组件)时,首先会尝试通过 fuchsia.pkg.PackageResolver 更新组件的软件包。

在日常开发中,此工具对于确保系统始终运行开发者环境中的最新组件非常有用。

对于 userdebuguser build,此功能已停用。对组件和软件包所做的任何更改都必须通过系统更新完成,这会更改 base 系统中的软件包并触发重新启动。

属性 eng userdebug、user
auto_update_packages true

软件包变种

软件包变种用于指定软件包的 eng 变种,然后该变种会包含组件的 eng 变种。然后,软件包会包含在定义 eng build 类型的产品配置中。

例如:

package_flavor_selections += [
  {
    name = "my_component_pkg"
    flavor = "eng"
  },
]

同样,软件包的 user 变种会包含在产品的 user build 中。

系统更新

Fuchsia 使用无线下载 (OTA) 更新机制来进行操作系统更新。有两个入口点,即 omaha-clientsystem-update-checker 组件:

属性 eng userdebug、user
自动系统 OTA true
更新检查工具 system-update-checker omaha-client
Omaha 配置 不适用 已定义

Omaha 配置定义了用于执行系统更新的服务器端配置,该配置适用于最终用户 build,例如 userdebuguser

Omaha 配置包含存储在 VBMeta 中的信息,以确保在执行前验证软件的完整信任根。

软件包集、可运行的组件和许可名单

Fuchsia 开发板和产品定义扩充了三个依赖项列表,即 Base、Cache 和 Universe。因此,这些集中定义的软件包决定了它们在 Fuchsia 中的管理方式。

例如,只能通过系统 OTA 更新对 base 集中的软件包进行更改。因此,这需要重新启动系统。

由于 universe 集允许访问整个 Fuchsia 软件集,因此不允许在 user build 中使用。

属性 eng userdebug 用户
可用集 基本, 缓存, 宇宙 基本, 缓存, 宇宙 基础
许可名单 允许所有软件包 基本版本 + 许可名单 仅基数

许可名单是一项政策,用于确定可以运行哪个组件(根据组件网址),或哪个组件可以在运行时访问特定服务。这有助于确保 user build 不会运行用于 eng build 的开发组件或服务。

再举一个例子,可以使用 userdebug build 运行一组有限的工具来检查系统,例如使用 iquery 来检查正在运行的组件的属性。

user 中,只允许运行产品所需的软件。在当前设计中,此软件仅限于 base 集内包含的内容。

软件来源

Fuchsia 软件通过托管在软件代码库中的软件包提供。这些软件来源必须为 Fuchsia 所知,并通过信任链以加密方式进行验证。

对于 eng build,可以在运行时将哪些软件源代码添加到系统没有任何限制。

对于 userdebug build,只有当目标系统通过直接接口连接到开发者的主机工作站时,才能添加软件源代码。

user build 中的软件源代码是固定的,不可修改。

调试、日志和 Shell

eng build 可实现对 Fuchsia 系统的完整访问权限,并提供所有调试端口和日志。user build 会限制所有访问和日志,而 userdebug 会出于调试目的而仅启用受限访问权限。

属性 eng userdebug 用户
ssh 已启用 已启用 已停用
序列号 已启用 r/o 引导加载程序和内核 引导加载程序中的 r/o
调试代理 已启用 已停用 已停用
k 命令 已启用 已停用 已停用
ffx 运行时 已启用 已启用 已停用

崩溃报告

崩溃报告服务由 fuchsia.feedback API 提供。默认情况下,系统会对 eng build 停用崩溃上传功能。对于 useruserdebug build,必须明确征得用户同意,才能启用崩溃报告上传功能。

默认情况下,系统仍会捕获所有 build 的崩溃报告,并将其存储在本地崩溃报告数据库中。

属性 eng userdebug、user
崩溃报告 已启用 已启用
崩溃上传 已停用 经用户同意后允许使用

崩溃上传的内容包括系统和内核日志文件,以及有助于对问题进行分类的组件检查数据。这些数据文件可能包含个人身份信息 (PII),会在上传之前进行清理。

遥测

Fuchsia 平台提供记录、收集和分析指标的服务。此服务由 fuchsia.metrics 提供。Cobalt 的两大支柱是保护用户隐私并提供高质量的汇总指标,以满足系统和组件软件开发者的需求。

属性 eng userdebug、user
指标收集 已启用 已启用
指标上传 已启用 经用户同意后允许使用

经过验证的执行

“验证执行”是 Fuchsia 安全性的核心设计,可确保所有已执行代码都是可信的。可信度通过哈希验证和来自可信实体的数字签名以递归方式断言,从不可变的信任锚开始。

启动时验证

启动时验证是一个验证执行阶段,在此阶段中,引导加载程序会验证 Fuchsia zbi 是否可信,可被引导加载程序执行。

本地 build(无论是 enguserdebug 还是 user)使用树内开发密钥,而为发布而生成的 build 则使用从安全密钥管理服务获取的更安全密钥签名。

预构建系统映像

预构建的 eng 映像在 Fuchsia SDK 中提供,而 userdebuguser build 可直接从 Fuchsia 全球集成构建器下载。

构建时间优化

Fuchsia 平台的常规构建优化标志在所有 build 类型中保持不变,以保持各个 build 之间的一致性。

eng build 中,is_debug 设为 true,这会将默认标志设置为 debug,而非 useruserdebug build 中设置的 speed。这些标志在全局 BUILD.gn 文件中的各种配置中都携带和使用。

对于组件,eng 软件包变种可以包含使用特殊标志编译的组件。例如,开发者 build 和机器人配置中通常会启用 DCHECK 断言,以帮助捕获 C++ 组件中的意外问题。

性能

可以理解,与 userdebug build 相比,eng build 可能会导致性能下降,但实际损失因产品和开发板类型而异。主要影响来自在平台中启用额外的断言。这是使用 /zircon/system/ulib/perftest 进行测试的。

在组件中,如果在基准测试和测试期间大量使用这些组件,那么启用 DCHECKeng 变种也会对性能产生重大影响。

userdebuguser build 之间的性能差异非常小。在进行性能基准测试时,首选 userdebug build 而非 eng build。这种方法存在一些缺点,请参阅下面的缺点部分。

安全注意事项

Fuchsia build 类型的设计充分考虑了安全隐患。自始至终,以下方法都旨在为所有用户强制执行最高级别的安全保证:

  • 利用“已验证的执行”功能,通过为加密签名分别使用单独的签名密钥,在启动时建立经过验证的完整信任链。

  • 利用组件框架中的许可名单安全政策,确保仅解析和执行允许的组件。

  • 只为最终用户 build 添加必要的软件包和组件。

  • 停用最终用户 build 中的所有访问端口和设施。

隐私注意事项

在设计 Fuchsia build 类型时,也充分考虑了隐私保护注意事项。系统会从最终用户 build 中擦除个人身份信息,并在上传崩溃、日志和指标之前征得用户同意。

文档

build 类型将在 Fuchsia > Concepts > Build System 中进一步记录,因此在 Fuchsia 中的产品适用不同属性和行为时,有一个针对不同属性和行为的规范引用。

测试

模拟器

如需测试不同 build 类型的行为,最简单直接的方法就是利用 Fuchsia 模拟器

开发者可以通过模拟器来模拟 build 类型,以便比较和测试平台和应用的不同行为。其缺点是,无法在模拟器环境中测试系统的某些方面,例如系统更新或启动时验证属性。

发布流程

Fuchsia 利用 CI(持续集成)和 CQ(提交队列)流水线,确保在 CL(变更列表)推出之前以及 CL 合并后的最终集成期间构建和测试代码更改。

  • CQ 流水线,在 CL 推出之前,跨不同的产品配置和环境构建和测试 CL。

  • CI 流水线构建和测试在同一集成提交中跨不同产品配置签入的代码。

由于 build 类型也是作为产品配置实现的,因此所有 build 类型配置都需要通过相同的 CI/CQ 流水线同时构建、测试和发布。

请注意,只有 eng build 类型产品配置会在 CI/CQ 中进行测试。不过,useruserdebug 仍然是持续构建流程的一部分。

设施

enguserdebug build 中设置的“宇宙”中提供了测试框架和工具。默认情况下,这些服务未启用,但已列入许可名单,以便在运行时解析和执行。

对于 user build,安全政策未启用也不允许使用测试工具。

例如,Fuchsia 针对端到端测试使用 SL4F 框架,针对组件框架测试使用 test_runner

对于自动化测试用例,可以使用上述框架。但是,如果需要其他软件包或其他工具,建议使用 eng build。

缺点、替代方案和未知情况

此 RFC 中记录的设计已实现,并反映了 Fuchsia 产品 build 类型的当前状态。

通过利用产品配置实现 build 类型,可以利用和重复使用现有的实现。主要缺点是此方法的可伸缩性和灵活性。例如,每个新产品都需要至少三种与三种 build 类型相匹配的产品配置。此方法会产生实现冗余,以及 Fuchsia 基础架构为这些新配置启动构建器所需的额外资源。

另一个缺点是需要测试 userdebug build。由于 userdebug build 包含特定变种的软件包、不同的系统更新配置,并且未启用调试标志,因此需要它们来运行端到端测试。但由于安全限制,SL4F 无法在官方 userdebug build 中运行。

作为替代方案,独立系统组件能够修改组装的映像,并可用于组装本地 userdebug build,这些 build 允许访问测试框架且限制较少。

将来,我们应采用一种扩缩能力更强的方法,允许将 enguserdebuguser build 类型配置文件应用于不同的产品配置。这样可以避免新产品需要多个产品配置才能适应 build 类型的线性扩缩问题。

另外值得注意的是,当前的实现融合了产品和平台,这并不是 Fuchsia 平台的长期目标。如前所述,建议将来考虑采用更灵活的设计。

早期技术和参考资料

Android 操作系统:

  • 定义 enguserdebuguser build。
  • 发布了有关修改 userdebug build 的最佳实践指南