Availability

若要选择哪些功能进入其 namespace,组件会在其 manifest 中为每项功能指定 use 声明。不过,由于功能路由涉及一系列组件,因此即使组件 use 具有某项功能,也不意味着该功能始终可用。它可能会因各种原因而变得不可用:例如,如果链中的某个组件未路由该功能,或者其中一个组件未能解析。

当组件 use 或路由功能时,它可能对功能是否必须可用有各种期望。在某些情况下,capability 对组件的运行至关重要:如果有人创建的拓扑无法将 capability 路由到组件,最好能尽早检测到该故障,以防止出现 bug。不过,在其他情况下,组件可能能够容忍缺少相应功能,或者在某些配置中,相应功能可能本来就应该缺失。为了适应这些不同的场景,cml 在 use、offer 和 expose 上提供了 availability 选项,组件可以使用该选项来声明其对功能可用性的预期。

选项

该框架支持以下 availability 选项:

必需

最常用的 availability 选项是 required,表示组件始终需要相应功能,如果缺少该功能,则无法正常运行。如果未指定任何使用情况,系统会自动设置此默认选项。

可选

optional 表示某些配置可能不支持相应功能。如果组件 use 是一项可选功能,但最终发现该功能不可用,则组件应能够在没有该功能的情况下正常运行,例如通过停用需要该功能的任何功能。

不过,如果某些配置中没有 optional 功能,框架会预期拓扑仍然包含以 void 结尾的完整功能路由。这样一来,产品所有者就需要明确选择相应功能是否可用(其路由在某个提供程序组件处终止)或不可用(其路由在 void 处终止)。如果路由不完整,工具和诊断程序会将此情况报告为错误。

过渡性

transitional 类似于 optional 的弱化版本。与 optional 类似,如果某个组件使用 transitional 功能,则应容忍该功能缺失的情况。不过,与 optional 不同,transitional 路由不需要以 void 结束,如果 transitional 路由不完整或无效,工具和诊断程序不会报告任何错误。

“过渡”一词表示此选项适用于软过渡。例如,假设您有一个 Echo 协议,想要将其替换为 EchoV2。在此过渡的早期阶段,您可以将客户端更改为 use 新协议,并提供 transitional 可用性。之后,一旦建立端到端路线,您就可以将可用性升级为 required 或 optional。如果您尝试使用 optional,工具和诊断程序会抱怨客户端组件的父级缺少 Echo2 的功能路由,而 transitional 会抑制此类警告。

与目标相同

same_as_target 充当直通:它会导致可用性从路由的目标组件设置的任何可用性继承。这对于传递大量功能的中间组件非常有用,这样当目标中路由的 availability 发生更改时,来源中无需进行任何更改。

由于 use 功能的组件是其最终目的地,因此 same_as_target 不是 use 的有效选项。

可用性比较

各种可用性选项之间存在相对的“强度”顺序。从最强到最弱,顺序为:required > optional > transient。 same_as_target 不属于此范围,因为它是一个直通功能:same_as_target 功能路由的强度实际上等于它从目标继承的任何可用性。

将可用性从来源降级到目标是有效且在许多情况下都很有用的。例如,如果组件 X 向 Y 公开 required 功能,Y 可以选择将该功能 use 为 optional,也可以将该功能 offer 为 optional 给另一个子级。不过,从来源升级可用性是一种路由错误。如果发生这种情况,任何使用或路由该功能的操作都会失败,就像路由链不完整时一样。这是一个错误,因为这意味着您尝试对可用性建立比来源所保证的更强的保证。例如,如果某个组件的父组件将某项功能 offer 为 optional,那么该组件将该功能 use 为 required 就没有意义了,因为这意味着父组件已声明该功能可能不可用。

工具和诊断

设置可用性的主要作用是控制主机工具和诊断报告如何路由错误。简而言之,这意味着 availability 越弱,他们就越不严格。详细规范如下:

  • 如果 required 功能路由不完整、无效或以 void 结尾:
    • 审查会将此报告为路由错误。如果 build 配置要求此值通过,则会导致 build 错误。
    • component_manager 将在描述路由错误的组件的范围内记录 WARNING 消息。
  • 如果 optional 功能路由不完整或无效:
    • 审查会将此报告为路由错误。如果 build 配置要求此值通过,则会导致 build 错误。
    • component_manager 将在使用组件的范围内记录一条 INFO 消息,用于描述路由错误。
  • 如果 optional 功能路线以 void 结尾:
    • Scrutiny 不会报告错误。
    • component_manager 可能会记录 INFO 消息,但不会记录错误。
  • 如果 transitional 功能路由不完整、无效或以 void 结尾:
    • 系统不会记录任何错误或其他信息。

对于一般运行时行为,availability 没有影响。例如,假设某个组件尝试 use 其命名空间中路由已损坏的协议。如果协议的路由方式为 required 或 optional,最终结果将相同:

  • 相应协议将显示在组件的命名空间中。
  • 连接到功能的初始调用将成功(假设使用了标准单向 API,例如 Rust 中的 connect_to_protocol)。
  • component_manager 将尝试路由功能。最终,路由将失败,并且通道将关闭并显示 NOT_FOUND 墓志铭。

source_availability: unknown

cml 具有一项附加功能,可用于自动生成 required 或 optional void offer,具体取决于是否包含具有来源子声明的 cml shard。如需详细了解此功能,请参阅build 文档。

target_availability:未知

cml 具有一项附加功能,可用于省略 offer,具体取决于是否包含具有目标子声明的 cml 分片。如需详细了解此功能,请参阅build 文档。

示例

以下示例说明了本文档中介绍的概念。

在此示例中,有三个组件:

  • echo_client,它会尝试使用 echo_server 提供的各种协议
  • echo_server,提供了一些协议
  • echo_realm,echo_client和echo_server的父级,用于将它们链接在一起

我们来检查一下它们的 CML 文件:

// echo_client.cml
{
    ...
    use: [
        { protocol: "fuchsia.example.Echo" },
        {
            protocol: "fuchsia.example.EchoV2",
            availability: "transitional",
        },
        {
            protocol: "fuchsia.example.Stats",
            availability: "optional",
        },
    ],
}

// echo_server.cml
{
    ...
    capabilities: [
        { protocol: "fuchsia.example.Echo" },
    ],
    expose: [
        {
            protocol: "fuchsia.example.Echo",
            from: "self",
        },
    ],
}

// echo_realm.cml
{
    offer: [
        {
            protocol: "fuchsia.example.Echo",
            from: "#echo_server",
            to: "#echo_client",
            availability: "required",
        },
        {
            protocol: "fuchsia.example.Stats",
            from: "void",
            to: "#echo_client",
            availability: "optional",
        },
    ],
    children: [
        {
            name: "echo_server",
            url: "echo_server#meta/echo_server.cm",
        },
        {
            name: "echo_client",
            url: "echo_client#meta/echo_client.cm",
        },
    ],
}

请注意,如果省略 availability,则默认为 required。在这种拓扑中,行为如下:

  • echo_client将能够成功连接到 fuchsia.example.Echo。
  • echo_client 将无法连接到 fuchsia.example.EchoV2 或 fuchsia.example.Stats。
  • 工具和诊断不会记录错误。
    • fuchsia.example.Stats 没有错误,因为它是 optional 并路由到 void。
    • fuchsia.example.Stats 没有错误,因为它是 transient。

现在,我们来看看使用其他版本会发生什么情况:

// echo_client.cml
{
    ...
    use: [
        { protocol: "fuchsia.example.Echo" },
        {
            protocol: "fuchsia.example.EchoV2",
            availability: "transitional",
        },
        {
            protocol: "fuchsia.example.Stats",
            availability: "optional",
        },
    ],
}

// echo_server.cml
{
    ...
    capabilities: [
        {

            protocol: [
                "fuchsia.example.Echo",
                "fuchsia.example.EchoV2",
                "fuchsia.example.Stats",
            ],
        },
    ],
    expose: [
        {
            protocol: [
                "fuchsia.example.Echo",
                "fuchsia.example.EchoV2",
            ],
            from: "self",
        },
        {
            protocol: "fuchsia.example.Stats",
            from: "self",
            availability: "optional",
        },
    ],
}

// echo_realm.cml
{
    offer: [
        {
            protocol: [
                "fuchsia.example.Echo",
                "fuchsia.example.EchoV2",
            ],
            from: "#echo_server",
            to: "#echo_client",
            availability: "same_as_target",
        },
        {
            protocol: "fuchsia.example.Stats",
            from: "#echo_server",
            to: "#echo_client",
            availability: "optional",
        },
    ],
    children: [
        {
            name: "echo_server",
            url: "echo_server#meta/echo_server.cm",
        },
        {
            name: "echo_client",
            url: "echo_client#meta/echo_client.cm",
        },
    ],
}

现在:

  • echo_client 将能够成功连接到 fuchsia.example.Echo、fuchsia.example.EchoV2 和 fuchsia.example.Stats。
    • 每个路由虽然具有不同的 availability,但都是完整的,并且最终会到达一个真实组件。
    • 对于每条路线,源和目标之间的可用性通过了比较检查
  • 工具和诊断信息不会记录错误,因为所有路线都已完成。