RFC-0213:移除 devfs FIDL 多路复用

RFC-0213:移除 devfs FIDL 多路复用
状态已接受
区域
  • 驱动程序
说明

概述了在 devfs 中移除 FIDL 多路复用的推理和计划

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2023-03-28
审核日期(年-月-日)2023-03-17

摘要

此提案概述了移除 devfs 功能的流程,该功能可将多个 FIDL 协议复用到单个连接上。它解释了移除此功能为何能解锁新的驱动程序功能,并使驱动程序 FIDL 连接与其余 Fuchsia 标准化。

设计初衷

驱动程序框架用于管理硬件设备与客户端之间的连接。从历史上看,此连接曾用于提供以下三种 FIDL 协议:

  • fuchsia.io/Node
  • fuchsia.device/Controller
  • 设备的实际 FIDL 协议

此多路复用要求驱动程序框架拥有通道,以便它可以提供节点和控制器协议。这样可以防止底层驱动程序拥有该渠道。此设计意味着驱动程序框架必须在驱动程序和驱动程序宿主之间保持 C FIDL 边界。这也意味着驱动程序无法区分多个连接或存储每个连接的状态。此限制导致出现了许多“跳板协议”,即驱动程序和客户端交换一对新通道只是为了避免多路复用通道的协议。

这种多路复用违反了 FIDL 关于组合的设计原则。FIDL 设计原则规定,协议可以在编译时成为多个协议的 composed。不过,驱动程序框架在运行时执行此组合,并且不知道设备正在使用的 FIDL 协议。运行时多路复用还可能会导致被多路复用的协议中出现冲突的序号。

控制器协议的多路复用意味着无法使用功能路由来限制对 fuchsia.device/Controller 的访问。例如,/dev/class/input-report 的客户大多希望访问 fuchsia.input.report/Device。不过,fuchsia.device/Controller 在同一渠道上提供,因此能够对这些设备进行解除绑定、重新绑定或设置电源状态。当设备的 FIDL 和控制器的 FIDL 在同一通道上多路复用时,无法解决此路由问题。

在整个代码库中使用节点协议的多路复用来克隆与设备的连接。虽然克隆设备连接的概念没有问题,但底层驱动程序并不知道此功能。此外,fuchsia.io/Node.Clone 的 API 接受 fuchsia.io/Node 的服务器端,因此使用此 API 克隆设备的渠道会谎报渠道的底层类型。目前有大量客户端代码通过直接调用 FIDL 或使用文件描述符来执行此操作。Fuchsia 在使用类型化渠道方面有既定的最佳实践,我们应在此方面强制执行这些最佳实践。

利益相关方

辅导员

  • abarth

审核者

  • abarth
  • cja
  • csuter
  • surajmalhotra
  • tamird
  • yifei

已咨询

共同化

此 RFC 最初是一份设计文档,并已通过驱动程序框架团队的设计审核。

要求

要求分为两类:迁移和最终状态。

Migration

迁移计划必须是具有许可名单的软迁移。Fuchsia 包含大量与树内和树外驱动程序客户端互动的代码。无法一次性从所有 devfs 中移除多路复用。 通过包含离散任务的许可名单,我们可以逐步取得进展,并防止迁移出现倒退。

迁移应尽可能机械化。每次客户端更新都应足够简单,以便不熟悉驱动程序或驱动程序框架的人员也能执行迁移。每次更新的机械化程度越高,迁移速度就越快。

结束状态

与设备的连接应明确。应明确客户端是请求设备控制器还是底层设备协议。不会有 FIDL 多路复用,因此客户端将能够使用类型化通道。

驱动程序框架不会在与设备的连接上提供 fuchsia.io/Node

司机将能够自行与客户建立联系。移除 FIDL 多路复用后,将进行另一次迁移,以将驱动程序移至 DDK API。每当客户端尝试连接时,该 API 都会为驱动程序提供一个通道。此次迁移将允许驱动程序具有每个连接的状态,并使用 Fuchsia 代码库其余部分使用的 FIDL 绑定。

设计

正在连接到 fuchsia.device/Controller

为了连接到 fuchsia.device/Controller,客户端将必须打开 devfs 文件系统中的特定节点。此节点将命名为 device_controller,并且在 devfs 类路径和 devfs 拓扑路径中均可用。

如果客户端从 /dev/class/input-report/abcd 获取设备协议,则控制器将在 /dev/class/input-report/abcd/device_controller 中可用。

如果客户端从 /dev/sys/platform/pci/00:12 获取设备协议,则控制器将在 /dev/sys/platform/pci/00:12/device_controller 中可用。

从 /dev/class/ 中移除了多路复用

将有两个 devfs 类路径许可名单:一个用于 fuchsia.io/Node,另一个用于 fuchsia.device/Controller。这些许可名单将包含仍在多路复用相应协议的 /dev/class/{protocol} 的名称。

在客户端更新为不再依赖多路复用行为后,此许可名单中的条目将被移除。

从拓扑路径中移除多路复用

当从许可名单中移除某个类路径的条目时,拓扑路径中的相应条目也会移除多路复用。

例如,如果 /dev/class/input-report 移除了 fuchsia.io/Node,则与这些输入设备对应的拓扑路径也将不再提供 fuchsia.io/Node

实现

许可名单将在驱动程序框架中实现。从许可名单中移除条目将需要更新依赖于此多路复用的客户端。

性能

移除 FIDL 多路复用不应造成显著的性能影响。由于发送到设备的 FIDL 消息不需要尝试调度到 Node 或 Controller API,因此性能可能会略有提升。

工效学设计

驱动程序框架可能会决定添加一个用于连接到控制器 API 的辅助库。这取决于前几次迁移。

如果客户端尝试在设备上调用未知的 FIDL 协议,驱动程序框架也会更新为记录错误。这意味着,如果客户端错误地仍依赖于多路复用,则会生成 ERROR 日志。遗憾的是,很难将错误日志正确归因于特定客户端。

向后兼容性

无法移除 FIDL 多路复用并保持向后兼容性。

安全注意事项

此提案没有安全方面的考虑因素。这项工作可能会通过使客户端行为更加明确和易于理解,略微提高 devfs 的安全性。

将来,驱动程序框架将需要限制对 fuchsia.device/Controller 的访问权限。例如,获得 /dev/class/input-report 访问权限的客户端无需访问控制器协议。限制此功能可提高安全性,而移除 FIDL 多路复用功能可让驱动程序框架能够在未来限制此功能。限制此协议的实际方案不在本 RFC 的范围内,可以作为后续项目进行处理。

隐私注意事项

此提案没有隐私权方面的注意事项。

测试

将测试许可名单和移除多路复用的驱动程序框架功能。

遗憾的是,每次移除许可名单都必须依赖 CQ 中的现有测试覆盖率。由于这种多路复用发生在 FIDL 类型系统之外,因此没有好的方法可以静态确定哪些客户端依赖于多路复用行为。

文档

我们添加了文档,以公开项目页面的形式呈现。此页面概述了许可名单、动机和更新步骤。项目完成后,将没有任何客户端依赖此行为,因此无需任何文档。

缺点、替代方案和未知因素

在 DFv2 中使用服务功能

目前,除了立即执行此工作之外,主要替代方案是等待驱动程序作为组件 (DFv2) 的工作完成,然后直接将客户端迁移到使用服务功能

不过,在所有可能的板上启用 DFv2 之前,无法开始将客户端迁移到服务功能。与此同时,将添加更多依赖于多路复用的客户端,包括更难迁移的树外客户端。此外,DFv1 兼容性 shim 需要支持 FIDL 多路复用,以便保留现有行为;将自身导出到 devfs 的 DFv2 驱动程序也需要支持多路复用。从 DFv1 中移除此技术债务将简化 DFv2 设计,而无需将此技术债务延续到 DFv2 中。

如果客户端还需要同时解开 FIDL 多路复用,则将客户端迁移到服务功能会更加困难。如果一次修复一个问题,这些迁移会更快完成。

在先技术和参考资料

FIDL 概述了协议组合的最佳实践