为此,组件会在其清单中为每项功能指定 use
声明。
不过,由于capability 路由涉及一组组件,因此仅仅因为某个组件 use
是 capability,并不意味着它始终可用。它可能会因各种原因而不可用:例如,链中的某个组件未路由该 capability,或者其中某个组件未能解析。
当组件 use
或路由功能时,它可能对功能是否必须可用有不同的预期。在某些情况下,capability 对组件的运作至关重要:如果有人创建的拓扑结构未能将 capability 路由到组件,理想情况下,应尽早检测到该失败情况,以防止出现 bug。不过,在其他情况下,组件可能会容忍缺少该 capability,或者在某些配置中预计该 capability 会缺失。为了适应这些不同的场景,cml 在 use
、offer
和 expose
上提供了 availability
选项,组件可以使用该选项声明其对 capability 可用性的预期。
选项
该框架支持以下 availability
选项:
必填
最常用的 availability
选项是 required
,表示组件始终希望该功能可用,并且如果该功能不存在,则无法正常运行。如果未指定播出信息,系统会自动设置此默认选项。
可选
optional
表示某些配置可能不支持某项 capability。如果某个组件use
了某项可选功能,但该功能不可用,则该组件应能够在不使用该功能的情况下正常运行,例如通过停用需要该功能的所有功能。
不过,如果某个配置不支持 optional
capability,框架会预期拓扑中仍包含以 void
终止的 capability 的完整路由。这样,产品所有者应明确选择相应 capability 是可用(其路线在某个提供方组件处终止)还是不可用(其路线在 void
处终止)。如果路线不完整,工具和诊断将将其报告为错误。
过渡
transitional
类似于 optional
的较弱版本。与 optional
一样,如果组件使用 transitional
功能,则应对缺少该功能保持容错性。不过,与 optional
不同,transitional
路由不需要在 void
中终止,并且如果 transitional
路由不完整或无效,工具和诊断不会报告任何错误。
“过渡”这个名称意味着此选项适用于柔和的过渡。例如,假设您有一个 Echo
协议,想要将其替换为 EchoV2
。在此过渡的早期阶段,您可以更改客户端,以便在 transitional
可用时use
新协议。稍后,建立端到端路线后,您可以将可用性升级为 required
或 optional
。如果您尝试改用 optional
,工具和诊断会抱怨客户端组件的父级缺少 Echo2
的 capability 路线,而 transitional
会抑制此类警告。
与目标相同
same_as_target
充当透传:它会导致可用性从路由的目标组件设置的任何可用性继承。对于传递大量功能的中间组件,这非常有用,这样一来,当目标中的路线的 availability
发生变化时,源代码中就无需进行任何更改。
由于 use
某项 capability 的组件是其最终目的地,因此 same_as_target
不是 use
的有效选项。
可用性比较
播出信息选项之间存在相对的“强度”排序。从高到低的顺序为:required > optional > transient
。same_as_target
不属于此类别,因为它是透传:same_as_target
capability 路线的强度实际上等于它从目标继承的任何可用性。
在许多情况下,从源降级到目标的可用性是有效且有用的。例如,如果组件 X
向 Y
公开 required
capability,Y
可以选择将该 capability use
为 optional
,也可以将该 capability offer
为 optional
并将其传递给另一个子项。不过,从来源升级库存状况属于路由错误。如果发生这种情况,任何尝试使用或路由该 capability 的操作都会失败,就像路由链不完整时会失败一样。这是一个错误,因为这意味着您尝试建立比来源保证更强的可用性保证。例如,如果某个组件的父级将某项 capability offer
为 optional
,那么该组件将该 capability use
为 required
是没有意义的,因为这意味着父级已声明该 capability 可能不可用。
工具和诊断
设置可用性的主要作用是控制主机工具和诊断程序如何报告路由错误。简而言之,这意味着 availability
越弱,限制就越少。以下是详细规范:
- 如果
required
capability 路径不完整、无效或以void
结尾,请执行以下操作:- 审核会将其报告为路由错误。如果构建配置要求此测试通过,这将导致构建错误。
component_manager
会在使用组件的范围内记录WARNING
消息,以描述路由错误。
- 如果
optional
capability 路由不完整或无效:- 审核会将其报告为路由错误。如果构建配置要求通过此测试,这将导致构建错误。
component_manager
会在使用组件的范围内记录INFO
消息,以描述路由错误。
- 如果
optional
capability 路由以void
结尾:- 审核不会报告错误。
component_manager
可能会记录INFO
消息,但不会记录错误。
- 如果
transitional
capability 路径不完整、无效或以void
结尾:- 系统不会记录任何错误或其他信息。
对于常规运行时行为,availability
没有影响。例如,假设某个组件尝试 use
其命名空间中路线损坏的协议。如果协议以 required
或 optional
进行路由,最终结果将相同:
- 该协议将显示在组件的命名空间中。
- 用于连接到该 capability 的初始调用将会成功(假设使用的是标准单向 API,例如 rust 中的 connect_to_protocol)。
component_manager
将尝试路由该 capability。最后,路由将失败,并且系统会使用NOT_FOUND
墓志铭关闭该通道。
source_availability:unknown
cml 还有一项额外的功能,可用于自动生成 required
或 optional void
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
,但都是完整的,并会在真实组件中终止。 - 对于每条路线,源和目标之间的播出信息通过比较检查
- 虽然每个路由都有不同的
- 由于所有路线均已完成,因此工具和诊断功能不会记录错误。