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

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

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

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

摘要

Fuchsia IDK 未指定外部组件应为其定义的各种 FIDL 协议实现客户端还是服务器。这使得很难正确评估对 Fuchsia API 所做的更改对向后兼容性的影响。此 RFC 提出了一种在 FIDL 中以人和机器都能读懂的方式表达此类信息的方法。这为改进基于 Fuchsia 的产品的正确性和稳定性提供了机会。

设计初衷

Fuchsia 系统接口的大部分内容都以 FIDL 的形式表示为一系列协议以及通过这些协议交换的类型。协议具有客户端和服务器端,但作为 SDK/IDK 的一部分提供的 FIDL 声明并未指定 Fuchsia 平台向产品提供的外部组件呈现的接口是用于这些协议的服务器端、客户端还是两端。

这种不精确性会严重限制在不了解 Fuchsia 平台实现(通常还包括外部组件)的情况下,可以安全地对 Fuchsia 系统接口进行哪些更改。实际上,大多数协议在 Fuchsia 平台中都只会实现服务器或客户端,但这些信息的表达方式无法被工具检查或被最终开发者发现。

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

利益相关方

哪些人对此 RFC 的接受与否有利益相关?

教员

由 FEC 任命的负责引导此 RFC 完成 RFC 流程的人员。

Reviewers:

  • 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

社交

向负责平台版本控制的人员分发了一份 1 页的文件,其中介绍了问题和方案。

要求

本文档中的关键字“必须”“不得”“必需”“会”“不会”“应”“不应”“建议”“可以”和“可选”将按 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 请求 Resp
E P、E 请求 Resp 请求、响应
P E Resp 请求
P P、E Resp 请求 请求、响应
P、E E Resp 请求 请求、响应
P、E P 请求 Resp 请求、响应
P、E P、E 请求、响应 请求、响应 请求、响应 请求、响应

平台代码保证支持外部代码支持的协议版本的超集,因此我们可以就类型约束条件是否可以收紧或放宽做出以下说明:

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

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

几乎所有根协议都是通过组件框架功能交换的。而非低级别和深奥的。其中包括 fuchsia.io.Directoryfuchsia.posix.socket 中的几个网络套接字控制信道协议。我们不应发明新的方法来将这些协议标记为通信根,而应扩展 @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 协议之外的组件之间序列化和传递。

此属性仅适用于非 resourcestructtableunion

它有两个可选参数: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 类别所做的那样),但由于这种分类是在声明级别进行的,因此人体工学效果较差,并且更有可能过时。

我们可以设计一个等效的属性,用于标记 fuchsia.io.Directory 等协议,该属性在兼容性方面具有相同的含义,但不支持协议功能。@discoverable这似乎是必要的额外复杂性。

我们可以直接编写使用这些类型且使用适当属性标记为 @discoverable 的占位符 FIDL protocol,而不是添加 @serializable 来标记需要在非信道内交换的类型,以暗示这些类型可在何处读取和写入。这意味着,协议从来就不是用来朗读的,通常很难正确使用,而且很杂乱。

我们曾短暂地使用 @discoverable(platform="server", external="client")(而非 @discoverable(server="platform", client="external") 等语法),但目前的语法更易于理解。

在先技术和参考文档

不适用