RFC-0168:通过 InspectSink 公开检查

RFC-0168:通过 InspectSink 公开检查
状态已接受
区域
  • 诊断
  • 组件框架
说明

定义组件公开 Inspect 的机制。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2022-05-17
审核日期(年-月-日)2022-06-15

摘要

此 RFC 引入了 fuchsia.diagnostics.InspectSink 协议,该协议允许组件公开检查数据。因此,现在可以移除当前机制(即 DirectoryReady 事件)。

设计初衷

Inspect today 通过一种与常规组件框架功能路由不一致的机制公开。目前,组件在其传出命名空间中向框架公开 diagnostics 目录。

在 RFC-121 中,DirectoryReady 事件被标记为已弃用,这是在 SDK 中发布事件功能的目标的一部分。不过,如果此目录不存在,我们目前还没有很好的解决方案来解决组件如何公开检查数据的问题。此外,Fuchsia 上的 Flutter 希望摆脱对这些文件系统抽象的依赖,并简化它们的实现。重新思考组件如何公开 Inspect 将有助于他们消除显著的运行时复杂性,并为开发者人体工程学提供优势。

利益相关方

教员:leannogasawara@google.com

审核者

  • crjohns@google.com
  • geb@google.com
  • shayba@google.com

已咨询

  • dworsham@google.com
  • surajmalhotra@google.com
  • zarvox@google.com

社会化:此 RFC 之前以 Google 文档的形式在诊断、组件框架、Flutter 和其他团队中进行了社会化。

设计

背景

很久以前,归档程序通过 /hub 注入检查数据。其代码库被构建为 Hub 上的目录监听器,一旦 out/diagnostics 目录出现(当时它的名称不同),就会立即开始跟踪组件的 Inspect 数据。此功能最终被移除,并通过事件(在 appmgr 和组件管理器中)实现。 此外,当时读取检查数据的测试是通过直接从 /hub 读取数据来实现的。

Archivist 目前依赖于 DirectoryReady 事件来执行以下两项操作:

  • 从组件(组件 expose /diagnostics to framework)提取检查数据。
  • 将 Inspect 数据归因于来源组件。

DirectoryReady 事件可解决上述两个问题。不过,我们已经有 CapabilityRequested 来解决 (2),并且作者认为我们可以使用常规协议(类似于 fuchsia.logger.LogSink)来解决 (1),从而带来更多优势。

解决归因问题不是此 RFC 的目标。这留作未来工作,用于移除当前用于 LogSinkDebugDataCapabilityRequested 事件。

InspectSink

此 RFC 引入了 InspectSink 协议,该协议允许 Archivist 从组件中提取检查数据。此协议的定义如下:

library fuchsia.diagnostics;

using zx;

@discoverable
protocol InspectSink {
    /// Publishes a handle to the `fuchsia.inspect.Tree` protocol that the server can use to read
    /// Inspect data, including lazy nodes.
    Publish(struct {
        tree fuchsia.inspect.Tree;
        root zx.handle:<VMO, zx.rights.BASIC | zx.rights.READ | zx.rights.MAP, optional>;
    });

    /// Publishes a read handle to the inspect VMO  that the component asynchronously updates.
    /// The server can read Inspect using the Inspect reader algorithm [1]. A component using this
    /// method to publish Inspect won't be able to expose lazy nodes.
    ///
    /// [1]: /docs/reference/platform-spec/diagnostics/inspect-vmo-format.md#reader_algorithm
    PublishVmo(struct {
        name string;
        root zx.handle:<VMO, zx.rights.BASIC | zx.rights.READ | zx.rights.MAP>;
    });
}

主要方法是 Publish,大多数组件都会使用它,因为 fuchsia.inspect.Tree 是公开 Inspect 的标准方式。不过,我们提供了一种机制,允许组件仅发布检查 VMO。这出于以下几个原因:

  • 如果组件不需要是服务器(没有理由运行异步循环,只是使用功能,不提供任何服务),则不需要是服务器,但仍应能够公开 Inspect。
  • 在驱动程序迁移为使用 fuchsia.inspect.Tree问题)之前,它们将继续公开 VMO。
  • 在 Inspect Dart 库支持 fuchsia.inspect.Tree 之前,它需要继续公开 VMO。

fuchsia.logger.LogSink 类似,此协议将由 Archivist 提供服务并路由到组件。

与提供 out/diagnostics 目录相比,此协议具有以下多项优势:

  1. 与标准组件协议路由保持一致:

    • 组件仅使用协议 fuchsia.inspect.InspectSink,而不执行 expose /diagnostics to framework,这与组件目前导出日志和轨迹的方式类似。
    • 归档器可以通过 CapabilityRequested 接收连接,同时保持提供方信息。
  2. 可在启动组件异步循环之前提供检查数据。

    • 目录由 fuchsia.io.Directory 提供支持,大多数组件在启动异步循环之前不会提供其 out 目录。使用此协议,快照可以包含尚未启动异步循环但已写入检查数据的组件的检查数据。

    • fuchsia.inspect.Tree 协议也是如此。在组件开始提供此协议之前,快照中不会显示组件的 Inspect 数据;在大多数情况下,在组件开始其异步循环之前,也不会显示这些数据。通过使用上述协议,我们可以立即为 Archivist 提供根 VMO(因此至少此 VMO 会包含在快照中)和 fuchsia.inspect.Tree 的句柄,以供将来请求使用。

  3. 不再出现跑步程序和文件系统实现方面的问题。

    • 我们目前在 appmgr 和组件管理器中添加了代码,用于处理组件未及时提供 out/diagnostics 的特殊情况,Flutter runner 就是这种情况。该运行程序会先提供 out/ 目录,然后再填充该目录。理想情况下,我们只会使用目录监听器,但并非所有 VFS 实现都实现了监听器(尤其是 Flutter 使用的 C++ SDK 中的 VFS 实现),并且我们无法依赖于未来使用完整 fuchsia.io.Directory 实现的 runner。

此更改可以在后台完成,方法是将 inspect/client.shard.cml 更改为使用新协议,而不是将诊断目录公开给框架。文件 inspect/client.shard.cml 通过 SDK 提供,并由所有公开“随处检查”功能的组件使用。

此提案适用于 v2 组件。出于兼容性考虑,我们仍会处理 v1 组件的 out/diagnostics。随着向 v2 的持续迁移,作者认为没有必要花时间更改 v1 的工作方式。我们的目标是在底层进行此更改,以便迁移到 v2 的组件无需更改其公开检查的方式。

实现

我们将遵循标准的 LSC 流程。

具体步骤如下:

  1. 在 Archivist 中实现新协议 InspectSink
  2. 使用 inspect/client.shard.cml 识别组件,并从 Archivist 将 fuchsia.inspect.InspectSink 路由到这些组件。如今,这会带来一个问题,即必须在 CML 定义中完全枚举所有此类组件,不过我们已经有了一个解决方案,该解决方案已公开,将在后续 RFC 中介绍。
  3. 更改 inspect/client.shard.cml 以使用此协议,同时向框架公开 /diagnostics 目录,从而实现软过渡。
  4. 支持连接到 InspectSink,而不是在检查库中公开 diagnostics 目录。
  5. 在组件管理器中移除 DirectoryReady 的实现,并在所有组件都已完成过渡且所有预构建项都已刷新后,从 fuchsia.sys2.Event 定义中移除该实现。我们将依靠 CTF 测试和支持窗口来了解何时可以完成此操作。

性能

性能应该会有所提升,因为我们不再需要遍历目录或创建 DirectoryReady 事件,只需依赖单个协议。

安全注意事项

此更改符合组件框架安全属性,特别是最小权限原则和分层隔离原则。

隐私注意事项

隐私权方面没有变化。检查数据会继续通过常规隐私权流水线。

测试

此 RFC 的实现将通过以下方式进行测试:

  • 在连接到 InspectSink 的库中进行单元测试。
  • 在提供 InspectSink 的 Archivist 中经过单元测试和集成测试。
  • 用于检测兼容性变更的 CTF 测试

文档

检查发现和托管功能将进行更新。

目标是在编写检查的库中进行此底层更改。不过,如果我们在将组件迁移到 v2 时最终需要更改代码,我们会在迁移指南的诊断部分反映这些更改。

缺点、替代方案和未知因素

用于日志和 Inspect 的单一协议

我们可以创建一个 DiagnosticsSink,让组件在一个位置连接 Inspect 和日志。

  • 优点:只需一个协议即可进行路由,而无需两个。
  • 缺点:如果将来出于某种原因,我们需要以不同的方式处理日志或 Inspect,那么如果这两个功能使用不同的协议,处理起来可能会更轻松。

我们认为,这种缺点使得此替代方案非常不具吸引力,因为日志和检查是不同的事物,因此将它们分开路由是有意义的。

在先技术和参考资料

不适用