RFC-0147:View 系统 | |
---|---|
状态 | 已接受 |
区域 |
|
说明 | 介绍了 Fuchsia 平台的窗口化系统,并确认了其在平台中的作用。 |
问题 | |
Gerrit 更改 | |
作者 | |
审核人 | |
提交日期(年-月-日) | 2021-11-03 |
审核日期(年-月-日) | 2022-01-05 |
摘要
本文档简要介绍了 Fuchsia 视图系统:一组用于推理和与视觉区域(“视图”)及其生命周期交互的 API。在其他平台上,这组功能通常也称为窗口系统。此 RFC 的范围仅限于具有单个显示屏的商品。未来的 RFC 将介绍为适应无头设备和/或多个显示屏而进行的更改。
View 是图形内容的区域,是 Fuchsia 上图形和用户互动的基本单元。视图会连接起来形成视图树层次结构,其中包含一个显眼的根视图。Fuchsia 的图形合成器 Scenic 会渲染 View 树中的每个 View 中的图形内容,以便为显示屏生成输出。Scenic 和输入流水线负责将界面定位的用户输入(例如键盘、鼠标和触控)路由到正确的 View。
视图系统是 Fuchsia 平台支持“自带运行时”的关键部分,也是产品开发者使用来自多个运行时的图形内容在 Fuchsia 上构建安全的视觉用户体验的机制。Fuchsia 的组合 API(Flatland 和 GFX)基于 View 系统构建。
设计初衷
此 RFC 的目标是记录和批准与 View 系统相关的“世界状态”。具体而言,我们想批准以下决定。
- 如需在 Fuchsia 上显示图形,组件必须使用 View 系统创建 View。唯一的例外是 Virtcon 和 Recovery 界面等单窗口实用程序界面,它们不使用窗口化功能,并且设计为在 Scenic 未运行且资源有限的情况下运行。这些界面会直接与显示屏控制器通信。
- 视图系统是组件与 Fuchsia 平台对用户触摸、鼠标和键盘以及无障碍服务的支持集成的唯一方式。
- 视图系统不依赖于所使用的组合策略(GFX 与 Flatland),并为 Fuchsia 上的所有合成器实现提供了共享基础。
如需修改这些决策,需要额外的 RFC 和/或对此 RFC 进行更新。
利益相关方
教员:
hjfreyer@google.com
审核者:
此部分预计会在审核期间更新
- 图形:reveman@google.com、jjosh@google.com、emircan@google.com
- 输入:quiche@google.com
- 组件:ypomortsev@google.com
- 安全团队:kostyak@google.com
- 常规问题:wez@google.com
咨询了:
sanjayc@google.com、hjfreyer@google.com、jjosh@google.com、lindkvist@google.com、 geb@google.com
社交:
草稿文档已发送给 Scenic 和输入团队进行讨论。
术语库
- 风景
- Fuchsia 平台中的图形合成组件
- View 系统 API 的唯一实现方,包括与图形组合 API 和 HCI API 的集成。
- 查看
- 图形内容的视觉区域。
- 它具有坐标系、边界框,并通过视图树与其祖先定义了空间关系。
- 查看树
- 系统中视图的结构,通过父子关系相连。View 树的根 View 通常附加到显示屏。
- 显示屏
- 基于像素的输出设备;也称为屏幕。View 系统目前支持一次连接到系统的屏幕数量为 1。
- 屏幕通过显示屏控制器进行管理。
- 显示控制器
- 用于管理连接到计算机的显示屏的驱动程序。
- 仅与 Scenic 对话。
- 不适用于树外客户端。
- 场景管理器
- 用于将根视图附加到屏幕的平台组件。
- 无障碍功能管理器
- 用于实现无障碍功能 API 的平台组件。
- 它对 View 系统具有特许访问权限。
- 系统 shell(“Sys UI”“System UI”)
- 开发者 Shell(“功能块”“present_view”)
- 用于测试的系统 shell。通常,这允许开发者单独启动 Fuchsia 组件。
- 界面客户端
- 这是引用 View 所有者的通用方法,在本 RFC 中会被使用。
- 示例:Flutter 应用、具有多个顶级 View 的 Chromium。
设计
View 的定义
Fuchsia View 是 Fuchsia 上图形和交互的基本单元。View 用于定义用于向用户显示图形内容的可视区域。并非所有视图都会在给定时间显示。每个 View 的图形内容由 Fuchsia 组件提供。Scenic 实现了平台对管理 View 和将其内容合成到屏幕上的支持。
每个视图:
- 可以纳入其他 View(其子 View)的内容,从而形成 View 树。
- 定义用于放置子内容的坐标系。
- 具有边界框,用于定义该 View 的可见(可选互动)部分。
- 可以与全景视图树连接和断开连接。(未连接的 View 可能存在,但其内容不会呈现到屏幕上,也不会接收输入。)
Scenic 支持的任何图形合成 API(例如 fuchsia.ui.composition 和 fuchsia.ui.scenic)都必须提供用于创建 View 和管理其生命周期的方法。所有未来的组合 API 也必须在 View 系统之上运行。Fuchsia 平台 HCI API(例如指针和键盘)使用 View 来路由输入。(如需了解详情,请参阅下文中的输入部分。)
视图树
有一个全局 View 树,由 Scenic 拥有和实现。View 树有一个与屏幕关联的特殊根 View。Scenic 是唯一一个直接操控所有 View 及其位置的 Fuchsia 组件。
视图树中的每个视图都有在其自己的坐标系中定义的边界,以及在父视图的坐标系中表示的位置和方向。这些因素共同决定了图形内容最终在屏幕上显示的区域,以及响应用户输入的区域。
子视图
一个 View 可以通过在其坐标系中为另一个 View 创建一个空占位符来嵌入其他 View 中的其他图形内容;该占位符称为视口。这两个 View 在 View 树中形成父子关系,其中父 View 的 Viewport 嵌入了子 View 的图形内容。如需建立这种关系,父级和子级必须在创建 View 和 Viewport 时提供匹配的令牌。这些令牌以内核对象的形式实现,无法克隆。父级和子级可以通过 View 系统之外的多种方式获取这些匹配令牌。
将父级 View 附加或分离到 View 树中也会附加/分离其子 View。即使子树从全局视图树中分离,子树中的视图之间的连接也会保留。
视图隔离
虽然 View 可以嵌入其他 View,但 View 系统不会向 View 授予对任何其他 View 的图形内容的访问权限。这种隔离保证是视图安全的基础之一。
将风景地图视图投影到屏幕上
Scenic 是与显示屏控制器通信的唯一组件。它会获取整个 View 树的图形内容以及树中编码的关系,然后创建单个图片(可能包含多个图层)。然后,它会对硬件进行编程,以显示最终的屏幕图像。
查看所有权
视图中的内容由单个 FIDL 通道提供给图形组合 API,该 API 由 Scenic 实现。指向 Scenic 的 FIDL 通道的每个客户端端点都称为“界面客户端”,并且界面客户端最多只能创建一个 View。
视图可以来自各种组件,包括面向用户的组件(例如浏览器)、系统界面,以及 Fuchsia 平台的组件(例如无障碍功能管理器)。一个组件可以创建多个通道,从而创建多个 View。因此,在某些情况下,单个组件可以同时出售父视图和该视图的子视图。
为了组合来自多个组件的图形,开发者应在每个组件中创建一个或多个 View,并使用子 View 和 View 树将它们组合起来。请务必注意,视图树层次结构无需与组件实例层次结构一致。在许多情况下,这些结构会刻意看起来完全不同。
Runtimes
对于使用高级语言(例如 Dart 或 JavaScript)编写的组件,运行程序实现通常负责创建和管理 View。使用这些语言的开发者可能不知道底层操作系统的许多细节;运行程序有责任将 View 生命周期转换为特定于语言或特定于运行时的机制。
窗口管理与窗口系统与组合
Fuchsia 会将其他平台上有时会合并的三个功能分开。
- 窗口管理包含产品专用政策,以及有关窗口行为方式的具体选项。在 Fuchsia 中,系统界面负责执行此操作,并且完全位于平台之外。
- 窗口化系统是指低级窗口管理。在 Fuchsia 上,此操作由 View 系统处理。
- 合成是指将来自多个来源的图片组合起来,以生成要显示的图片。这目前也是 Scenic 组件负责的工作,但未来可能会发生变化。
选择将窗口系统和组合分开,可为图形呈现提供快速路径,并实现高效的实现。虽然 View 系统和合成器目前主要在 Scenic 中实现,但它们在 API 和代码方面是分开的。这种分离使得 View 系统能够支持多种组合策略(Flatland 和 GFX)。
通过将窗口管理作为产品级问题,我们将政策逻辑保留在平台之外,确保平台与产品之间清晰分离。
输入
视图系统是 Fuchsia 平台确定如何路由用户输入(例如指针事件或键盘事件)的主要机制。Fuchsia 的用户输入 API 的设计方式使得每个通道都限定在特定 View 中。系统会根据当前的视图焦点(对于键盘事件)和/或与输入事件位置对应的视图(对于触摸或鼠标事件)将输入路由到视图。只有在连接到 View 树后,View 才能接收用户输入。
多个 View 可以参与同一事件的输入处理。特定产品的窗口管理器可以根据产品政策配置此路由,例如向系统界面授予对鼠标事件的全局访问权限。如需了解更多详情,请参阅用户输入架构。该系统可在来自多个运行时的 View 中提供无缝的用户体验,包括能够对触摸手势进行解析。
这有一个重要的含义,即 Fuchsia 平台之外的组件无法直接访问来自驱动程序的输入事件。它们必须通过 View 系统接收此类信息。
视图焦点
在任何给定时间,视图树都有一个特殊的视图,称为聚焦视图。聚焦的 View 通常是用户希望接收用户输入的 View。Fuchsia 的输入子系统依赖于 View 焦点来确定将输入路由到何处。如需了解详情,请参阅焦点链文档。父 View 所有者可以控制其子树中的 View 焦点。
ViewRef
该平台使用名为 ViewRefs 的令牌来标识和传达视图。ViewRef 是对特定 View 的唯一引用,在系统重新启动之前保持唯一性。它以内核对象的形式实现,其句柄可以自由复制,并通过任意协议发送到其他组件。
View 系统 API 大量使用 ViewRef 来为每个 View 提供稳定的跨组件引用。ViewRef 还用于发送与关联 View 相关的生命周期事件。这样,平台内外的其他组件就可以就 View 及其生命周期进行通信,并将用户输入和无障碍功能协议路由到 View。
实现
Scenic 是 View 系统的权威来源,因为 View 树和核心 View 管理 API 都是在 Scenic 中实现的。每个客户端都会使用其 ViewRef 进行注册,以接收关联 View 的用户输入和无障碍功能事件。Scenic 目前支持两个图形合成 API:fuchsia.ui.scenic(旧版)和 fuchsia.ui.composition(正在开发中)。View 系统独立于它们,但与它们密切相关。
API 实现细节不在本 RFC 的讨论范围之内,但您可以在下方找到相关 API。值得注意的是,这些 API 在数年间逐步演变。未来可能会简化某些方面。
视图系统中涉及的平台组件
- 风景
- 输入管道
- 场景管理器(在旧版系统上为根呈现程序)
- 无障碍功能管理器
- 文本管理器
用于 View 管理的 API
- fuchsia.ui.views
- 查看引用、查看令牌定义
- 查看焦点管理
- fuchsia.ui.composition
- 创建视图、移动视图、调整视图大小、连接/断开视图
- fuchsia.ui.policy
- 将系统界面视图连接到根视图
- fuchsia.ui.app.ViewProvider
- 通过组件创建 Surface View
- fuchsia.web.Frame
- 创建 Web 客户端视图
用于用户输入的 API
- fuchsia.ui.pointer
- 指针事件
- fuchsia.ui.input3
- 键盘输入
- fuchsia.ui.shortcut
- 键盘快捷键
无障碍功能 API
- fuchsia.accessibility.semantics
- 允许 View 发送语义信息以实现无障碍功能
- fuchsia.ui.annotation
- 允许无障碍功能突出显示聚焦的界面组件
性能
View 系统的许多方面都会影响图形和输入性能。下面介绍了一些重要方面。
- 所有运行时都是平等的:Fuchsia 的自行提供运行时原则意味着 Fuchsia 上的所有运行时都使用相同的事件路由,并且没有任何运行时会获得优先待遇。
- 一次渲染:借助 Scenic,您可以组合不同 View 的图形内容,而无需重新渲染,因为它知道 View 位置,并且可以正确将图形内容转发给显示驱动程序。
- 高效调度:Scenic 会公开焦点信息,从而允许直接从处理非图形用户输入(例如键盘事件)的组件调度这些输入。
安全和隐私权注意事项
View 系统提供了多项保证,可确保在 Fuchsia 上安全地组合图形内容,这些保证构成了安全用户体验的基础。不过,仅 View 系统无法保证每种用户体验都安全无虞,只能保证 View 系统遵守自己的安全保证。
View 系统会通过以下方式尝试实现安全的用户体验:
- 将拥有和操控 View 树的全部责任委托给 Scenic。
- 将在屏幕上显示图形内容的全部责任委托给 Scenic。
- 禁止界面客户端在没有匹配的 Viewport 或 ViewRef 的情况下操控其他 View。
- 禁止界面客户端使用 View 系统检查任何其他界面客户端 View 的内容。
- 仅允许界面客户端向其 View 子树注入输入。
- 仅允许在连接到视图树后,视图才能获得焦点并接收输入。
界面安全性依赖于组件框架针对 capability 路由提供的保证。我们将在未来的 RFC 中介绍 View 安全的详细信息。
测试
视图系统在多个抽象层中实现,因此需要采用分层方法进行测试。
在 fuchsia.git 中:
- Scenic 组件代码库中的 View 树和 View 生命周期的单元测试。
- /src/ui/tests 中的界面集成测试,用于演练 View 系统 API 周围的合约。
- 这些 API 由 Scenic、SceneManager、输入流水线、无障碍功能管理器和文本管理器等平台组件提供和使用。
- fuchsia.ui.observation.test API 用于在树内集成测试中检查 View 系统行为。
外部树:
- Chromium 和 Flutter 等运行时会编写集成测试来运行 View 系统 API
- 产品编写端到端测试,以间接调用 View 系统。
文档
本文档简要介绍了 View 系统的角色和职责。我们将编写文档和可能还有其他 RFC 来阐明详细信息。
鉴于此 RFC 和 Flatland 即将发生的变更,部分 Scenic 文档也需要更新。
缺点、替代方案和未知情况
已知限制
View 系统目前缺少用于在多个 View 之间同步更新的机制。
View 系统负责将功能路由到公开 View(使用 ViewRef)的运行时。这在概念上与通过 Fuchsia 的组件框架进行 capability 路由有一定重叠,但目前完全是分开的。未来,在组件框架中支持 View 功能可能会很有用。
当前的 API 仅允许 View 所有者创建子 View。对于希望创建多个顶级窗口的应用,这种方式并不理想。
由于 View 系统 API 在多年来由许多不同的贡献者自然演变,因此运行时开发者的认知负担目前非常高。我们日后会通过提供更完善的文档和示例,以及可能简化 API 来缓解这一问题。
替代方案
View 系统架构提供了多种架构选项。
- 任何包含图形的商品都必须提供 View 系统。
- 或者,Scenic 可以是可选的,产品可以包含自己的 compositor。这需要在树外公开许多低级 API。
- 当前方法的优势:
- 跨运行时的一致行为(包括无障碍功能和输入)
- 一致的安全保障
- Display API 可以不断演变,而不会破坏客户端
- 目前方法的缺点:
- 产品自定义功能较少
- 运行时集成的复杂性
- 如果基于 Fuchsia 构建的产品需要,这种情况未来可能会发生变化。
- View 系统分布在多个组件中,包括 Scenic 和输入流水线。
- 或者,我们也可以将整个 View 系统构建到 Scenic 中。
- 当前方法的优势:
- 分离关注点:图形组合、窗口管理、产品政策都是分开的。
- 允许通过委托组合实现高性能图形路径
- 与界面相关的组件可以独立演变
- 即使子系统(例如文本输入)崩溃,图形也能继续正常运行
- 当前方法的缺点:
- 多个进程可能会通过 IPC 增加延迟时间
- 增加了组件之间的协调/同步复杂性
在先技术和参考文档
- View 系统和 Scenic 在架构上与 X Windows 系统有相似之处。
- 其他方面与 Wayland 协议有更多相似之处。
- 输入架构 RFC 详细介绍了 View 系统如何与 Fuchsia 的用户输入子系统进行交互。