| RFC-0188:组件 ABI 兼容性 | |
|---|---|
| 状态 | 已接受 |
| 区域 |
|
| 说明 | 检测组件目标 ABI 修订版本,并检查其与平台的兼容性。 |
| 问题 | |
| Gerrit 更改 | |
| 作者 | |
| 审核人 | |
| 提交日期(年-月-日) | 2022-06-27 |
| 审核日期(年-月-日) | 2022-09-31 |
摘要
本文档介绍了组件框架如何在与组件交互之前检测组件的目标 ABI 修订版本,并检查该版本是否与 Fuchsia 平台兼容。
设计初衷
随着应用和 Fuchsia 系统接口的发展,越来越需要规范组件与平台之间的 ABI 兼容性。
组件是根据平台 ABI 的一组行为预期构建的,如果不通过 ABI 修订版强制执行明确的 ABI 合约,这种预期就会成为平台开发的限制。有时,组件的构建目标 ABI 修订版本不再受平台支持。
组件框架可以防止执行以不受支持的 ABI 修订版本为目标的组件,同样也可以保证平台在组件运行时支持组件的目标 ABI。此 RFC 概述了组件框架将如何强制执行组件与 Fuchsia 平台之间的此 ABI 合约。
利益相关方
辅导员:
- leannogasawara@google.com
审核者:
- abarth@google.com
- etryzelaar@google.com
- geb@google.com
- jsankey@google.com
已咨询:
- adamperry@google.com
- jmatt@google.com
- lukenicholson@google.com
- richkadel@google.com
- wittrock@google.com
- yeg@google.com
共同化:
此 RFC 的设计文档已通过组件框架团队的设计审核。
什么是组件 ABI 兼容性?
ABI 兼容性是指 Fuchsia 系统接口向组件提供的行为预期协议。RFC-0002 详细介绍了 ABI 修订的含义以及平台如何支持这些修订。
RFC-0002 详细介绍了 Fuchsia 平台如何支持不断发展的 ABI 修订版本集:添加的每个 ABI 修订版本都会对 Fuchsia 系统接口造成向后不兼容的更改,当平台不再支持旧 ABI 修订版本的行为保证时,这些旧版本会从该集中移除。 如果组件的目标 ABI 修订版本包含在此不断发展的集合中,则该组件被视为与平台兼容。
此 RFC 描述了组件与平台之间的 ABI 兼容性。组件之间行为兼容性方面的总体保证(尤其是当它们使用不同但受支持的 ABI 修订版本构建时)不在本 RFC 的范围内,并且可能是 RFC-0002 中建议的未来工作的一部分,例如根据 ABI 修订版本引入功能路由。
条款
该设计区分了打包组件的组件解析过程中的多个参与者。以下术语将用于指代具有指定角色的参与者:
| 执行者 | 角色 |
|---|---|
| 解决操作 | 在组件管理器中执行组件解析工作流的操作。 |
| 解析器-客户端 | Component Manager 中的一个客户端实体,用于将 FIDL 请求代理到组件解析器以解析组件。 |
| 组件解析器 | 用于提供 fuchsia.component.resolution.Resolver FIDL 协议以解析组件的组件。注意:此 actor 不适用于内置解析器。 |
| Package Resolver | 用于提供 fuchsia.pkg.PackageResolver FIDL 协议以解析软件包的组件。 |
NOTE
解析操作和解析器客户端都是 Component Manager 的一部分,但在此设计中扮演着不同的角色。
一个重要区别是,解析操作无法区分打包的组件和未打包的组件。ABI 修订版本必须从其数据源(在封装组件和非封装组件之间有所不同)解码,然后才能到达解析操作。
另一方面,目前为每个组件解析器实现了一个解析器客户端,该客户端执行特定于其解析的组件类型的职责。
设计
当前状态
本文档围绕以下规定进行设计:封装组件的目标 ABI 修订版本取自其软件包目标 ABI 修订版本来源,如 RFC-0135 中所定义。
此设计提供了一种在当前打包组件的 ABI 修订版状态下满足要求的方法,而无需假设未来组件的目标 ABI 修订版将如何表示以及开发时间范围。
有关如何为非封装组件支持 ABI 修订版本的问题,请参阅 ABI 修订版本和非封装组件部分。
概览
此 RFC 建议组件解析工作流包括以下步骤:从组件的软件包中读取并解码组件的目标 ABI 修订版本;通过 FIDL 传递该值;进行检查以确定 ABI 修订版本是否与平台兼容。
图 1:支持 ABI 的 ABI 组件解析工作流程
1. 组件解析器打开并读取软件包 ABI 修订版本文件
封装组件的目标 ABI 修订版本目前与其软件包目标 ABI 修订版本相同。ABI 修订版值存储在软件包的 meta.far 中的某个文件中。
虽然组件的目标 ABI 是以这种方式定义的,但组件解析器可以使用软件包解析器返回的目录代理读取文件。组件解析器直接读取该文件的理由是,最大限度地减少从软件包目标 ABI 设置组件目标 ABI 的影响;缺点部分讨论了此行为的特定缺点。
如果该文件存在,组件解析器必须读取并解码 ABI 修订版本,并将该值包含在返回给解析器客户端的 FIDL 组件表示中。如果该文件不存在,则不包含相应值。 因此,组件解析器会将 ABI 存在性强制执行推迟到组件管理器。
2. 为 fuchsia.component.resolution.Component 引入 ABI 修订版本字段
在组件 FIDL 表示法中,引入了一个单独的字段来表示组件的目标 ABI 修订版本,其中 AbiRevision 是 uint64 值的别名:
sdk/fidl/fuchsia.component.resolution/component.fidl:
type Component = resource table {
...
abi_revision AbiRevision;
}
...
技术债务部分将讨论,如果组件的目标 ABI 修订版本包含在 FIDL 中已表示的数据源(例如组件清单)中,此字段将如何变得冗余。
3. 在组件管理器中检查 ABI 修订版本是否存在以及是否兼容
解析器客户端将具有可选 ABI 修订字段的 FIDL fuchsia.component.resolution.Component 类型转换为 Component Manager 表示形式,以交给解析操作。
验证已解析组件的元信息时,应检查 ABI 修订版本是否存在以及是否与 Fuchsia 平台兼容。
解析操作必须使用一个库,该库公开了一个 API 来检查给定的 ABI 值是否属于平台支持的 ABI 值集。这将确定解析的组件的目标 ABI 修订版本是否与平台兼容。
组件管理器的配置标志可能会指示解析操作针对缺少的目标 ABI 修订版本生成警告,而不是错误,这将用于在实现策略中实现向后兼容性。同样,引入单独的配置标志以允许不兼容的组件 ABI 修订版本可能有助于在没有 ABI 兼容性监管的情况下针对不同的 build 测试组件。
为什么要在组件解析中进行 ABI 兼容性检查?
组件管理器的调用方会解析组件网址,以便与构建的组件或其功能进行交互。将 ABI 兼容性集成到组件解析流程中可确保组件以预期的方式与平台交互。
重新解析组件时,ABI 修订版本应属于已更新的组件数据。与其他组件元数据类似,在明确更新组件之前,ABI 修订版本不应发生变化。
其他设计注意事项
处理封装组件中缺少或不兼容的目标 ABI 修订版本
如果封装的组件需要提供目标 ABI 修订版本,则可能会在以下任一时间点出现错误并缩短组件解析时间:
- 如果 ABI 修订版本文件存在,组件解析器无法解码 ABI 修订版本值。
- 解析操作无法将 FIDL 值解码为 ABI 修订版本数据类型。
- 解析操作发现 ABI 修订版本缺失或与平台不兼容,并且 Component Manager 配置标志将此情况标记为错误。
最终用户或组件管理器是否触发组件解析取决于具体情况,错误是可直接返回给用户,还是只能记录以供发现,也取决于具体情况。人体工程学部分详细介绍了如何向用户显示警告和错误。
ABI 修订版本和非封装组件
此 RFC 未定义非封装组件(例如 Web 组件)如何表示 ABI 修订版本。此类组件的 ABI 兼容性含义将另行考虑,不会影响此设计的初始推出,该设计允许 ABI 修订为可选。
与子软件包的 ABI 兼容性
如 RFC-0154 所述,顶级软件包和子级子软件包应包含 ABI 修订版本。就此 RFC 的问题而言,无需对子封装组件进行特殊处理:当每个子封装组件得到解析时,它将受到与图 1 描述的相同的组件解析工作流程的约束。不过,如果某个子封装组件的目标 ABI 修订版本与顶级封装组件不同,并且平台放弃了对该子封装组件的 ABI 修订版本的支持,那么该子封装组件将无法进行组件解析。这会与子软件包通常提供的可用性保证(如 RFC-0154 中所述)相冲突。
ABI 兼容性和内置解析器
启动组件由内置于组件管理器的启动组件解析器解析。RFC-0167 引入了启动组件的封装:启动组件解析器从以类似于非启动组件软件包的方式格式化的 bootfs 软件包中解析组件。
检索和评估启动组件的 ABI 修订版本遵循与图 1 类似的流程设计,只是启动组件和启动软件包解析器不是作为外部组件实现的。
具体而言,启动组件解析器所需的更改如下:
- 启动组件解析器会打开并读取在 bootfs 软件包的
meta.far中找到的 ABI 修订版本文件。 - 启动组件解析器会将 ABI 修订版本值纳入返回给解析操作处理程序的已解析组件表示形式中。
实现
此设计分两个阶段实现:
- 组件管理器使组件目标 ABI 修订版本成为可选。
- 组件管理器使组件目标 ABI 修订成为必需项。
- 如果找不到 ABI 修订版本文件,打包的组件解析器会出错。
- 表示非封装组件的 ABI 修订版本。
组件管理器的配置标志可用于强制执行 ABI 要求并启用阶段 2。
可以通过 ffx component 等组件发现工具检查组件的目标 ABI 修订版本。
性能
对性能没有显著影响。
工效学设计
Component Manager 负责显示因缺少或不兼容的目标 ABI 修订版本而导致的组件解析警告或错误。应记录所有组件解析警告和错误。
在某些场景(例如使用 ffx component)中,最终用户可能会发起 FIDL 请求,该请求将解析组件,并在失败时返回描述性 FIDL 错误响应。
在其他情况下,无法向用户提供直接反馈。例如,从提供功能的源组件到目标组件的路由路径上的组件解析失败可能会中断功能路由。这会关闭具有墓志铭的 fuchsia.io 功能渠道,要求用户读取日志或可能使用诊断工具来获取渠道关闭的原因。
向后兼容性
两阶段实现策略可确保组件解析继续适用于尚未指定目标 ABI 修订版本的组件软件包。
为 FIDL ABI 修订版本字段生成的绑定固有地使该字段成员成为可选字段,并允许我们推出实现,而不会破坏尚未指定 ABI 修订版本的组件。
向后兼容性行为由配置标志控制,该标志指示 Component Manager 在组件的目标 ABI 修订版本缺失或与平台不兼容时返回错误。
安全注意事项
没有已知的安全问题。
隐私注意事项
没有已知的隐私权问题。
测试
现有测试框架将用于测试以下场景:
- 针对组件解析器中读取和解码 ABI 修订版文件的单元测试。
- 用于根据配置设置检查 ABI 修订版本是否存在/值是否正确的单元测试。
- 组件解析器与解析器客户端接口之间的集成测试。
文档
https://fuchsia.dev 上的文档将介绍:
- 组件目标 ABI 修订版的概念。
- 如何定义组件目标 ABI 修订版本。
- 如果发现组件的目标 ABI 修订版本与平台不兼容,会发生什么情况。
此外,还会根据需要编写源代码内文档。
缺点
组件解析器读取软件包元数据以检索组件的目标 ABI 修订版本
组件的目标 ABI 修订版本派生自其软件包目标 ABI 修订版本,存储在 meta.far 中,其中存储了软件包元数据。或者,可以在组件元数据中定义组件目标 ABI 修订版本,这样组件解析器就不会与软件包元数据进行交互。
此外,由于软件包中的所有组件都从同一个单值派生出其目标 ABI 修订版本,因此这限制了软件包中的组件彼此独立演变的方式。对于软件包中具有不同更新周期的组件的单独维护者来说,这可能会带来问题。另一方面,子软件包提供了一种对依赖项中的组件目标 ABI 修订版本进行分组和区分的方法。
此点面临一个决定:为什么将组件的目标 ABI 修订版本设置为其软件包目标 ABI 修订版本。此 RFC 的一个未知之处在于,未来是否会更改组件目标 ABI 修订版本的定义方式,以及何时会进行更改。不过,我们可能承认,与需要更高程度的承诺和协调工作的组件级目标 ABI 修订相比,定义和引入软件包级目标 ABI 修订更容易。此外,当前策略提供了一个 MVP,使我们能够开始使用组件目标 ABI 修订版本,而无需等待未来在软件包或组件元数据中如何定义它们。
替代方案
在软件包解析器中检查 ABI 兼容性
另一种设计方案可以承认 ABI 修订版本是在软件包级别定义的,并且在组件解析过程中,ABI 修订版本文件的第一个发现点是在软件包解析时。另一种相关方法是,在组件元数据中定义 ABI 之前,推迟引入组件级目标 ABI 修订版本。
优点:
- 解决了有关如何定义 ABI 修订版本的直接问题。
缺点:
- 不适用于无软件包组件。
- 影响在 Component Manager 中使用组件目标 ABI 修订版本的未来工作计划,例如根据 ABI 修订版本调节功能路由。
- 将 ABI 控制移至组件管理器外部的外部组件。
- 添加一种用户可控制的方式来停用 ABI 强制执行以进行调试或测试,不像向组件管理器添加配置标志那样简单。
- 对于已解决并下载但未使用的不兼容 ABI 修订版的软件包,可能会过于严格,或者需要特殊处理。例如,解析和提取包含当前运行平台尚不支持的 ABI 修订版本的更新软件包应仍能成功完成。
在组件解析器中检查 ABI 兼容性
除了打开和解析 ABI 修订版本文件之外,组件解析器还可以检查 ABI 与系统的兼容性。
优点:
- 如果组件的目标 ABI 不受支持,则防止将组件返回给组件管理器。
缺点:
- 将 ABI 控制移至组件管理器外部的外部组件。
- 影响在组件管理器中使用 ABI 修订版本的未来工作计划,例如根据 ABI 修订版本引入功能路由。
- 添加一种用户可控制的方式来停用 ABI 强制执行以进行调试或测试,不像向组件管理器添加配置标志那样简单。
组件管理器在进行特定组件互动之前检查目标 ABI 兼容性
在对(已解析的)组件执行特定操作(例如启动组件或访问其某项功能)之前,组件管理器可以检查该组件的目标 ABI 修订版本是否受支持。
优点:
- 更具体地说明了何时应检查 ABI 修订版本。
- 可能更好地控制错误处理。
缺点:
- 忽略了组件的目标 ABI 是构成其接口的声明的一部分,该接口在组件解析期间经过验证。
- 维护成本高,需要人工了解应执行 ABI 检查的上下文。
- 由于缺少 ABI 兼容性检查,因此容易因组件而引入破坏性、意外或难以调试的行为。
从解析器客户端打开并读取软件包 ABI 修订文件
我们可能希望尽量减少此临时设计对组件目标 ABI 的影响,并实施一种最容易撤消的解决方案,方法是避免向组件解析器和 FIDL 引入新行为。
优点:
- 避免向
fuchsia.component.resolution.Component引入新的 FIDL 字段,如果组件目标 ABI 修订版本包含在 FIDL 中也表示的数据源(例如组件清单)中,则可能会成为技术债务。技术债务部分更详细地介绍了此方案。
缺点:
- 直接从软件包读取文件会违反解析器客户端的抽象边界。这必须在解析器客户端中执行,而不是在解析操作中执行,因为解析操作无法区分打包组件和非打包组件。
- 目前尚不清楚此临时修复方案会持续多长时间。
未知
未来是否会定义组件特定的目标 ABI 修订版本,以及定义方式和时间
每个组件的 ABI 修订版本何时确定尚不清楚,因此同一软件包中的组件可能具有不同的目标 ABI 修订版本。此外,我们也没有承诺未来将使用哪个数据源来存储组件目标 ABI 修订版本;ABI 是否会包含在组件清单中也是一个悬而未决的问题。
技术债
此设计并未假设未来如何定义组件目标 ABI 修订版本,因此可能会引入技术债务。
如果组件目标 ABI 修订版本包含在也具有 FIDL 表示形式(例如组件清单)的来源中,则 fuchsia.component.resolution.Component 的 ABI 修订版本字段成员将变得冗余,应予以移除。此技术债务将仅限于 fuchsia.component.resolution.Resolver 协议和使用该协议的组件。
在先技术和参考资料
此设计中未考虑。