RFC-0115:build 类型

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

产品 build 类型的规范定义。

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

摘要

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

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

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

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

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

设计初衷

Fuchsia 定义了多种 build 类型,供开发者、测试人员和最终用户等多种用户使用。这三个用户群体对正在运行的 Fuchsia 系统的行为有不同的预期。

特定 build 类型会对不同的用例(例如开发或面向最终用户分发的产品)编码并保证特定的 Fuchsia 系统行为。

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

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

设计

本部分概述了 Fuchsia 上 build 类型的当前常见惯例。其中详细介绍了每种类型的不同属性以及运行时限制(如果适用)。

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

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

  • user
  • userdebug
  • eng

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

如需添加其他 build 类型,则需要提交一份提案,该提案需要通过 RFC 流程并获得 Fuchsia 工程委员会 (FEC) 的批准。

目标

该设计的主要目标如下:

  • 为构建类型制定正式的通用惯例,以支持开发者需求以及最终产品发布要求。
  • 实现 build 类型时,应尽可能使其尽可能相似,以避免产品行为出现进一步差异。
  • 构建类型的发布和资格认定采用相同的条件和节奏。

定义

user

user build 类型用于面向最终用户出货的正式版设备。

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

userdebug

userdebug build 类型的行为默认与 user 相同,但允许进行额外的调试和插桩操作。

userdebug build 主要用于开发设备,以进行最终用户产品测试和认证。

eng

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

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

产品配置

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

构建类型关系可以总结如下:

build 类型。备注如下。

图 1:将 build 类型用作商品配置。

注意:

  • eng build 类型会继承 core,并且可以包含特定于产品的其他软件包。

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

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

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

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

实现

以下部分按平台的主要领域记录了每种 build 类型的实现详情。

断言

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

整个代码库中使用了几种不同的类似断言的机制。内核和用户模式断言的启用或停用取决于 build 类型。例如,ZX_ASSERT 始终针对所有 build 类型处于启用状态,并且必须更便宜,以免影响性能。

再举一个示例,assert_leveleng build 中为 2,并启用所有断言,而在 userdebuguser build 中为 0,这会停用标准 C assert()ZX_DEBUG_ASSERT

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

属性 eng userdebug、user
ASSERT 开启 开启
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 false

软件包变种

软件包变种用于指定软件包的 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 false true
更新检查工具 system-update-checker omaha-client
Omaha 配置 不适用 已定义

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

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

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

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

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

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

属性 eng userdebug user
可用套装 base、cache、universe base、cache、universe 基础
许可名单 允许所有软件包 基准 + 许可名单 仅限基础

许可名单是一种政策,用于确定哪些组件可以运行(基于组件网址),或哪些组件可以在运行时访问特定服务。例如,这对于确保 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 user
ssh 已启用 已启用 已停用
serial 已启用 只读引导加载程序和内核 引导加载程序中的 r/o
debug_agent 已启用 已停用 已停用
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 Global Integration builders 下载。

构建时优化

Fuchsia 平台的常规 build 优化标志在所有 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 变种在基准测试和测试期间被大量使用,也会对性能产生重大影响。

userdebug build 和 user build 之间的性能差异非常小。在对性能进行基准测试时,请优先使用 userdebug build,而不是 eng build。此方法存在缺点,详见下文的缺点部分。

安全注意事项

在设计 Fuchsia build 类型时,我们非常注重安全影响。我们在整个过程中都采用以下方法,为所有用户强制执行最高级别的安全保障:

  • 利用经过验证的执行,从启动开始建立完整的经过验证的信任链,并使用单独的签名密钥进行加密签名。

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

  • 仅包含最终用户 build 所需的软件包和组件。

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

隐私注意事项

在设计 Fuchsia build 类型时,我们也非常重视隐私保护注意事项。最终用户 build 中的所有日志都会经过清理以去除个人身份信息,并且必须征得用户同意才能上传崩溃、日志和指标。

文档

我们将在 Fuchsia > 概念 > 构建系统中进一步记录 build 类型,以便为 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 包含特定变种的软件包、不同的系统更新配置,并且未启用调试标志,因此非常适合运行端到端测试。但由于安全限制,无法在官方 userdebug build 中运行 SL4F

作为替代方案,独立系统汇编提供了修改已组装映像的功能,并且可用于组装允许访问测试框架且限制较少的本地 userdebug build。

未来,我们应采用更可扩缩的方法,以便在不同的产品配置中应用 enguserdebuguser build 类型配置文件。这样可以避免出现线性扩缩问题,即新产品需要多个产品配置来适应 build 类型。

另请注意,当前的实现会混合产品和平台,这并不是 Fuchsia 平台的长期目标。如前所述,建议您日后考虑采用更灵活的设计。

在先技术和参考文档

Android 操作系统:

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