RFC-0155:可选的功能路由

RFC-0155:可选 capability 路由
状态已接受
区域
  • 组件框架
说明

在组件清单的“offer”和“use”部分中添加了一个新字段,用于指明给定 capability 可能不存在的情况。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2022-02-07
审核日期(年-月-日)2022-04-14

摘要

系统会向组件清单的 offer 和 use 部分添加一个新字段,以指明给定 capability 可能不存在的情况。

设计初衷

核心领域分片

使用核心 Realm 分片时,可能会出现 capability 路由的来源或目标不存在的情况。例如,

  • 组件 /core/wlancfg 使用协议 fuchsia.location.sensor.WlanBaseStationWatcher,但某些产品不支持此协议。
  • 组件 /core/bt-a2dp 必须使用 fuchsia.power.battery.BatteryManager 功能(如果可用),但该功能并非适用于所有产品。
  • /core/omaha-client-service 组件必须使用 fuchsia.update.config.OptOut 协议(如果可用),但该协议并非适用于所有产品。
  • CommsAgent 软件包必须使用视频(如果有),但某些商品没有视频。
  • 轨迹提供程序是一种提供 fuchsia.tracing.provider.Registry 功能的组件。这对开发很有用,但不应将此组件包含在用户 build 中。

上述场景是我们今后想要支持的组件配置,但目前组件框架中仍有几个地方存在与此相关的粗糙边缘:

  • 向清单中不存在的组件提供或从中获取内容将导致清单验证失败。
  • 从未公开相应功能的组件提供该功能将导致审核验证失败。
  • 功能路线失败(例如,尝试使用未提供的功能)会导致组件管理器(正确地)发出警告级日志,这可能会看起来令人担心,因此在调查故意省略该功能的产品时会造成误导。

通过集合进行路线验证

Scrutiny 是一款组件路由验证工具,可确保给定组件树中使用的所有功能都具有有效的功能路由。除了提供系统正确性断言之外,它还是一款实用的开发工具,因为它可以将路线验证从运行时移至构建时,从而缩短开发周期。

目前,我们维护了许可名单,用于停用对特定 capability 路线的审慎检查。这样一来,当组件使用不可用的 capability 时,build 便会成功;但遗憾的是,当 capability 用时,如果 capability 路线在 build 上配置错误,build 也会成功。

此外,在 https://fxbug.dev/42174612 得到解决后,审核还将验证源自会话领域的 capability 路由。会话组件通常依赖于会话之外的功能,如果其中某个组件希望被添加到审核许可名单,则会增加摩擦,因为这些组件可能在 fuchsia.git 之外开发。

利益相关方

哪些人对此 RFC 的接受与否有利益相关?(此部分为可选部分,但建议填写。)

主持人:Hunter Freyer (hjfreyer@google.com)

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

Reviewers:

  • Mark Dittmer(markdittmer@google.com)- 安全
  • Gary Bressler (geb@google.com) - 组件框架
  • Marc Khouri (mnck@google.com) - WLAN
  • Ani Ramakrishnan (aniramakri@google.com) - 蓝牙
  • Yaar Schnitman(yaar@google.com)- 产品

社交

在从 https://fxbug.dev/42168255 收到要求并征求一些特定个人的反馈后,我们在利益相关方之间分享了此 RFC 的早期版本。

设计

系统会在使用声明中添加一个名为 availability 的新字段。此字段的默认值为 required,这表示组件预计会提供该 capability,如果该 capability 不可用,则可能会出现故障。此 RFC 不会对 required capability 的行为提出任何更改建议,它们的行为将与所有 capability 的行为一样

{
    use: [
        {
            protocol: "fuchsia.logger.LogSink",
            availability: "required",
        },
        {
            directory: "config-data",
            path: "/config",
            rights: [ "r*" ],
            // The `availability` field defaults to `required` when omitted.
        },
    ],
}

您还可以将 use 声明的 availability 字段设置为 optional,以反映在 capability 不可用时组件何时可以正常运行(可能具有修改后的行为)。

{
    use: [
        {
            // Emergency location is not present in all products.
            protocol: "fuchsia.location.sensor.WlanBaseStationWatcher",
            availability: "optional",
        },
    ],
}

系统会将名为 void 的新来源添加到商品声明的可能来源列表中。

{
    offer: [
        {
            protocol: "fuchsia.update.config.OptOut",
            from: "void",
        },
    ],
}

使用声明为可选的 capability 可以从现有组件或“void”提供。需要使用声明的 capability 不得从 void 提供,因为这可能会导致组件故障。

中间商品(从父级到子级)也可以将 availability 字段设置为以下值之一:

  • required(默认):无论子项能否处理此 capability 缺失的情况,子项都必须获得对此 capability 的访问权限(它可能无法从祖先中的 void 提供)。
  • optional:子级必须能够处理缺少此功能的情况(优惠链末尾的使用声明必须是可选的)。
  • same_as_target:优惠的选填性与目标相同。如果目标平台需要此功能,则此优惠规定目标平台必须获得此功能。如果目标平台可以选择是否使用此 capability,则此 offer 规定目标平台可以或不可以获得此 capability。
{
    offer: [
        {
            protocol: "fuchsia.power.battery.BatterManager",
            from: "parent",
            to: "bt-a2dp",
            // Emit a build-time error if this protocol is not correctly routed
            // to this child (including offers from void).
            availability: "required",
        },
        {
            protocol: "fuchsia.location.sensor.WlanBaseStationWatcher",
            from: "parent",
            to: "wlancfg",
            // Emit a build-time error if this child is unable to handle the
            // absence of this protocol.
            availability: "required",
        },
    ],
}

如果某个组件使用了 optional,并且其父级以 required 的形式提供该 capability,那么如果该 capability 的路径无效或以“offer from void”结尾,系统会发出构建时错误。如果某个组件使用了 required,并且其父级以 optional 的形式提供该 capability,那么系统会发出构建时错误。此字段可以取消设置,在这种情况下,系统会忽略该字段。

核心 Realm 汇编

RFC-0089 中所述,核心领域由“核心分片”组成,这些分片是指在构建时与核心领域合并的 CML 代码段。核心分片的确切集合由产品定义设置。

通常建议将定位到子项的商品包含在与子项声明相同的核心分片中。这有助于确保如果 build 中包含子模块,则系统也会向其提供其正常运行所需的功能。

如果商品希望具有可选择包含在 build 中的来源,则在与子项相同的分片中包含子项的商品会变得复杂。如果目标为子级 a 的商品的来源为子级 b,但 b 也位于分片中,则 a 的分片只能包含在同时包含 b 分片的 build 中,否则,由于商品来自不存在的子级,系统会在构建时发出清单验证错误。

为了允许子商品与子商品声明位于同一核心分片中(无论来源如何),我们将引入一个名为 source_availability 的新字段来提供声明。此字段的默认值为 present,但可以设置为 unknown

source_availability 设置为 unknown 后,如果商品声明引用的来源不在清单中,则该声明将通过清单验证。在清单编译期间,此优惠声明缺少的来源将替换为 void 来源,这样,路线以此优惠声明结束的任何使用声明都可以通过将其可用性设置为 optional 来通过路线验证,以反映该功能并非所有产品都具备。

{
    offer: [ {
        protocol: "fuchsia.examples.Echo",
        from: "#child-that-might-not-be-declared",
        to: "#echo-user",
        source_availability: "unknown",
    } ],
}

这样,平台配置维护人员就可以将一组核心分片用作核心领域中存在的功能和组件的唯一可靠来源。忽略核心分片不仅会从核心领域中移除某个子系统,还会将源为该子系统的所有产品准确更新为从 void 提供,这样,当系统有意将某个子系统排除在外时,对该子系统有可选用途的所有组件都不会获得对这些子系统的访问权限(但在这种情况下,任何必需用途仍会导致错误)。

示例

核心领域中具有可选功能的组件

在本例中,我们来看看 wlancfg 的清单和核心 Realm 分片会如何根据所提议的设计而发生变化。

fuchsia.location.sensor.WlanBaseStationWatcher 协议的优惠将从 emergency.core_shard.cml 移至 wlancfg.core_shard.cmlsource_availability 字段设为 unknown(因为紧急核心分片及其紧急组件可能包含在与 wlancfg 相同的平台配置中,也可能不包含)。

// src/connectivity/location/emergency/meta/emergency.core_shard.cml
{
    offer: [
        // This is removed
        {
            protocol: "fuchsia.location.sensor.WlanBaseStationWatcher",
            from: "#emergency",
            to: "#wlancfg",
        },
    ],
}
// src/connectivity/wlan/wlancfg/meta/wlancfg.core_shard.cml
{
    offer: [
        // This is added
        {
            protocol: "fuchsia.location.sensor.WlanBaseStationWatcher",
            from: "#emergency",
            to: "#wlancfg",
            source_availability: "unknown",
        },
    ],
}

将商品声明移至 wlancfg 的核心分片是确保 source_availability 字段正常运行的必要条件,这也符合核心分片最佳实践。

除了核心分片更改之外,wlancfg 中对此协议的使用声明将更新为 optional

// src/connectivity/wlan/wlancfg/meta/wlancfg.cml
{
    use: [
        {
            protocol: "fuchsia.location.sensor.WlanBaseStationWatcher",
            // This line is added
            availability: "optional",
        },
    ],
}

现在,如果 emergency.core_shard.cml 文件未包含在 build 中,则不会因 wlancfg 无法访问 fuchsia.location.sensor.WlanBaseStationWatcher 协议而出现构建时错误。这意味着,该协议可能会从审核的许可名单中移除,并且任何导致该协议在可用的平台配置上无法供 wlancfg 使用的配置错误都将导致构建时错误。

会话中具有可选功能的组件

在本例中,我们来看看在将 fuchsia.power.battery.BatteryManager 协议从 /core/battery_manager 更改为 /core/session_manager/session:session/workstation_session/login_shell/ermine_shell 时,涉及的清单和核心 Realm 分片会如何根据所提议的设计而发生变化。

workstation.core_shard.cml 文件中协议的优惠将更新为将 source_availability 设置为 unknown

// src/session/bin/session_manager/meta/workstation.core_shard.cml
{
    offer: [
            protocol: "fuchsia.power.battery.BatteryManager",
            from: "#battery_manager",
            to: "#session-manager",
            // This line is added
            source_availability: "unknown",
    ],
}

无需更改 coreermine_shell 之间的优惠,只需更新 ermine_shell 清单,将协议的 availability 字段设置为 optional

// src/experiences/session_shells/ermine/shell/meta/ermine.cml
{
    use: [
        {
            protocol: "fuchsia.power.battery.BatteryManager",
            availability: "optional",
        },
    ],
}

进行这些更改后,workstation.core.shard.cml 文件可以包含在没有 battery_manager.core_shard.cml 的平台配置中,而不会导致构建时审核错误或将此功能添加到许可名单中。这意味着,可以从旨在在没有电池的硬件上运行工作站会话的平台配置中安全地排除电池管理器组件。

会话所有者希望确保一项可选功能始终

可用

基于前面的示例,假设有一个名为 workstation-on-laptops 的虚构会话,该会话与 workstation 会话完全相同,但具有额外的笔记本电脑专用功能。如果此会话的所有者希望使用 workstation 会话中存在的相同 ermine 组件,但希望确保它始终有权访问 fuchsia.power.battery.BatteryManager 协议(由构建时错误强制执行),则会话所有者可以将此协议作为 required 提供给 ermine

// src/experiences/session_shells/ermine/session/meta/workstation_on_laptops_session.cml
{
    offer: [
            protocol: "fuchsia.power.battery.BatteryManager",
            from: "parent",
            // login_shell offers the capability to ermine
            to: "#login_shell",
            availability: "required",
    ],
}

在此示例中,如果将 workstation-on-laptops 会话与提供 void 中的 fuchsia.power.battery.BatteryManager 协议(即不包含 battery_manager.core_shard.cml)的平台配置进行比较,则会发出构建时错误,即使 ermine.cml 可以选择使用该协议也是如此。

会话所有者希望确保组件能够处理以下情况:

可选 capability

再次以“ermine 可选地使用 BatteryManager”示例为基础,如果工作站会话的所有者希望确保 ermine 始终能够处理 fuchsia.power.battery.BatteryManager 协议的缺失(无论该协议当前是否可用),则可以将此协议作为 optional 提供给 ermine

// src/experiences/session_shells/ermine/session/meta/workstation_session.cml
{
    offer: [
            protocol: "fuchsia.power.battery.BatteryManager",
            from: "parent",
            // login_shell offers the capability to ermine
            to: "#login_shell",
            availability: "optional",
    ],
}

此可选功能对给定配置的构建或运行时行为没有影响,因为 ermine 也可以选择使用该功能。不过,如果 ermine 发生更改以需要此 capability,则无论 capability 路线是否有效或是否以“offer from void”结尾,scrutiny 都会发出构建时错误。

实现

如需实现这些更改,必须更新 fuchsia.component.decl.Component FIDL 表和 CML JSON 架构以添加新字段,同时更新 CMC、cm_fidl_validator 和 Scrutiny 以正确处理设计部分中所述的 optional 语义。

性能

由于在这些清单中携带额外的枚举的开销非常小,因此所提议的更改不会对构建时间或大小产生任何重大影响。此外,组件管理器中建议的运行时行为更改不会对性能产生任何重大影响,因为在开始执行此工作时,实现新命名空间汇编逻辑所需的信息全部都在内存中。

工效学设计

对于目前需要与许可名单互动以抑制审核验证错误的任何组件作者,这项更改应该会显著改善人体工学,因为预期验证错误周围的上下文将得到改进,这样审核就不会发出这些预期错误。

向后兼容性

此更改仅是对 FIDL 表和 JSON 格式的补充,因此没有向后兼容性问题。

安全注意事项

此项变更将使组件作者能够在不获得安全团队批准的情况下为未路由的功能停用审核错误,因为许可名单将不再用于控制未路由功能的审核错误抑制。

我们认为这可以接受,因为此提案不会改变创建或更改组件路由本身的审核流程。

隐私注意事项

拟议的更改不会影响用户数据的收集、处理或存储方式,因此不会产生任何隐私问题。

测试

已经有大量测试涵盖了组件清单流水线。这些测试将被更改,以涵盖这项新功能的测试覆盖率。

文档

组件清单文档将更新,以介绍新字段及其对验证的影响。

缺点、替代方案和未知情况

在先技术和参考文档

TODO