RFC-0155:可选功能路由 | |
---|---|
状态 | 已接受 |
领域 |
|
说明 | 优惠中添加了一个新字段,并使用组件清单的各个部分来指明给定功能可能不存在的情况。 |
问题 | |
Gerrit 更改 | |
作者 | |
审核人 | |
提交日期(年-月-日) | 2022-02-07 |
审核日期(年-月-日) | 2022-04-14 |
摘要
优惠中添加了一个新字段,并使用组件清单的各个部分来指明给定 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
功能的组件。这对于开发很有用,但不应将此组件添加到 user build 中。
以上场景是我们今后要支持的组件配置,但目前组件框架中有一些位置存在与此相关的粗糙边缘:
- 如果通过清单中不存在的组件提供或来自该组件,会导致清单验证失败。
- 如果通过未提供该功能的组件提供某项功能,则会导致审查验证失败。
- 功能路由失败(例如,尝试使用未提供的功能)会导致组件管理器(正确)发出警告级日志,这看起来可能令人担忧,因此在调查故意省略该功能的产品的问题时具有误导性。
通过集合进行路由验证
审查是一种组件路由验证工具,可确保给定组件树中使用的所有功能都具有有效的功能路由。除了它提供的系统正确性断言之外,这是一款实用的开发工具,因为它可以将路线验证从运行时验证转移到构建时,从而缩短开发周期。
目前,维护的许可名单用于禁止对特定功能路由进行审查检查。这样,当组件使用某个不可用的 capability 时,构建就能成功。不过,如果相应功能可用的 build 上的功能路由配置有误,这也会导致构建成功。
此外,在 https://fxbug.dev/42174612 解决后,审查功能还将验证源自会话领域的功能路由。通常,会话组件依赖于来自会话外部的功能,如果其中有一个组件希望添加到审查许可名单中,这会增加阻力,因为这些组件可能是在 fuchsia.git 之外开发的。
利益相关方
谁能决定此 RFC 是否被接受?(此部分为可选内容,但我们建议您。)
教员:Hunter Freyer (hjfreyer@google.com)
由 FEC 指定的人员,负责通过 RFC 流程照管此 RFC。
审核者:
- 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
,这意味着该组件希望提供该功能,如果该组件不可用,则可能会发生故障。此 RFC 未建议对 required
功能的行为进行任何更改,它们的行为方式与目前所有功能的行为相同
{
use: [
{
protocol: "fuchsia.logger.LogSink",
availability: "required",
},
{
directory: "config-data",
path: "/config",
rights: [ "r*" ],
// The `availability` field defaults to `required` when omitted.
},
],
}
使用声明中的 availability
字段也可设置为 optional
,以反映在功能不可用时组件可以正常工作的时间(可能出现行为被修改)。
{
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",
},
],
}
使用声明是可选的,可以通过现有组件或“void”提供。需要声明使用声明的功能可能无法在无效时提供,因为这可能会导致组件出现故障。
中间优惠(从父优惠到子优惠)也可以将 availability
字段设置为以下值之一:
required
(默认值):无论子项是否可以处理其缺失行为,都必须获得对此功能的访问权限(不能在祖先实体中通过 void 提供该功能)。optional
:子级必须能够处理没有此功能的情况(优惠链末尾的使用声明必须是可选的)。same_as_target
:优惠将具有与目标相同的可选性。如果目标需要该功能,则此优惠会规定目标必须获得该功能。如果目标可以选择是否使用该功能,则此优惠会规定目标不一定获得此功能。
{
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,则会发出构建时错误。此字段可以未设置,在这种情况下,会被忽略。
核心领域组件
如 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
的清单和核心领域分片将如何根据提议的设计发生变化。
fuchsia.location.sensor.WlanBaseStationWatcher
协议的优惠将从 emergency.core_shard.cml
移至 wlancfg.core_shard.cml
,并且 source_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",
},
],
}
现在,当 build 中不包含 emergency.core_shard.cml
文件时,由于 wlancfg
无法访问 fuchsia.location.sensor.WlanBaseStationWatcher
协议,构建时将不会发生构建时错误。这意味着该协议可能会从审查的许可名单中移除,如果任何配置错误导致该协议在平台配置(若该协议可用)上无法供 wlancfg
使用,则会导致构建时错误。
会话中具有可选功能的组件
在此示例中,我们来看看根据提议的设计,将 fuchsia.power.battery.BatteryManager
协议从 /core/battery_manager
转换为 /core/session_manager/session:session/workstation_session/login_shell/ermine_shell
所涉及的清单和核心领域分片将如何变化。
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",
],
}
无需更改 core
和 ermine_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
,而不会造成构建时审查错误,也不会将此功能添加到许可名单中。这意味着,可以在无电池的硬件上运行工作站会话的平台配置安全地排除电池管理器组件。
会话所有者希望确保某个可选 capability 始终始终
可用
以前面的示例为基础,考虑一个名为 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
可以选择使用该协议。
会话所有者想确保组件能够处理缺少
可选功能
同样在“ermine”示例的基础上进行构建。如果工作站会话的所有者希望确保 ermine
始终能够处理缺少 fuchsia.power.battery.BatteryManager
协议(无论协议当前是否可用)的情况,他们可以将此协议作为 optional
提供给 ermine
。BatteryManager
// 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 被更改为需要此功能,那么审查时将会发出构建时错误,无论功能路由是否有效或是否以“void
提供的优惠”结尾。
实现
为了实现这些更改,必须更新 fuchsia.component.decl.Component
FIDL 表和 CML JSON 架构以包含新字段,同时更新 CMC、cm_fidl_validator
和审查,以正确处理“设计”部分所述的 optional
语义。
性能
建议的更改不会对构建时间或大小产生任何显著影响,因为在这些清单中携带额外枚举的成本很低。此外,在组件管理器中提议的运行时行为更改不会对性能产生任何显著影响,因为在此项工作开始时,实现新命名空间组合逻辑所需的信息就全部存储在内存中。
工效学设计
对于当前需要与许可名单互动的任何组件作者来说,这项变更应该会显著提升工效学设计,以抑制审查验证错误,因为我们将改进预期验证错误的上下文,使审查完全不会发出这些预期错误。
向后兼容性
此更改纯粹是对 FIDL 表和 JSON 格式的补充,因此没有向后兼容性问题。
安全注意事项
通过这项变更,组件作者无需获得安全团队的批准即可停用未路由功能的审查错误,因为许可名单将不再用于控制对未路由功能的审查错误抑制。
这种做法被认为是可以接受的,因为此提案没有更改创建或更改组件路由本身的审核流程。
隐私注意事项
建议的更改不会影响用户数据的收集、处理或存储方式,因此没有任何隐私问题。
测试
已经有广泛的测试,涵盖组件清单流水线。这些测试将改为包含这项新功能的覆盖范围。
文档
我们将更新组件清单文档,以说明新字段及其对验证的影响。
缺点、替代方案和问题
现有艺术和参考资料
TODO