| RFC-0189:窗口管理 | |
|---|---|
| 状态 | 已接受 |
| 区域 |
|
| 说明 | 描述了窗口管理的平台架构和标准 API。 |
| 问题 | |
| Gerrit 更改 | |
| 作者 | |
| 审核人 | |
| 提交日期(年-月-日) | 2022-08-12 |
| 审核日期(年-月-日) | 2022-09-20 |
摘要
此 RFC 提出了一种模型,用于说明 Fuchsia 平台、产品会话和会话 shell 如何协同工作以支持具有多个窗口的复杂图形应用。具体而言:
- 虽然平台负责将图形显示在屏幕上并路由输入的机制,但产品组件必须指定产品特定的政策,以确定何时以及如何显示图形。
- 平台将定义一个用于窗口管理的标准化 API 表面1,以最大限度地提高应用和产品之间的兼容性。
由此产生的一个重要结果是,应用会与 Fuchsia 平台集成,而不是与特定的 Fuchsia 产品集成,因此,与某个 Fuchsia 产品兼容的应用也应与支持相同窗口管理功能集的任何其他 Fuchsia 产品兼容。具体而言,针对某个 Fuchsia 桌面产品运行的应用应能针对任何此类产品运行,无论具体的产品会话或系统 shell 实现如何。
此 RFC 扩展了 RFC-0092:会话。它描述的是计划状态,而不是当前的工作方式。此 RFC 中描述的方法取代了之前的所有尝试(模块化、会话框架),并且是未来的记录计划。
设计初衷
目前的 Fuchsia API 使产品和应用难以实现丰富的窗口管理和多窗口应用。平台和产品责任之间的区别令人困惑,并且平台提供的 API 源自 Fuchsia 愿景的早期,缺少当前工作(例如工作站)所需的一些重要功能。之前曾多次尝试解决此问题及相关问题(模块化、会话框架),但没有一个完全在所有 Fuchsia 表面上实现。
当前系统状态缺乏明确的职责划分,并且有多种方式可以执行相同的操作。这导致了不同产品之间的碎片化。现在批准该架构可让我们在未来就平台将支持的 API(例如,可能采用 Wayland 在 Fuchsia 中使用)做出决策,并为 shell 和应用解除开发限制。
此 RFC 可能是涵盖窗口管理不同方面的一系列 RFC 中的第一个。其目标是明确产品和平台之间的划分,并让您更轻松地做出后续决策,确定要使用的确切 API(例如 Wayland)。
利益相关方
Facilitator: abarth@google.com
审核者:
- Graphics: dworsham@google.com
- 工作站:sanjnyc@google.com
- Architecture:abarth@google.com
- 组件框架:thatguy@google.com
- Chrome:wez@google.com
- 用户体验:asz@google.com
咨询对象:quiche@google.com、jasoncampbell@google.com、geb@google.com、masonben@google.com、jsankey@google.com、tjdetwiler@google.com
社会化:在通过 Gerrit 发布之前,此 RFC 的草稿已与利益相关者广泛分享和讨论。
定义
就本文档而言:
- 显示服务器(又称合成器):一种组件,负责允许应用组件创建和显示视图,允许控制这些视图的位置和大小,并确保根据应用组件的视图将图形输入事件传递给这些组件。在 Fuchsia 上,这是 scenic。
- 窗口管理器:一种控制应用提供的窗口的位置和外观的组件(或多个组件)。在某些系统上,此系统还负责渲染界面(例如标题栏)。 由于 Fuchsia 平台可用于实现各种具有截然不同的图形和输入功能的产品,因此 Fuchsia 上的窗口管理器职责分配可能与其他操作系统(其中平台与单一用户体验的关联更紧密)有很大不同。
- 系统 Shell:负责绘制产品界面的组件。此组件拥有视图层次结构的产品子树中显示视觉内容的顶部场景视图。此视图有时称为 shell 视图。系统 shell 负责在视图树中安装由应用组件提供的视图,并针对如何显示这些视图做出政策决策。
- 产品会话:负责实现 Fuchsia 产品体验的组件。此组件作为会话管理器的子级运行。此组件负责启动具有相应功能的应用组件,以响应用户操作。在撰写此 RFC 时,Fuchsia 每次仅支持一个会话。
- 元素:会话框架概念,指具有图形的组件。此 RFC 弃用了元素角色。
- 应用组件:实现图形用户体验并在系统 shell 中运行的组件。
- View Tree:Scenic 场景图中的视图层次结构。
设计
概览
Fuchsia 上的窗口管理主要有两个方面:机制和政策。
- “政策”是指有关哪些组件允许在屏幕上放置图形、这些图形的显示位置、它们如何接收输入和焦点以及它们在视图树中的相关性的具体产品细节。 政策是关于决定允许对窗口执行哪些操作。
- “机制”是指在屏幕上显示像素并将输入路由到其底层组件的机制,主要通过 Fuchsia 界面堆栈来处理。提供图形的所有组件都必须与这些 API 通信。政策决定的影响可能需要多次调用机制 API 才能对界面进行相关更改。
Fuchsia SDK 为窗口管理政策定义了两个 API 接口:
- 一个用于系统 Shell 的 API,用于实现其特定于产品的窗口管理政策,并提供有关此产品上可用的窗口管理器功能的信息。如今,这是通过要求系统 shell 实现图形演示者角色来实现的。
- 一种 API 或一组 API,供应用组件用来请求更改该组件所拥有视图的存在状态和外观。这是一种核心 API,所有应用客户端都应使用该 API,并且可能通过扩展来实现其他行为(可在运行时检测到)。此 API Surface 应在所有 Fuchsia 应用之间共享,从而有助于在基于 Fuchsia 构建的不同产品之间实现兼容性。
目前,客户端应用的实现细节差异很大。部分应用实现元素角色,而其他应用则直接与组件框架和 Scenic 互动,或在应用内实现元素管理器 API。此 RFC 强制要求简化此流程,为所有应用组件改用单个 API。
此 RFC 目前并未就系统 shell 和应用组件是否直接相互通信,或者平台组件是否应调解这些互动表达意见。
架构示意图

上图展示了在 Fuchsia 上运行的图形化产品的可能架构。产品会话负责启动系统 shell 和任何应用。应用和系统 shell 必须就任何政策决策进行通信,可能通过平台提供的窗口管理器或“桥接”组件进行通信(请参阅下文中的可能的平台桥接组件)。系统 shell 和应用还必须与 Fuchsia 平台界面堆栈(包括处理图形和输入处理的组件)通信,才能在窗口管理的“机制”方面执行操作。此通信也可能通过网桥组件进行。
产品会话职责
产品会话是产品启动时要启动的第一个特定于产品的组件。对于包含图形的产品,该角色还需承担以下责任:
- 产品会话负责启动应用组件并为其提供适当的功能,包括将界面显示在屏幕上所需的功能。
- 产品会话必须为用户体验提供根视图,可以通过直接实现此功能或将其委托给子组件来实现。提供此视图的组件也称为系统 shell(有时也称为系统界面)。系统 shell 具有一项功能 (fuchsia.session.scene.Manager),可用于在视图树中安装其根视图。(请注意,一个产品可能包含多个 shell,例如登录 shell 和用户 shell,并根据需要在这两者之间进行切换。)
- 商品会话负责窗口管理的商品政策方面。具体而言,会话必须实现 Fuchsia SDK 提供的窗口管理政策 API。此责任包括提供有关此产品上可用的窗口操作种类的信息。
组件层次结构示例

此图显示了用户体验的可能组件层次结构。请注意,这会移除元素管理器。如图所示,应用组件是产品会话的子级。某些产品可能会选择以不同的方式进行设置,例如在产品会话的 realm 中创建一个负责启动应用的组件,或者将应用组件实例化委托给具有不同功能的某个平台组件。
设置视图层次结构
启动后,应用可以联系 Scenic 来创建应用视图,然后通过窗口管理 API 联系系统 shell,以将该视图显示为系统 shell 用户体验的一部分。系统 shell 会联系 scenic,将应用视图安装到视图树中,通常作为根视图的子视图。
应用可以按照上述初始窗口创建流程打开第二个顶级窗口。其他窗口管理操作(例如调整应用视图的大小、启动弹出式窗口等)需要应用组件通过调用窗口管理 API 向系统 shell 请求这些更改。一般来说,每个组件都负责直接与 Scenic 通信,以了解其拥有的视图的内容。不过,如果视图所有者/应用希望更改视图的显示方式(例如调整大小、最小化或打开另一个顶级视图),系统 shell 必须以某种方式指示允许执行此操作。系统 shell 可以通过响应客户端 API 调用来执行此操作,也可以通过在视图树中存储信息来指明相应视图可以执行的操作,并允许 Scenic 执行相关政策。
注意:
- 生成的组件层次结构和视图树并不相同! 虽然应用视图必须是系统 shell 所拥有的视图的子视图,但应用组件不必是系统 shell 组件 Realm 的一部分。
- 此说明省略了有关视图创建的许多详细信息,包括如何通过视图树将用户输入等内容路由到视图。
视图层次结构示例

上图显示了运行多个图形应用的系统界面的示例视图树。系统 shell 视图是用户体验的根视图。请注意,视图树的父子关系可能与上面显示的组件层次结构不同。
窗口管理功能协商
并非所有系统 shell 实现都会公开相同的功能,因为系统 shell 在一定程度上实现了特定于产品的政策。因此,这些实现会因产品而异。例如,智能手表的界面可能非常简单,一次只能在屏幕上显示一个视图,而桌面设备则支持多个应用,这些应用具有多个重叠的窗口。有些产品支持通过触摸屏进行用户输入,而另一些产品仅支持鼠标和键盘。
对于“核心集”之外公开的特定于产品的能力,客户端必须能够发现当前产品支持哪些此类能力。这样一来,客户端就可以根据不同的产品调整其行为,并实现可在不同产品上运行的图形化 Fuchsia 应用。
同样,系统界面必须告知平台当前有哪些功能可用。
可能的平台桥组件
平台可能会引入一个“桥接”组件,用于协调客户端应用与系统界面之间的通信。此组件类似于其他平台上的窗口管理器,随后可以自动执行一些窗口管理“机制”操作,并减少开发者编写向 Fuchsia 界面堆栈发送低级命令的代码的需求。这样做的好处是,客户端可以通过单个 API Surface 与机制和政策进行通信,这在其他系统(例如 Wayland)中是一种常见模式。通过将桥接组件置于平台中,产品还可以共享窗口管理代码,避免类似功能的重复。
是否使用平台桥接组件/平台窗口管理器的决定留待未来的 RFC。
实现
此 RFC 解决了窗口管理的高级架构问题。由于我们预计未来 RFC 会对所涉及的 API 进行重大更改,因此许多实现细节应在这些 RFC 中解决。
当 API 就位后,此 RFC 意味着将移除许多针对系统当前缺陷的旧版变通方案。具体而言:
- 此 RFC 弃用了元素管理器(当前元素管理器功能成为产品会话的职责)。
- 此 RFC 批准了以下意图:规范应用的行为方式(不再需要 Chrome 特有的解决方法)。未来 RFC 中将介绍现有 API 的替代方案。
性能
虽然图形和用户输入处理对性能非常敏感,但打开新应用或窗口等窗口管理政策决策通常以“人类速度”发生,因此不需要与渲染或输入处理相同的性能水平。因此,在执行“控制”操作(例如打开新窗口)时,通常可以使用额外的 RPC。不过,在设计 API 时应谨慎,确保任何对性能敏感的流程(通常是涉及数据流的流程,例如将帧放置在屏幕上、路由用户输入)避免不必要的 IPC,并且不会不必要地阻塞客户端响应。在窗口管理器和 shell 不是同一组件的情况下,这一点尤其重要。即将发布的 RFC 中应详细说明特定 API 的性能影响。
动画和同步
为了给用户提供顺畅的体验,请务必确保界面操作(例如调整大小动画)可以在多个组件之间同步。虽然这在很大程度上取决于特定 API 及其关于原子性的保证,但架构可能会影响构建可实现此类同步的用户体验的难度。
此 RFC 并未正式采用特定 API,但其中包含的决策已针对 Wayland API 进行评估,该 API 的既定目标是实现“每个帧都完美”。在最终确定此 RFC 中描述的 API 时,同步问题将是一个重要的考虑因素。
安全性和隐私权注意事项
组件安全性
此 RFC 阐明了组件层次结构和视图层次结构不必相同,并允许应用作为产品会话的子级(而非系统 shell)启动,这在某些系统上可能不太稳定或不太安全。这样一来,产品可以更轻松地确保产品内的组件层次结构符合该产品的特定安全和隐私需求。
查看安全性
有关视图系统的安全保证,请参阅视图系统 RFC,其中详细介绍了相关信息。此 RFC 的一个重要保证是,视图只能在自身或其子项当前获得焦点时操纵视图焦点,并且与视图树断开连接的视图无法接收用户输入。这意味着,产品会话的系统界面视图安装和系统 shell 所做的窗口管理政策决策(例如为启动的应用安装子视图)也是关于哪些组件在任何给定时间有资格接收用户输入的决策。虽然平台无法保证所有产品都会实现安全行为,但视图系统为产品创建安全体验提供了构建块。
测试
平台应为所有窗口管理 API 提供一致性测试,以便产品和应用都能确保与 Fuchsia 平台的兼容性。这些测试可能会因特定应用或产品会话支持的窗口管理 API 扩展而异。
系统 shell 和应用开发者可以使用测试界面堆栈来编写集成测试,以测试其代码与 Fuchsia 平台界面堆栈的交互。
文档
此 RFC 以及后续处理 API 细节的 RFC 将需要对 fuchsia.dev 上的会话框架文档进行重大更新,以反映有关产品和平台之间拆分以及消除元素管理器的更新预期。
缺点、替代方案和未知因素
替代方案:Scenic 执行窗口管理
- 如果没有新的 API,系统 shell 就无法应用产品级政策/概念。
- 不清楚如何扩展此 API 以处理产品差异。否则,会将大量特定于产品的逻辑(例如“最小化”的含义)推送到平台中。
在先技术和参考资料
-
这些 API 将在后续 RFC 中定义。 ↩