RFC-0101:具有编号句柄的动态组件

RFC-0101:具有编号手柄的动态组件
状态已接受
领域
  • 组件框架
说明

提供一种将带编号的句柄传递给动态组件的方法。

Gerrit 更改
作者
审核人
提交日期(年-月-日)2021-05-18
审核日期(年-月-日)2021-06-02

摘要

本文档建议将新参数添加到 fuchsia.sys2.Realm/CreateChild。此参数将包含一组 标识名。已创建组件的 runner 将收到这些句柄 调用它。提供的标识名只会 适用于在集合中运行的组件,具有新型耐用性: single-run。集合中持久性single-run 在创建时启动,停止时销毁。范围 提供的句柄。

设计初衷

Starnix 是一个运行 Linux 二进制文件的组件框架 v2 运行程序 在 Fuchsia 上。Starnix 实现了 Linux 系统接口来运行这些二进制文件 修改。

Starnix 提供了一个 ffx 插件,可让用户运行 Linux 组件 从主机命令行登录。Starnix 希望将 将 Linux 组件的 stdin/stdout/stderr 转换为三个套接字句柄。 该组件不会通过公开 FIDL 协议与系统交互。 而是通过提供的套接字与用户互动。

设计

背景

组件框架中的生命周期转换有两个维度。 第一个与存在(CreatedDestroyed)有关。第二个 与组件的执行(StartedStopped)有关。在其他 这类操作系统只有进程,没有组件, 维度是等效的:创建进程与启动进程相同, 进程在停止运行时就会被销毁

CreatedStarted 之间的区别在提供 为组件添加参数通常,可以启动单个组件实例 并多次停止,因此组件管理器必须存储 提供它们。如果参数是句柄,则可以 存在问题,因为并非所有标识名都可以重复。任何不可重复项 句柄被“消耗”相应事件

协议更新

背景中所述,创建组件与创建组件完全不同 启动它因此,提供给 CreateChild 的句柄必须为:

  1. 组件每次启动时都可用。
  2. 将作用域限定为组件的单次运行。

由于并非所有句柄都可以复制(存储在组件管理器中 后续运行),(1) 只有在从 每次运行时的来源请参阅路由 处理方法 未选择在启动时提取句柄。幸运的是,(2) 是一种可行的解决方案 用于激励用户的应用场景。

系统会创建一个新表 ChildArgs,并将其作为参数添加到 Realm/CreateChild

protocol Realm {
  /// If args contains numbered_handles, the collection must have a durability
  /// of type `single-run`.
  CreateChild(CollectionRef collection, ChildDecl decl, ChildArgs args)
      -> () error fuchsia.component.Error;
}

resource table ChildArgs {
  /// The numbered handles for the component instance.
  ///
  /// Only PA_FD and PA_USER* handles are valid arguments, and inclusion of any other
  /// handles will result in an error.
  1: vector<fuchsia.process.HandleInfo>:N numbered_handles;
}

此外,fuchsia.component.runner.ComponentStartInfo 表将 已更新为包含带编号的句柄:

resource table ComponentStartInfo {
  6: vector<fuchsia.process.HandleInfo>:N numbered_handles;
}

运行程序会向组件提供这些手柄,或者关闭它们并返回 如果运行程序不支持向 组件。

集合持久性

通过 Realm 协议创建的组件位于集合中。 集合有一个 durability 注解,用于指明生命周期 各个组成部分的语义质量之间有何区别。

系统将添加新集合“durability”的值“single-run”来指明 集合中的组件在创建后立即启动 它们会在停止后被销毁ChildArgs.numbered_handles只能是 与标记为 single-run 的集合一起使用。这会将 ChildArgs

collections: [
    {
         name: "playground",
         durability: "single-run",
    }
],

实现

将更新组件管理器以存储 ChildArgs,直到其传递 以及处理 single-run 集合语义。

向后兼容性

这项变更对于运行程序而言是向后兼容的:运行程序不是 需要使用提供的编号标识名。如果跑步者没有 支持带编号的句柄,则预计会关闭这些句柄。

此更改不向后兼容 Realm 客户端。

就 CML 而言,此更改向后兼容:唯一的更改是 添加了耐用性枚举。

性能

由于句柄是直接提供给 组件管理器。

安全注意事项

此变更引入了一种方式,可让父级将任意编号句柄传递到 子女。这些句柄的交换由组件和 和运行程序只有在集合中运行的组件被标记为 single-run 可采用这种方式接收句柄。

测试

针对 CreateChild 的现有测试将纳入检查范围,以涵盖新的 参数。

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

缺点

与 替代方案:

  • 这是一种新的组件启动方式:组件的生命周期 受功能绑定影响
  • 提供的句柄对于组件框架的静态 CML 是不透明的 分析。
  • 由于接收句柄的组件会在停止时销毁, 永久性存储空间也会被清除因此,使用 不适合使用此功能。

将带编号的句柄作为功能传送

路由带编号的句柄可以由组件框架显式完成。

有多种方法可以实现这一目的,但它们都具有 按照“形状”操作

引入由编号来源实现的协议 标识名:

protocol HandleProvider {
    Get(string handle_name) -> (fuchsia.process.HandleInfo handle);
}

然后,此协议会转换为功能:

capabilities: [
    {
        handle_provider: "stdin",
        path: "/svc/fuchsia.component.HandleProvider",
    },
],
expose: [
    {
        handle_provider: "stdin",
        from: "self",
    },
],

然后,这些信息可以通过 CML 路由到目的地,就像 的功能。

优势

  • 可以进行改进,以支持有关句柄的更多类型信息。
  • 使手柄的路由对组件显式可见 框架。

缺点

在提取句柄之前,组件无法启动。 即使性能影响可以通过缓存中的句柄 那么激励应用场景就无法受益于此,因为 每次运行组件时,句柄都是不同的。在建议的 主机代码可能会“触发后忽略”启动组件的请求 然后继续执行,就像调用成功一样。在此替代方案中, 主机代码需要坐着并旋转,等待关联的句柄请求 然后再回来。

句柄提供程序并非总能通过静态路由访问。在 激励用户场景:句柄提供程序位于主机上,并连接到 通过 Overnet 的 Fuchsia 设备。这可以通过路由“尽可能远”来解决 然后具有“边缘”组件通过临时机制提取句柄 然后再将其返回到组件框架这会带来额外的负担 希望使用此功能的开发者

句柄提供程序无法区分 指定功能路由。具体而言,请考虑激励用户用例:

  1. 用户在不同的终端从主机启动两个 Linux 组件。
  2. 这些组件在集合中进行了实例化。
  3. 句柄提供程序收到对同一句柄的两个请求。

此时,句柄提供程序不知道哪个组件 都与哪个句柄请求相关联这可以通过引入 用于识别客户身份的其他机制, 比提议的设计更复杂。

该解决方案需要更大的投入,并且比建议的设计更复杂。 尽管如此,所提议的设计并不会阻止 将来会进行编号标识名的路由。

StartChild

该替代方案建议将带编号的手柄作为参数添加到 RealmStartChild 通话。这与建议的设计类似, 在组件绑定到功能之间引入争用的缺点 由组件提供(将启动组件)和 StartChild 调用。具体来说,该组件只会收到 会处理 StartChild 调用是否赢得了比赛,因为不清楚 句柄将被提交。

入门协议

您可以通过 Starter 协议传递带编号的句柄。入门 协议可用于启动组件,由组件实现 管理器代表组件进行路由,并且可以像其他任何协议一样进行路由 (即,组件可由并非其父组件的组件启动)。

此协议可以像任何其他协议一样进行路由,因此客户端可以使用它 启动位于组件任意位置的组件 层级结构。

起始协议包含一个接受编号句柄作为参数的方法:

[Discoverable]
protocol StarterWithArgs {
    /// Start the component that is bound to this protocol.
    /// If the component is already running, the call returns an error.
    Start(StartArgs start_args) -> () error fuchsia.component.Error;
};

此提案与 StartChild 非常相似。公开的协议 这样便于审核和列入许可名单, 会在调用 Start 与绑定到任何其他 capability 之间引入争用 由该组件公开此外, 客户端并非始终是父级,因此也不一定会重启 该组件可提供参数这可以通过添加经停点来解决 方法。

客户端还需要在启动方式之间协调子级管理工作 和 Realm 协议,而不是专门管理子项 通过 Realm 协议进行传输。