RFC-0241:SDK 接口中的显式平台 / 外部拆分

RFC-0241:SDK 接口中的显式平台 / 外部拆分
状态已接受
领域
  • FIDL
说明

更精确地表达 Fuchsia 接口的哪些部分可在 Fuchsia 平台之外实现。

问题
Gerrit 更改
  • 982353
作者
审核人
提交日期(年-月-日)2024-01-29
审核日期(年-月-日)2024-04-09

摘要

Fuchsia IDK 不指定外部组件是否应为其定义的各种 FIDL 协议实现客户端或服务器。因此,很难正确评估对 Fuchsia API 的更改对向后兼容性的影响。此 RFC 提出了一种在 FIDL 中以人类和机器可读的方式表示该信息的方法。这为改善基于 Fuchsia 的产品的正确性和稳定性创造了机会。

设计初衷

大部分 Fuchsia 系统接口FIDL 中都表示为一组协议以及通过这些协议交换的类型。协议与客户端和服务器端不对称,但作为 SDK/IDK 的一部分提供的 FIDL 声明没有指定由 Fuchsia 平台提供的与产品提供的外部组件之间的接口是适用于服务器端、客户端还是这些协议的两端。

由于缺乏精确性,因此在无需了解 Fuchsia 平台实现(通常是外部组件)的情况下,可以安全地对 Fuchsia 系统接口进行更改种类。在实践中,大多数协议要么仅包含服务器,要么仅包含在 Fuchsia Platform 内实现的客户端,但此信息的表示方式不能可由工具检查或可由最终开发者发现。

例如,如果系统接口的某个类型包含 string:100(一个使用 UTF-8 编码的字符串,其长度最多为 100 个字节),而后来我们发现我们需要支持更长的字符串。如果该类型仅从外部组件发送到平台组件(在协议方法请求中),则可以安全地增加长度限制,因为组件解码包含该字符串的消息将始终至少与编码该字符串的组件一样新。如果该类型可能从平台组件发送到外部组件,则无法安全地增加长度,因为针对平台中更高 API 级别构建的组件可能会无意中向外部组件发送格式错误的消息。

利益相关方

谁能决定此 RFC 是否被接受?

教员

由 FEC 指定的人员,负责通过 RFC 流程照管此 RFC。

审核者

  • abarth@google.com
  • chaselatta@google.com
  • hjfreyer@google.com

咨询人员

  • aaronwood@google.com
  • awolter@google.com
  • crjohns@google.com
  • mkember@google.com
  • pesk@google.com
  • surajmalhotra@google.com
  • wittrock@google.com

社交

向负责平台版本控制的工作人员分发了一份简明介绍其问题和方案的简明介绍。

要求

本文档中的关键字“必须”“不得”“必需”“会”“不会”“应”“不应”“建议”“可以”和“可选”应按 IETF RFC 2119 中的描述进行解释。

我们必须能够说明哪些系统接口协议可以在平台或外部组件中实现其客户端和/或服务器。这些信息必须以方便评估平台变更兼容性的工具访问的方式表示。

这些信息应可供在软件组装时运行的工具使用,也可在运行时供组件框架使用。这些信息应通过生成的 API 文档和构建时检查向最终开发者公开。

为了使这些信息有助于评估 Fuchsia 平台与基于该平台构建的组件之间的兼容性,外部组件必须根据该平台支持的稳定 API 级别构建。

设计

分析

平台 ABI 整体的兼容性可细分为考虑外部组件与平台组件之间交换的各个类型的兼容性(在基于通道的协议中以及序列化和带外交换中)。

组件之间的所有 FIDL 数据交换都基于以下某个条件:

  • 通过组件框架协议功能交换的 FIDL 协议。它们使用 @discoverable 属性进行标记。
  • 通过非 FIDL 方式交换的 FIDL 协议,例如进程参数
  • 在文件(例如组件清单)或定制 IPC 传输中序列化和交换的 FIDL 类型。

给定整个 Fuchsia 系统接口 FIDL 的视图后,我们可以针对每个根收集可能从客户端发送到服务器以及从服务器发送到客户端的一组类型。

协议

如果我们知道,对于每个“根”协议,无论其客户端和服务器是否可在外部组件或平台组件中实现,我们都可以收集可能从外部组件发送到平台组件、从平台组件发送到外部组件、在平台组件之间以及外部组件之间发送到平台组件的一组类型。

对于协议:

@discoverable
protocol {
    M(Req) -> (Resp);
}

鉴于我们允许实现客户端和服务器的位置,我们可以看到请求 (Req) 与响应 (Resp) 中的类型可能在外部组件 (E) 和平台组件 (P) 之间流动:

客户端 服务器 E 到 P P 到 E P 到 P E 到 E
E E 请求、销售代表
E P 请求 响应
E P、E 请求 响应 请求、销售代表
P E 响应 请求
P P、E 响应 请求 请求、销售代表
P、E E 响应 请求 请求、销售代表
P、E P 请求 响应 请求、销售代表
P、E P、E 请求、销售代表 请求、销售代表 请求、销售代表 请求、销售代表

平台代码一定会读出由外部代码读出的协议版本的超集,因此我们可以就是否可收紧或放宽类型限制做出如下陈述:

发件人 接收器 约束条件
外部 平台 没法收紧
平台 外部 无法放松
外部 外部 无法更改

因此,我们需要能够限制允许实现客户端和服务器的位置。

几乎所有作为 root 的协议都通过组件框架功能进行交换。但这些都不是低阶和深奥的。它们在 fuchsia.posix.socket 中包含 fuchsia.io.Directory 和一些网络套接字控制通道协议。我们不应开发新方法来将这些协议标记为通信根,而是应该扩展 @discoverable 的含义以纳入这些协议。实际上,fuchsia.posix.socket 中有用于套接字控制协议名称的常量,这些常量会在标记为 @discoverable 后自动生成。

类型

目前,任何组件(外部或平台)代码都可以对原始字节中的任何非资源类型进行序列化或反序列化。为了让兼容性工具了解哪些 FIDL 类型不会在某些情况下进行序列化或反序列化,我们应该在常规 FIDL IPC 之外的组件之间明确标记传递类型。

语法

协议

将对可发现属性进行扩展,以指明可在哪里实现可发现协议。默认情况下,标记为 @discoverable 的协议可能具有由外部组件和平台组件实现的客户端和服务器。

serverclient 可选属性列出了可以实现此类端点的组件类型。默认情况下,这两个端点都可以由任何组件实现。

例如:

// All servers in the platform, all clients in external components.
@discoverable(client="external", server="platform")
protocol P {};

// All servers in external components, all clients in the platform.
@discoverable(client="platform", server="external")
protocol Q {};

// Only clients allowed in external components, both clients and servers allowed in the platform.
@discoverable(client="platform,external", server="platform")
protocol R {};

// Servers are only allowed in platform components. Clients are allowed anywhere.
// If both clients and servers are allowed that argument can (and should) be omitted.
@discoverable(server="platform")
protocol S {};

类型

我们将向 FIDL 添加新的 @serializable 属性,以标记哪些类型可以序列化并在 FIDL 协议之外的组件之间传递。

此属性仅适用于非 resource structtableunion

它有两个可选参数:readwrite。其中每个字段都接受以逗号分隔的 platformexternal 列表,指示平台组件或外部组件应读取或写入该类型。每个参数的默认值为 "platform,external",表示可以从此类组件读取和写入参数。

实现

FIDL 工具链

fidlc 将更新为接受 @discoverable 的这些参数和新属性 @serializable目前不会修改 FIDL 绑定生成器 (fidlgen_*)。

Fuchsia 系统接口

系统将更新 partnerpartner_internal 库中的所有可检测到的 FIDL 协议。大多数组件将被标记为 @discoverable(server="platform"),表示外部组件应仅实现客户端,但平台组件可以实现客户端和服务器。其中一些组件(如 fuchsia.io 中的许多组件)将被标记为 @discoverable(),表示任何组件都可以实现客户端和服务器。有少数组件(主要针对驱动程序)将被标记为 @discoverable(client="platform", server="external"),以表示外部组件应仅实现服务器,而平台组件应仅实现客户端。

经过一些实验和原型设计后,似乎没有什么直接的方法来计算每个协议所属的类别。组件图的运行时检查和 CML 分片的静态评估都不清楚。而我们会查看外部组件的清单,这些组件用于实现它们使用和提供的协议功能。

对于独立数据类型,我们将查找对各种语言绑定的显式序列化 API 的调用,并注释其中使用的类型。

兼容性工具

我们正在开发一种工具,用于评估不同版本的 Fuchsia 系统接口 FIDL IPC 部分的兼容性。这适用于 FIDL IR,并将整合可检测属性中的信息。有关此工具将实现的兼容性规则的完整说明将包含在另一个 RFC 中。

未来机遇

兼容性工具是对 FIDL 语法的这种增强的推动重点。不过,这些关于 Fuchsia 系统界面的更丰富信息在其他地方可能仍然有用。

FIDL 绑定

FIDL 绑定生成器可以了解其构建的绑定是否以平台组件或外部组件为目标,并调整它们生成的代码,以鼓励开发者仅在有兼容性保证的上下文中实现协议的客户端和服务器。

阻止任何不受支持的客户端或服务器只会适得其反,因为开发者需要在测试中伪造或模拟类似应用,但或许我们可以设置保护措施,以阻止在非测试环境中使用它们。

可以更新独立的序列化代码,以仅允许传入标记为 @serializable 的类型。

组件框架

在组件框架中,协议功能没有类型。它们通常以它们携带的 FIDL 协议命名,但这仅仅是一种惯例,也违反了这种惯例。用于推断组件与对等方通信所使用的协议的工具必须根据功能的名称,推断正在使用的协议。

如果组件框架向其模型中添加了协议类型,则这些工具会更简单、更可靠且更准确。

软件组装

软件组装通过配置、平台组件和外部组件生成 Fuchsia 系统映像。它可以利用有关哪些协议可能来自平台组件或外部协议的信息来拒绝组合违反这些规则的产品。这样可以确保产品所有者不会无意中构建能够保证 Fuchsia 不提供的兼容性保证的产品,并帮助平台开发者避免以他们不打算支持的方式公开功能。

安全性

了解跨外部/平台边界路由的协议功能的哪端可能有助于评估系统的安全属性。这可以临时完成,也可以集成到现有工具中。

性能

效果不会发生任何变化。

工效学设计

这就需要将系统中的某些假设明确地表达出来,这需要的前期工作多一些,但可以使系统更易于理解和使用。

向后兼容性

现有的 FIDL 库不会受到影响。不带参数的 @discoverable 仍为有效属性。

最初,我们不希望对可检测和可序列化的属性进行版本控制,因为它们是版本控制的输入,对源代码或运行时兼容性没有影响,并且需要广泛采用以了解其优势。如果我们更新 FIDL 绑定,以根据可检测到的参数进行更改,就必须考虑对其进行版本控制,因为更改这些绑定可能会破坏现有的源代码。

安全注意事项

未来可能有机会在这方面提高整体系统安全性。

隐私注意事项

测试

通过对我们承诺兼容的协议的哪一端进行明确编码,这样可以更轻松地确保我们对 Fuchsia 平台进行完整的兼容性测试

对于所有 fidlc 更改,我们将添加新的 fidlc 测试。

在我们组装时验证所有组件都遵循 FIDL 文件中表示的规则之前,我们无法确定我们在 SDK 中表示的外部/平台拆分是否与 Fuchsia 产品中的实际情况一致。

文档

以下 FIDL 文档需要更新:

缺点、替代方案和问题

我们可以保持现状,但这样会大大限制我们可以支持的更改类型,或者限制我们的工具在检查更改安全性方面的信心。

我们可以在 API 工具中表示除 FIDL 语言之外的外部 / 平台拆分(就像处理 SDK 类别时所做的一样),但由于这种分类发生在声明级别,不利于人体工程学,因而更有可能过时。

我们可以提出一个在兼容性方面具有相同但不支持协议功能的等效属性,而不是使用 @discoverable 来标记像 fuchsia.io.Directory 这样的协议。这似乎是必要的更加复杂。

我们无需添加 @serializable 来标记带外交换的类型,而是只需编写占位符 FIDL protocol,这些 FIDL protocol 使用这些类型化且带有适当属性标记为 @discoverable,以暗示可以在哪些位置读取和写入这些类型。这意味着,他们制定的协议永远都不要读出来,而且通常很难搞得好混乱。

我们使用了 @discoverable(platform="server", external="client") 一段时间,而不是像 @discoverable(server="platform", client="external") 这样的语法,但当前的语法更容易理解。

现有艺术和参考资料

不适用