RFC-0138:处理未知交互

RFC-0138:处理未知交互
状态已接受
领域
  • FIDL
说明

我们扩展了 FIDL 语义,以允许对等方处理未知交互。

Gerrit 更改
作者
审核人
提交日期(年-月-日)2021-05-25
审核日期(年-月-日)2021-10-27

摘要

我们扩展了 FIDL 语义,以允许对等方处理未知交互,即 收到未知事件或收到未知方法调用。为此:

  • 我们在 FIDL 中引入了灵活交互严格交互 语言。即使未知,灵活互动也可以优雅地 由对等方处理严格的交互会导致突然终止。

  • 我们介绍了三种协议操作模式。封闭协议是指 一种绝不允许未知交互。相反,开放协议 就是允许任意类型的未知互动。最后, ajar 协议仅支持单向未知交互。

FIDL 对进化的支持概览

在深入研究此提案的具体细节之前,最好先了解一下 FIDL 如何致力于解决进化方面的担忧。

此问题有两个方面:源兼容性 (API) 和二进制文件兼容性 (ABI) 中所定义。

API 兼容性旨在保证 在更改之前生成的代码仍然可以在 更改。例如,可以合理地预期添加新声明 添加到 FIDL 库(例如定义新的 type MyNewTable = table {};)不会 会导致使用此库的现有代码无法编译。

您可以通过三种方法来解决源代码兼容性问题:

  1. 让尽可能多的更改来源兼容(例如 RFC-0057: Default 无标识名);
  2. 提供明确的保证(例如 RFC-0024: Mandatory source) 兼容性);
  3. 提供版本控制信息(例如 RFC-0083: FIDL versioning)。

ABI 兼容性旨在确保所构建的程序的互操作性 不同版本的库进行对比例如,两个程序可以有 对表架构有不同的理解,但又能够成功地 进行通信。

实现 ABI 兼容性可分为三个部分:

  1. 静态兼容性旨在实现数据的互操作性 级别,即何时可以使用同一表的不同架构的两个对等方 能否互操作?
  2. 动态兼容性假设所有数据类型都兼容,并着重分析 在同行拥有不同版本的网络环境时实现互操作性 协议(例如不同的方法);
  3. 最后,在有些情况下,采用不同的协议 而解决方案则是了解 然后调整通信(协议是 语音)。

动态兼容性尤其适合“本地灵活性”的情况为 例如,对一个基本保持不变的模型进行细微添加, 操作。在其他情况下,可以说 fuchsia.io1 相对于 fuchsia.io2,后者是一个域 需要进行模型转换。存在“全球灵活性”所需的解决方案, 都属于协议谈判类别。

我们在这篇 RFC(严格而灵活)中具体讨论的机制 可改善动态兼容性的现状 (2)。

术语

关于架构设计模型 协议

两个对等体之间的通信称为“互动”。互动开始 请求,并且可选择性地要求提供响应

请求和响应都是事务性消息, 以标头(“交易标头”)表示,可以选择后跟 载荷1

交互为定向,我们将两个对等命名为 clientserver客户端到服务器的互动始于来自 收到响应,如果反向 。与此类似,我们讨论的是服务器到客户端的互动

我们通常使用“即发即弃”的术语,或用“单向”表示无响应通话双向术语, 需要响应的互动(当前模型中始终由客户端发起)。 当服务器是无响应交互的发起方时, 通常称为事件2

协议一组互动。我们将“会话”定义为 使用 即客户端与服务器之间的一系列交互。

应用错误是指遵循错误语法的错误。答 “传输错误”是指由于内核错误(例如 写入已关闭的频道)或 FIDL 中发生的错误。

设计初衷

Fuchsia 的核心原则是 可更新:软件包旨在 它们彼此独立进行更新即使是驱动程序,也要具备二进制稳定性, 这样设备就可以无缝更新到较新版本的 Fuchsia, 保留现有的驱动程序。FIDL 在实现可更新性方面,并且 它最初用来定义应用二进制文件 接口 (ABI)、 从而为向前和向后兼容性奠定了坚实的基础。

具体而言,我们希望能有两位理解方式略有不同的同行 安全互操作性。更棒的是 我们需要有强有力的静态保证,即两个对等网络 “compatible”

为了保证编码的灵活性和 和解码 FIDL 类型(我们称之为静态兼容性)。我们推出了 table 布局union 布局,选择了显式 union 序数,引入了strictflexible布局修饰符、 引入了 protocol 序哈希减少有序的protocol碰撞概率 哈希技术,并推动了事务性 API 消息标头格式

现在我们转向动态灵活性和保证,我们称之为动态 兼容性。假设两个对等体在静态时兼容,即所有类型 它们用于交互时是否兼容,而动态兼容性则是其 这两个对等网络之间成功互操作, 另一个对等方由于意外交互而取消通信。

利益相关方

  • 教员:jamesr@google.com。
  • 审核者: <ph type="x-smartling-placeholder">
      </ph>
    • abarth@google.com (FEC)
    • bprosnitz@google.com (FIDL)
    • ianloic@google.com (FIDL)
    • yifeit@google.com (FIDL)
  • 已咨询: <ph type="x-smartling-placeholder">
      </ph>
    • jamesr@google.com
    • jeremymanson@google.com
    • jsankey@google.com
    • tombergan@google.com
  • 社交化:RFC 草稿已与 FIDL 团队分享,并与 FIDL 团队讨论 我是 Fuchsia 团队的一员。该项目在工程委员会广泛分享 讨论邮寄名单 (eng-council-discuss@fuchsia.dev)。

设计

我们介绍了灵活互动严格 互动。简言之,即使未知,灵活互动也可以 由对等方妥善处理。相反,如果接收对等方未知, 严格交互是指会导致对等方突然终止 会话。我们通过互动的严格程度来判断互动是否 是灵活或严格的互动。请参阅“灵活”和“严格”语义 互动

如果没有保护措施,灵活的互动可能会被无意中用于 侵犯隐私权的内容:

  • 以一个旨在不断发展的渲染引擎为例。一种新的 版本添加了 flexible SetAlphaBlending(...); 与 希望以旧版渲染器为目标的新客户 设置会被忽略(但大部分呈现功能仍可正常运行)。现在,如果 这种新方法是采用特殊的个人身份信息呈现模式StartPIIRendering(); 务必要让旧版渲染程序停止处理 请忽略这一点,因此使用 strict 互动比较合适。
  • 另一个例子是恶意对等方尝试反思发现 通过发送各种消息来了解哪些 。通常,反射功能会带来额外的性能 并为隐私保护问题打开大门(您可能会接触到 )。根据原则,FIDL 选择禁止 或需要明确选择启用。

因此,我们还引入了三种模式, 运行:

  • 封闭协议是指不允许灵活互动的协议 在预期之内,接收灵活互动是异常行为。
  • 开放协议是指允许任何灵活互动(不管是 单向或双向)。此类协议提供最大的灵活性。
  • ajar 协议允许灵活的单向交互 (即发即弃通话和事件),但灵活的双向交互 允许(如果对等方不知道这一点,则无法进行方法调用) 方法)。

如需了解详情,请参阅协议的语义

严格和灵活的交互的语义

严格交互的语义非常简单: 未知请求,即接收方不知道其序号的请求,对等方 突然终止会话(通过关闭通道)。

灵活互动的目标是让收件人能够安心地处理 未知的互动。这会给设计提供一些指导信息。

灵活互动的发送者必须知道其请求可能会被忽略 (因为收件人无法识别)。

接收方必须能够知道该请求是灵活的(相对于 严格执行),并采取相应的措施。

由于双向互动需要接收者回复发送者,因此它 要求未知请求的接收方能够构建 响应缺少任何其他详细信息。收件人必须转达给发件人 请求无法理解为了满足此要求,响应 灵活的双向互动方式就是结果并集(请参阅 详细信息)。

它遵循以下语义:对于单向交互, 发送者无法判断接收者是否知晓其请求。 在使用灵活的单向交互时,FIDL 作者应格外小心 整体协议的语义。

值得注意的是,单向交互在一定程度上 是“尽力而为”, 发送方无法判断对等方是否收到了互动的感觉。 不过,通道提供排序保证, 是确定的并且是已知的严格的单向交互使其 可以确保当且仅当 理解了互动。例如,日志记录协议可能具有 StartPii()StopPii() 严格互动,以确保从未有过类似应用 请忽略这些内容。

为进一步讨论选择 Responsible AI 时要权衡哪些因素, 严格且灵活的互动方式,另请参阅:

开放、封闭和半开式协议的语义

closed 协议的语义具有限制性,只有严格的交互, 没有灵活的互动方式对于 closed 协议而言,这是编译时错误, 有任何flexible互动。

ajar 协议的语义允许严格的交互, 灵活互动对于 ajar 协议而言,这是编译时错误, 进行任意flexible双向互动。

open 协议没有任何严格和灵活的限制, 它允许双向交互

为进一步讨论选择 Responsible AI 时要权衡哪些因素, 封闭式、ajar 式或开放式协议的设计方案,另请参阅:

更改语言

我们引入了 strictflexible 修饰符,用于将互动标记为 严格或灵活:


protocol Example {
    strict Shutdown();
    flexible Update(value int32) -> () error UpdateError;
    flexible -> OnShutdown(...);
};

默认情况下,互动非常灵活。

在风格指南方面,建议始终明确指明严格程度 即应为每次互动设置此值。3

我们引入了 closedajaropen 修饰符来标记协议 闭合、半开(部分开)或开放:


closed protocol OnlyStrictInteractions { ...
ajar protocol StrictAndOneWayFlexibleInteractions { ...
open protocol AnyInteractions { ...

在封闭协议中,不能定义灵活的交互。关闭 协议只能编写其他封闭协议。

在 ajar 协议中,无法定义双向灵活交互。一个 ajar 协议只能编写封闭式或 ajar 协议。

(开放协议没有任何限制。)

默认情况下,协议处于开放状态。

此提案的上一个版本将 ajar 指定为默认值。不过, 在开放性修饰符的默认值 (ajar, ajar) 上, 与 2018 年 1 月 24 日之前的 在没有显式修饰符的情况下声明双向方法的情况。这意味着 包含双向方法的协议在 至少使用协议或方法请参见下文: 开放度以粗体显示,严格程度的默认值以 斜体。

可视化:网格,其中显示了打开/Ajar/关闭编译的哪些组合
替换为
严格/灵活。

为了解决此问题,我们将默认的开放性从 ajar 更改为打开, 允许协议在不使用修饰符的 协议或方法

在风格指南方面,建议始终明确指明 即应为每个协议设置此变量。[^default-debate]

线传输格式变更:事务性消息标头标记

我们修改了事务性消息, header 是:

  • 交易 ID (uint32)
  • 静态标志(array<uint8>:2,即 2 个字节)
  • 动态标志 (uint8)
  • 魔数 (uint8)
  • 序数 (uint64)

也就是说,标志字节拆分为两部分,静态标志两个字节,以及 dynamics 标记一个字节。

动态标志字节的结构如下所示:

  • 位 7,第一个 MSB“严格位”:严格方法 0,灵活方法 1。
  • 位 6 到 0,未使用,设为 0。

关于“动态标志”的使用的一些更多详细信息:

  1. 我们在第三版事务消息中添加了标记 标头。这些标记旨在“暂时用于软 迁移”。例如,在从严格到可扩展的 联合迁移。不过,目前没有 就会需要使用这么多标志,因此我们可以更改 从仅用于临时使用 用作传输格式的一部分。

  2. 发送方必须使用严格程度位向接收方指明 strict 交互(在接收方不知道该交互的情况下) 互动在这种情况下,预期的语义是 突然终止。如果不这样严格,发件人之间的偏差 接收者可能会被忽略例如,Ajar(或 开放)协议,并添加了新的 strict StopSomethingImportant(); 协议 互动方式如果没有严格要求,接收方就不得不猜测 无论未知互动是严格还是灵活,选择灵活 。因此 在以下情况下,FIDL 作者将不得不依赖双向严格交互: 扩展协议

另请参阅在事务中放置严格位 标识符用于讨论 替代表示法以及互动模式 位表示未来的替代表示形式 所需的资源。

对传输格式的变更:结果并集

结果并集,目前有两个变体(序数为 1 表示成功) 响应的序数 2)扩展为有第三个变体, 序数 3,将带有一个新的枚举 fidl.TransportError,用于指示 “传输层”错误。

例如,此次互动:

open protocol AreYouHere {
    flexible Ping() -> (struct { pong Pong; }) error uint32;
};

具有响应载荷:

type result = union {
    1: response struct { pong Pong; };
    2: err uint32;
    3: transport_err fidl.TransportError;
};

具体而言,如果一个灵活的方法使用 error 语法,则系统会提供成功类型和 错误类型(分别为序数 1 和 2)。否则,如果 灵活的方法不使用 error 语法,即结果的错误变体 并集(序数 2)标记为 reserved4

一些精度:5

  • 我们选择名称 transport_err,因为从应用的角度来看, 错误的来源应该无法区分。还有应用程序 和“传输错误”这是由于 FIDL 导致的错误混合 编码/解码、FIDL 协议错误、内核错误等。 “传输错误”指的是模型中可能出现的各类错误, 框架(包含多层软件)。

  • 我们将类型 fidl.TransportErr 定义为严格的 int32 枚举,具有 单个变体 UNKNOWN_METHOD。此变体的值与 ZX_ERR_NOT_SUPPORTED;值为 -2 时的值:

    type TransportErr = strict enum : int32 {
      UNKNOWN_METHOD = -2;
    };
    

    向客户端显示传输错误时,如果绑定提供了一种方式, 获取未知互动 transport_errzx.status,即绑定 需要使用 ZX_ERR_NOT_SUPPORTED。不过,使用容器时 将未知互动 transport_err 映射到不合适的 zx.status 如何向客户端显示错误

    另一种方法是仅使用 zx.status,并始终使用 ZX_ERR_NOT_SUPPORTED 作为值,表示未知方法 有两个明显的缺点:

    • 它需要依赖于 zx 库,该库可能无法直接用于 多个库。这使得在 因为我们需要自动插入 zx 的依赖项,或者将 类型设置为 int32,但在 IR 中生成绑定,则将其视为 zx.status

    • 它不定义绑定应如何处理transport_err 不是 ZX_ERR_NOT_SUPPORTED。通过将类型指定为严格类型, 我们明确定义了接收 transport_err 值;则会被视为 解码错误。

  • 我们指的是“结果并集”但实际上 描述了一类共用一个通用结构的并集类型,即三个 序数,第一个变体不受限制(成功类型可以是任何值), 第二个变体必须是 int32uint32 或其枚举,第三个变体 变体必须是 fidl.transport_err

JSON IR 的变更

我们公开了 JSON IR 中互动的严格程度。在实践中, #/definitions/interface-method 类型,并将 strict 布尔值添加为 与 ordinalnameis_composed 等同级。

我们在 JSON IR 中公开协议的模式。在实际操作中,我们会更新 #/definitions/interface 类型,并添加包含 closed 成员的 mode 枚举, ajaropencomposed_protocolsmethods 等同级。

对绑定的更改

我们希望绑定的自动处理 请求。例如,虽然绑定可能能够自动 构建一个指明请求未知的请求,请务必 同时指出收到了未知请求(可能带有一些元数据 请求信息),并选择回复“请求未知”或突然 终止通信。

静态问题。

  • 对于灵活交互,绑定应呈现 结果联合体的 transport_err 变体通过同一客户端传递给客户端 呈现其他传输级别错误(例如错误)的机制, zx_channel_write 错误或解码期间出错。errresponse 结果联合的变体应以相同的方式呈现给客户端 如果该方法声明为 严格。

    • 例如,在 Rust 绑定中,Result<T, fidl::Error> 用于 呈现调用中的其他传输级错误,因此 transport_err 应 可折叠到 fidl::Error 中。同样,在低阶 C++ 绑定中, fit::result<fidl::Error> 用于传达传输级错误,因此 transport_err 应合并为 fidl::Errorresponseerr 变体的表达方式与严格方法相同。在 对于以下属性,将意味着 Result<Result<T, ApplicationError>, fidl::Error> 的 Rust: 包含错误语法的方法;Result<T, fidl::Error>(针对不带错误语法的方法) 错误语法,其中 response 值为 Terr 值为 ApplicationError

    • 对于将错误折叠为 zx.status 的绑定,transport_errUNKNOWN_METHOD 必须转换为 ZX_ERR_NOT_SUPPORTED

动态问题。

  • 使用 zx_channel_writezx_channel_call 或 它们的同级关系,必须按如下方式设置动态标志:
    • 严格程度位(位 7)必须设置为 0 以实现严格交互,而位必须设置为 设置为 1 表示灵活互动。
    • 接下来的六位必须设置为 0。
  • 收到已知交互时: <ph type="x-smartling-placeholder">
      </ph>
    • 当前绑定的工作方式没有变化。
    • 具体而言,绑定不应验证严格程度,以简化 从严格互动迁移到灵活互动(反之亦然)。
  • 当收到未知交互(即未知序数)时: <ph type="x-smartling-placeholder">
      </ph>
    • 如果互动严格(用收到的严格程度标记表示):
    • 绑定必须关闭通信(即关闭通道)。
    • 如果互动方式是灵活(用收到的严格程度标记表示):
    • 对于封闭式协议,绑定必须关闭通道。
    • 如果互动是单向的(交易 ID 为零): <ph type="x-smartling-placeholder">
        </ph>
      • 绑定必须向应用发出这种未知的交互(详情 )。
    • 如果互动是双向的(交易 ID 为非零): <ph type="x-smartling-placeholder">
        </ph>
      • 对于 ajar 协议,绑定必须关闭通道。
      • 对于开放协议,绑定必须将这种未知的交互 (详情如下)。
    • 有关引发未知互动的详情: <ph type="x-smartling-placeholder">
        </ph>
      • 如果交互是双向的,绑定必须通过 发送一个结果并集,其中包含所选的第三个变体, 第 fidl.TransportErr 个,共 UNKNOWN_METHOD 个。此操作必须在 未知的交互操作。
      • 绑定应向应用引发未知的交互, 可能通过调用先前注册的处理程序(或类似处理程序)进行调用。
      • 建议让绑定要求注册未知的 互动处理程序,以避免构建“默认行为”可以 造成误解。绑定可以提供“空操作处理程序”或类似名称,但 建议将其用于显式用途。
      • 绑定可以选择为应用提供关闭 渠道。

当未知邮件包含标识名时,服务器必须在以下位置关闭标识名: 来接收消息服务器必须关闭传入邮件中的所有句柄 早于:

  • 关闭渠道,如果是严格的方法,则使用灵活的方法, 或基于 ajar 协议的灵活双向方法
  • 回复邮件(如果对打开的 协议
  • 通知用户代码未知的方法调用(如果代码为柔性环境) 单向双向方法。

同样,当客户端收到包含句柄的未知事件时, 客户端必须关闭传入消息中的句柄。客户端必须全部关闭 处理以下事件:

  • 在发生严格事件或灵活事件时关闭渠道 关闭协议
  • 通知用户代码未知事件(如果是 或 ajar 协议

一般来说,在处理未知交互时, ,如下所示。

  1. 关闭传入消息中的标识名。
  2. 如果适用,请关闭此频道或发送 UNKNOWN_METHOD 回复。
  3. 将未知互动提交给未知互动处理程序或报告 出错。

在异步环境中可能会同时有多个线程 尝试通过该频道发送/接收消息时,系统可能无法或 切实可行,可以保证在报告未知方法之前关闭相应渠道 错误。因此,无需关闭渠道即可报告 错误。不过, 对于此 RFC 中指定的可恢复的未知交互,必须 在调度未知请求之前,先关闭句柄并回复(如果适用) 互动处理程序。

此 RFC 的先前版本未指定关闭句柄之间的排序 响应未知的双向方法,以及引发未知的 互动。

兼容性影响

ABI 兼容性

将互动从 strict 更改为 flexible,或将 flexible 更改为 strict 与 ABI 不兼容。

更改协议模式(例如从 closed 更改为 ajar)不会使用 ABI 兼容。虽然看起来从更严格的模式 限制较少的模式可能与 ABI 兼容,但这并不是因为 同时定义发送者和接收者的协议(即发即弃) 和事件)。

所有更改都可以进行软过渡。修饰符可以 versionned(如果需要)。

源代码兼容性

将互动从 strict 更改为 flexible,或将 flexible 更改为 strict 可能兼容源代码建议绑定提供相同的 API 无论交互的严格程度如何,都可以通过折叠现有的传输层, 错误 API。

无法更改协议模式(例如从 closed 更改为 ajar) 源代码兼容。建议绑定绑定以专门提供其提供的 API 具体取决于协议模式例如,封闭式协议不需要 以提供“未知方法”处理程序中,并且最好不要提供此类 不再使用的处理程序。

与平台版本控制的关系

RFC-0002 中,“更改 ABI 修订版本 每当平台对语义代码做出向后不兼容的更改时 Fuchsia 系统界面”界面中。

一项衡量我们是否成功实现 可更新目标是指 创建新的 ABI 修订版本。由于添加或移除灵活互动 该功能有助于改进 Fuchsia 的可更新性。

实现

  • 我们可以想象这样一种情况:绑定只实现 如果提前停止通信,这是安全的,就好像 遇到其他错误或 bug。
  • 鉴于 FIDL 的进化性(首要目标)的重要性,我们并不希望这么做。 因此,我们要求绑定遵守此规范。
  • 为符合绑定规范,绑定必须实现 严格灵活的交互语义,以及三种 API 模式, 协议
  • 考虑到这一点,我们将详细说明对绑定规范的更改。这是 破坏 ABI 合规性,是有线格式( 涵盖“静态”和“静态”和“动态”问题)。

此 RFC 的先前版本已调用,以限制未知的发布 新的神奇数字背后的交互方式。但正如我们所指定,未知的 可向后兼容现有协议,因为标头 用于表明严格程度的位是以前未使用/预留的, 只针对灵活的双向方法进行格式更改,这种方法只能存在于开放式 协议我们将使用两阶段部署,而不是更改虚拟数字 在其中启用未知交互支持,但设置了默认修饰符 添加到 closedstrict,然后将这些修饰符显式添加到现有 FIDL 然后将默认值更改为 openflexible

性能注意事项

closed 协议没有影响。封闭协议无需 请检查严格程度,如 绑定部分。

ajaropen 协议的影响不大:

  • 处理未知互动与处理已知互动类似, 系统会调用预注册的处理程序,并运行应用代码。
  • 此外,对于双向未知交互(只有 open 则绑定将构建并发送响应。

我们预计,性能考虑因素很少产生影响, 协议模式的选择主要取决于安全性 注意事项

工效学设计

这使得 FIDL 更易于理解,但又能满足一项非常重要的需求 关于可进化性,迄今为止,这一直都是一个尖锐的利器。

向后兼容性

此功能不向后兼容,需要进行软迁移 所有 FIDL 客户端和服务器的数据。

安全注意事项

添加了向对等方发送未知请求的功能(例如, 灵活互动)将引发安全问题的大门。

对于特别敏感的协议,可能需要 因需要非常刚性的交互而抢占,因此倾向于采用 使用 closed 协议。正常情况下 Fuchsia 依赖于 closed 协议(例如 fuchsia.ldsvc)。

在考虑 ajaropen 协议时,有两个问题 FIDL 作者需要考虑的事项:

  • 恶意对等方发送包含大型载荷的未知请求。(与 在使用 flexible 类型时存在的担忧 未知载荷。)如此处所述, 需要有影响 ABI 的更多功能 赋予 FIDL 作者控制权,并将在未来的工作中解决。
  • 开启协议嗅探之门,即对等方尝试发现 方法是在没有先验知识的情况下实现,然后设法 来利用已发现的方法。如果一个 Pod 内的 会比预期多公开一些方法。例如,打算 而是绑定构成 。请注意,灵活交互不会改变攻击途径, 但它可能更容易被利用 一个接一个地连接多个序数,而不必重新连接( 在某些情况下可能非常昂贵)。
  • 当您在选择 ajar 与选择 open 协议之间进行平衡时, 假设同伴无法判断单向互动 而对于双向未知互动(如 open 协议允许),则处理对等方会披露其无法 理解互动,这样就能揭示宝贵的信息 传送给恶意对等方。

隐私注意事项

开启协议嗅探大门可能会引起隐私问题。如前所述 在安全考虑部分中,此威胁 没有通过此 RFC 更改,但可能更容易被利用。

测试

开发本 RFC 中描述的一系列新功能的关键在于 确保所有绑定都遵循相同的规范,并且所有绑定的行为 。为此,客户需要能够以 测试,例如“发送此请求,使用正确的交易 ID 进行响应,但错误 序数,预计发送方渠道关闭”。根据我们的经验, 专注于流利地表达规范会导致测试量增加, 进而提高了所有绑定对本规范的遵从性 增强了回归保护。

我们将遵循与编码和解码相同的方法, 主要是在 GIDL 开发过程中实现的:先编写 手动测试,执行尽可能多的绑定,并逐步执行 泛化可以进行的部分,着眼于声明式测试 方法。虽然我们希望能够针对 动态的担忧,以及我们将努力实现的目标,并不是我们将这种情况 最终结果,可能更倾向于用手头流畅表达的考试结果。

文档

我们会提供大量有关此功能的文档。关于规范 侧面:

FIDL API 评分准则中的其他条目将 添加了介绍协议演变的内容

在此功能的特定目标语言中,我们希望每个 单个绑定更新其文档,并提供工作示例。

缺点、替代方案和未知问题

缺点:消息的最大大小会影响 ABI

处理未知数据时出现问题,比如可能遇到的未知载荷 其中引入的 flexible 类型或未知互动是指 预计对等设备读取的消息大小上限会影响 ABI; 不会明确说明此限制,也不应进行静态验证。

目前,没有信道的矢量化读取,也不支持 进行部分读取因此,可以将消息发送给满足 所有要求(例如灵活互动,当同行预期时), 会导致通信失败,进而破坏 ABI。如果相关帖子是 太大,对等方无法读取,因为该对等方预期消息内容小于 1KiB,则系统永远不会读取超过该限制的新邮件, 通道将被关闭,两个对等体之间的通信将中止。

灵活互动的引入可增加 这样的问题,由于 flexible 类型而已存在。

下面列举了一些针对未来发展方向的建议:

  • 矢量化通道读取,让接收方可以执行诸多操作,例如 只读取邮件标头,然后决定是否阅读邮件的其余内容 载荷或舍弃该消息(这也需要新的系统调用)。
  • 将消息的最大大小设为协议的显式属性, 可能也使用预定义的尺寸类别,例如 smallmediumlargeunbounded

替代方案:与命令模式进行比较

命令模式有助于 允许客户端批量处理多个请求,以便由服务器进行处理。它还 可以使用命令模式来实现这种可 请参阅此 RFC。

例如:

open protocol AnOpenProtocol {
    flexible FirstMethod(FirstMethodRequest) -> (FirstMethodResponse);
    flexible SecondMethod(SecondMethodRequest) -> (SecondMethodResponse);
};

这可通过下面的封闭协议进行近似,即: 要实现 进化能力相同:

closed protocol SimulateAnOpenProtocol {
    strict Call(Request) -> (Response);
};

type Request = flexible union {
    1: first FirstMethodRequest;
    2: second SecondMethodRequest;
    ...
};

type Response = flexible union {
    1: first FirstMethodResponse;
    2: second SecondMethodResponse;
    ...
    n: transport_err zx.status;
};

不出所料,命令模式方法并不令人满意。

由于我们必须将每个请求与并集中的响应进行匹配,因此会失去 “匹配对”的语法执行这也会导致 语法位置。

由于不受控制的服务器可以使用 SecondMethodResponse 响应 FirstMethodRequest,还会失去类型安全。人们可以认为 绑定可以注意到此模式,也许可以借助 @command 属性定义了。

在线路级别,命令模式会强制使用“两种方法判别器”/ 排序。事务性邮件标头中有序号(标识 Call 表示互动),并得到并集序数(用于确定 选择并集的变体,即 1 表示 FirstMethodRequest,2 表示 2 SecondMethodRequest)。

同样,有人可以认为,如果所有方法都遵循命令模式, 即所有方法的请求和响应都是联合体,所以我们不需要 事务消息标头中的序号。从本质上讲,灵活的协议 会“编译为”使用命令 模式。并集的传输格式需要计算 并要求由合规的解码器验证这些计数。 这在两个方面都存在问题:

  • 事务性消息标头允许的刚性(没有描述 例如有效负载,如果可以,则解码)是与联合线不匹配的 格式(实际上从设计上来讲)。这种呆板性和简洁性 非常适合低级别用例,FIDL 则是轮替的目标。

  • 组合模型没有任何“协议分组”的感觉。这个 非常强大,因为我们可以(并且确实) 。我们会尽可能使用结构化组合(例如 compose) 节),还采用了动态组合(例如服务发现)。如果 我们采用了“全部编译为并集”的观点就会强制采用 。

最后,某些 FIDL 作者希望“自动化技术” 批量发送请求”。例如, fuchsia.ui.scenic 图书馆因其 在 fuchsia.ui.scenic/Session.Enqueue 方法中使用命令模式。 但是,提供“自动批处理请求”有危险的功能 考虑如何在一个单元中处理多个命令的语义 应用之间也往往会有很大差别。我们该如何应对 未知命令?我们该如何处理失败的命令?命令应为 被忽略、停止执行、导致中止和回滚?即使是 RDBM 系统, 是围绕“批处理工作单元”的概念设计的,(交易)倾向于 提供多种批处理模式([隔离 levels)(https://en.wikipedia.org/wiki/Isolation_(database_systems))).够了 FIDL 不打算支持“自动批处理请求”。

总而言之,尽管从表面上看,它看起来像是严格、 灵活交互与命令模式相同, 区别在于确保特殊语义。

替代方案:协议协商

什么是协议协商

协议协商是一个宽泛的术语,描述面向对等方的一组技术 相互交互以逐步建立彼此相关的背景信息, 从而让他们能够正确、更快速、更高效。

例如,假设随机拨打一个电话号码。对方也许会 以“是这样,是吗?”开头。您先前对同行没有上下文, 身份识别。我们可以继续说“哦,这样吧。我做对了吗?” 鉴于营销通话的普遍性,您现在可能 “这场通话是关于什么的?你是谁?”。依此类推。两个对等网络 几乎可以发现对方是谁,以及具备什么能力。

  • 可以理解哪些数据元素?例如向对等方指示 创建所需的表,要小心,以避免同行生成大量 复杂数据,仅在收到后被忽略。
  • 类似应用支持哪些方法?在渲染引擎中,您可以想象 询问是否可以使用 alpha 混合功能,如果不可用, 与渲染程序的互动(可能通过发送不同的内容)。
  • 应使用哪些性能特征?双方通常会就 缓冲区大小,或者允许用户进行调用的频率(想一想 配额)。

每种类型所需的解决方案往往略有不同,尽管它们都是 本质上是将互动模型的抽象描述(例如,“ 一组方法”)转换成可交换的数据。

为了出色地解决协议协商问题,首先要提供一种方法, 说明这些概念(“协议”、“方法 foo 的响应类型”)。且 因为同行是从低语境开始的,也就是说,他们不了解 而且必须假定它们对 概念的描述往往依赖于结构属性。 例如,假设“响应类型为 MyCoolType”毫无意义, 但如“响应类型为 struct { bool; }”站在 且无需上下文即可进行解释。

协议协商与严格灵活的互动方式的关系

此 RFC 中提出的严格、灵活的交互方式, 在不断演变的协议方面具有较大的灵活性。现在,您可以向 remove 方法。甚至可能更多。但是,滥用进化的能力, 其域难以确定, 从其形状开始理解。这与表格类似,加时 因为它们现在表示一种“聚合结构体” 组合使用随时间推移而发生变化的多组要求。

在合同协议的协商中,如果使用得当,则有可能: 分离版本管理负担,并在进行一些动态选择(协商)后, 采用更加简洁和严格的协议(可能是 closed 协议)。

这两种进化技术都有自己的位置,在 进化工具箱。

替代方案:将严格位置于事务标识符中

使用事务标识符传达严格和 灵活交互具有一个重要的缺点。某些事务标识符 由内核生成,即 zx_channel_call 将前四个 消息的字节,作为 zx_txid_t 类型的事务标识符。打包更多 将信息传递到事务标识符中,可以实现更强的耦合, (这是不可取的)。使用事务性模式 标头标记,使用 zx_channel_call 的 FIDL 代码可以继续 构造标头中除标识符以外的所有内容的结构。

替代方案:交互模式位

此 RFC 的早期版本称为添加“交互模式”位至 将单向互动与双向互动区分开来,并且预计会扩展 到更复杂的互动,如终端 互动)。

主要缺点是,如果交互模式位与 交易标识符中提供的信息:单向互动 交易标识符为零,则双向互动具有非零交易量 标识符。由于信息冗余的原因, 实现(例如绑定)时,使用不同冗余位的子集来 决定如何处理消息。这反过来又为恶意人员打开了大门 精心构思的消息,而该消息可由内容的不同部分 系统。

我们的目标是既将交易标识符 和扩展互动模式等新功能, 所以我们倾向于将此设计 讨论何时推出这些功能。

备选:在命名时

随着这篇 RFC 的不断反复测试,关于如何正确命名 所引入的新概念。我们在本文中总结了一些讨论内容。

划分可能“未知”的互动那些需要 “known”:

  • 已选择“open”和 closed 个原始名称。
  • (none)required,这意味着您的对等方必须实现该方法。 否则,协议将被终止。
  • 入围者flexiblestrict(借用自 RFC-0033: Handling of 未知字段和严格程度

为了划分出永远不会接收未知交互的协议, 可以接收单向未知交互的协议 可以同时接收单向和双向交互:

  • 已选择 staticstandarddynamic 个原始名称。使用 YAML 格式 “static”和“动态”我们一直使用“静态”这一术语,和 “动态”参阅 FIDL 的传输格式和消息传递方面。对于 例如,此 RFC 中有一部分提到了“动态问题”它与 它的含义是“动态的”而不是“动态协议”
  • strict(none)flexible 再次从 RFC-0033 借用。
  • sealed 代替 static,突出显示协议不能 扩展。
  • 使用 hybridmixed 代替 standard
  • 入围者closedajaropen。由于不使用开放型和封闭式 我们可以将它们用于协议修饰符。通过 “ajar”的定义是“部分打开”这正是 概念。没错,所有担心的人都感觉这件事有点恐怖

先验技术和参考资料

(如文中所述。)


  1. 令人困惑的是,消息(而不是事务性的) 是指 FIDL 的编码形式 值

  2. 对于 fidlc 和 JSON IR 爱好者,请注意 编译器的内部结构将事件表示为 maybe_request_payload 等于 nullptrmaybe_response_payloadpresent。来自模型 不过,我们将此载荷称为请求 从服务器到客户端的方向我们应该与组合模型保持一致, 更改 fidlc 和 JSON IR。这超出了本 RFC 的讨论范围,但已注明 以确保完整性。

  3. 我们更喜欢采用自由语法,同时提供风格指南 执行 lint 请求。这是设计选择的动机 使用更易于新用户理解的语言 对紫红色有非常明确(反过来又很详细)的标准 平台。 

  4. 值得注意的是,将error添加到 flexible 交互可以作为兼容 ABI 的软更改进行。 

  5. 我们之后将 transport_errTransportErr 重命名为了名称 分别更改为 framework_errFrameworkErr。请参阅 如需了解详情,请访问 https://fxbug.dev/42061151。