RFC-0200:支持用于硬件测试的 adb 协议和接口

RFC-0200:支持 adb 协议和接口进行硬件测试
状态已接受
领域
  • 开发者
  • 测试
说明

添加了 adb 协议和接口支持,以使 Fuchsia 设备能够与库存 adb 客户端进行交互,以进行硬件测试用例。

问题
Gerrit 更改
  • 715977
作者
审核人
提交日期(年-月-日)2022-08-24
审核日期(年-月-日)2022-11-17

总结

此 RFC 提议为 Fuchsia 添加 Android 调试桥 (adb) 协议和接口支持,以进行硬件测试。这将使 Fuchsia 设备能够与库存 adb 客户端进行交互,该客户端在当前硬件测试工作流中有多个应用。借助 adb 支持,我们还可以从 Windows 主机发现 Fuchsia 设备并与之互动,而 Fuchsia 工具目前不支持该主机。此外,添加对 adb 的支持后,我们还可以重复使用围绕 adb shell 构建的大多数测试、工具和流程,以进行硬件验证和制造。为了添加 adb 接口支持,Fuchsia 的 USB 外围设备配置将更新为使用新的 adb 接口,该接口将在启用了 adb 的 build 中取代(或协同工作)现有的 USB CDC 以太网接口。adb 协议支持仅限于硬件验证和制造用例认为必需的功能。支持的 adb 服务将特定于 Fuchsia,不会尝试模拟 Android adb 服务。

设计初衷

在硬件验证和制造测试场景中,adb 支持非常有用:

  • 有几个围绕 adb 构建的工具、库和框架(123 以及更多)可以重复使用。
  • 适用于各种平台的 adb 客户端预构建二进制发行版广泛可用,并且易于设置。
  • 依赖于 adb 提供设备发现、连接和命令执行服务的现有测试框架无需进行任何更改即可正常运行。
  • adb 由于很受欢迎,并且其开源社区支持也很广泛,因此开发者非常熟悉 adb。
  • 它可以通过在当前不受支持的环境中建立通过网络连接来进一步扩展 ffx 的用例。适用于 Windows 的 adb 已经过充分测试且广泛使用,而且可以随时从 Google 获取 adb Windows 驱动程序,以进行安装。
  • adb 支持基于 USB 外设的发现和通信,与 目前 Fuchsia 中使用的基于 mDNS 的发现相比,延迟更低。 对于制造用例来说,缩短延迟时间非常重要。

鉴于 adb 是一个通常很稳定的轻量级工具,因此它是 Fuchsia 工具集的很好补充。

利益相关方

教员

leannogasawara@google.com

审核者

  • curtisgalloway@google.com
  • rdzhuang@google.com
  • gkalsi@google.com
  • prashanthsw@google.com
  • jeremymason@google.com
  • surajmalhotra@google.com

咨询人员

  • palmer@google.com

社交:制定概念验证,并与相关利益相关方讨论。

设计

本文档中的“必须”“不得”“必需”“会”“不会”“应”“不应”“建议”“可以”和“非强制”等关键字的含义如 IETF RFC 2119 中所述。

概览

Android 调试桥 (adb) 由三个主要部分组成:客户端、服务器和守护程序。客户端和服务器在主机上运行,并使用套接字相互通信。adb 守护程序 (adbd) 在设备上运行,并通常通过 USB 连接到 adb 服务器。adb 守护程序与服务器之间的通信在 adb 协议中定义。

为了让 adb 发现 Fuchsia 设备,我们必须公开一个新的 USB adb 接口。为此,必须更新 USB 外设配置,并写入新的 USB adb 函数驱动程序。主机上运行的 adb 服务器将通过此接口连接到设备。连接后,adb 服务器将在由 USB adb 函数驱动程序支持的 USB adb 接口上发送/接收 adb 协议消息。为了编码/解码这些 adb 协议消息,我们需要编写一个 adb 守护程序组件。根据请求的服务,adb 守护程序会将请求转发到相应的组件。我们可能必须编写新的 adb 服务组件,以桥接现有组件与 adb 守护程序之间的连接。我们打算仅支持一部分 adb 命令(请参阅 adb 服务)。 下图展示了提议的 adb 软件堆栈:

替代文本:显示 USB adb 堆栈:在设备上 - 在 USB 外围设备驱动程序顶部添加了新的驱动程序 usb-adb-function 驱动程序。在 usb-adb-function 驱动程序的基础上添加了新的组件 adb.cm。adb.cm 的基础之上还可以存在 adb-shell.cm、adb-ffx.cm 和许多新服务。在主机上 - 库存 adb 客户端和 adb 服务器通过 USB 主机堆栈与设备进行交互

以下各部分详细介绍了每个部分。

adb 接口和设备发现

adb 只能在支持 USB 外围设备模式的 Fuchsia 开发板上使用。为了使 Fuchsia 产品包含 adb 支持,产品配置必须包含 adb 软件包,并配置启动参数以指定 USB adb 接口。默认情况下,adb 接口仅在硬件测试产品中启用。不得在 user build 或正式版 build 中启用 adb,以限制这些 build 的攻击面。

Fuchsia 的 USB 外围设备配置将更新,以使用新的 adb 接口,该接口将在启用了 adb 的 build 中取代现有的 USB CDC 以太网接口(或与其搭配使用)。新接口将遵循 adb 接口要求:

  • USB 类:vendor
  • USB 子类:0x42
  • 协议:1

主机上运行的 adb 服务器会不断轮询接口描述符与上面列出的属性匹配的新 USB 设备。找到后,它会记下 USB 设备描述符中提到的 USB 序列号,并使用它来识别设备。adb 客户端将使用此序列号将请求路由到设备。在 Fuchsia 上,此序列号由引导加载程序传递、派生自 MAC 地址,或者是硬编码的回退序列号(按照所列顺序可用)。

USB adb 函数驱动程序

此驱动程序负责处理对 adb 接口的 USB 请求。此驱动程序将仅负责计算 USB 数据包和回调。

adb 组件

此组件了解 adb 协议,负责解析消息并将其路由到相应的服务。

adb 服务

当 adb 客户端向 adb 服务器发送命令时,服务器可能会与守护程序联系,请求连接到设备上的服务(例如 shell 或日志记录器服务)。adb 守护程序会检查已注册的服务提供商列表以查找匹配项。如果匹配,已注册的服务提供商会请求 zircon 套接字。adb 守护程序会将与服务相关的 adb 客户端中的所有通信转发到此套接字。请求的服务示例包括 shell、logcat、端口转发和文件同步。其思路是通过为每项服务提供单独的组件来支持这些服务。例如,我们可以有一个 adb-shell 组件,用于打开仪表板 shell 并管理 adb 传输与仪表板 shell 之间基于 pty 设备的通信;我们还可以有一个 adb-ffx 组件,以便于关联 adb 传输和 overnet。服务列表

服务和 adb 组件之间的接口可位于以下代码行中:

// Max length of arguments passed in adb OPEN message.
const MAX_ARGS_LENGTH uint64 = 1024

/// A Provider is a provider for one service.
/// The interaction between the adb daemon and Provider is as follows:
///    - adb daemon is started eagerly by core.cml
///    - When an request for a service comes in, adb daemon starts up a lazy component serving
///      Provider and calls ConnectToService, handing it a socket.
///    - If the service has already been started, it opens that service and hands it a socket.
///    - adb daemon and Provider communicate over the socket.
@discoverable
protocol Provider {
    /// Connect `socket` to the service (called in response to adb OPEN message).
    /// `args` provides additional arguments passed by the client if any.
    ConnectToService(resource struct {
        socket zx.handle:SOCKET;
        args string:<MAX_ARGS_LENGTH, optional>;
    }) -> (struct {}) error zx.status;
};

adb 协议指定了多项服务,但我们打算仅支持其中一部分服务,包括 shell、logcat、同步(用于 adb 推送/拉取)。这些服务可能无法模拟其他平台上的 adb 的所有行为,并且将针对 Fuchsia 进行定制,例如,shell 命令必须与 Fuchsia 支持的命令匹配,并且日志可能采用 Fuchsia 系统日志格式。下一部分将详细讨论 adb shell 服务。我们将根据具体情况考虑今后增加对更多服务的支持。

adb 服务示例:adb shell

本部分通过考虑 adb shell 服务示例来说明 adb 服务与 adb 守护程序之间的交互。adb shell 组件将通过信息中心启动器服务将 adb shell I/O 桥接到仪表板 shell I/O,从而提供 adb shell 服务。默认情况下,adb-shell.cm 将提供类似于通过 sshd-host.cm 使用 ffx component explore 的 shell 或具有更受限功能的其他方式。如果我们迁移到 Fuchsia 中的其他界面,也可以将 adb-shell 迁移到该界面中。如需限制特定产品配置和特定用例中的功能,功能有限的自定义 shell 提供程序可以替换此组件。它与使用 ffx component explore <specific-moniker> 类似。

每当用户请求新的 adb shell 实例时,adb 守护程序都会请求新的 adb shell 会话(并因此请求新的信息中心会话)。从 adb 客户端或短划线关闭连接将关闭整个会话。以下序列图显示了互动的顺序:

替代文本:adb shell 序列图如下所示:在主机上,adb 客户端向 adb 服务器发送“adb shell”消息。然后,adb 服务器向设备上的 adb.cm 发送 OPEN(&quot;shell&quot;) 协议消息。adb.cm 根据预先配置的服务组件映射启动 adb-shell.cm,然后调用 adb-shell.cm 的“ConnectToService() API”和 adb-shell.cm 的“ConnectToService() API”
随后调用 adb-shell.cm 的“ConnectToService() API”和 adb-shell.cm 之间的“debug&quot;&quot;&quot;adb shell&quot; API。

身份验证和加密

adb 协议支持使用 RSA 密钥对进行身份验证。此外,它还支持 TLS 加密。 这两项功能均为可选功能。对于初始实现,这些功能不会实现,因为预期用途仅适用于在受限环境中运行的开发者或测试 build。此外,由于 USB 是唯一受支持的传输方式,因此会在某种程度上限制攻击方式。将来,如果要支持这些机制,只能对 adb 守护程序进行更新。

维护

将支持当前的 adb 协议版本 0x01000000。未来对协议的更新将根据具体情况进行。adb 协议的更改不是已知的,并且一直向后兼容。

实现

实现过程可分为三个部分。

  • 在不同的开发板和 build 中添加支持。
  • adb 守护程序
    • 其中部分内容将在 OSRB 批准后从 Android 代码库导入。
  • adb 服务
    • 目前的计划是支持 adb-shelladb-ffx
    • 如果必须支持其他命令,此阶段可能会延长。

目前已经有概念验证,它将作为实现时的参考。

性能

计算影响:添加 adb 支持应该不会产生任何显著的计算开销。系统将使用 adb 而不是 SSH 守护程序和/或上网堆栈,这两者依赖于相似类型的驱动程序和组件,因此系统的总体 CPU 使用率应该保持不变。

对大小的影响:添加 adb 守护程序和服务后,映像大小将增加大约 1MB。请注意,这仅适用于使用 adb 支持组建的开发和测试 build。这不会对运行时内存占用量产生任何重大影响,因为系统将使用 adb 而不是现有工具。

延迟时间:由于没有额外的网络堆栈,adb 中命令处理的延迟时间比 SSH 或其他基于网络的服务略长。设备发现延迟时间预计会更短,并且它基于 USB 枚举,而不是像在 mDNS 中那样基于定期广播。

向后兼容性

这涉及三个部分:一个是 adb 协议本身的向后兼容性,这不在 Fuchsia 项目的控制范围之内。尽管如此,我们已知 adb 协议仍保持了向后兼容性。其次,支持 adb 服务 - 弃用服务会影响依赖于这些服务的主机端命令/脚本。在进行此类更改时,必须使用适当的迁移策略。第三,shell 命令例如,废弃假设的 CLI xyz-tool 意味着运行 adb shell xyz-tool 的脚本将无法再运行。此问题属于 Fuchsia 工具的范围,并非特定于 adb,因此不会得到解决。

安全注意事项

关于 adb 传输的安全注意事项,我们提供了一些用于启用身份验证和加密的规定。但在最初的实现中并不会启用这些功能。由于 adb 仅在特定 build(如开发者 build 或测试 build)中可用,而不能在 user build 中使用,因此这应该不是主要问题。

关于通过 adb 公开的服务的安全注意事项,这些服务与 Fuchsia 上的现有服务没有区别。该 adb-shell/adb-ffx 公开的交互界面与 dash-shell/ffx 相同或小于 dash-shell/ffx。对于特定用例,可以通过将 shell 提供程序从 adb-shell 替换成自定义 shell,来为用例定制限定范围的 shell。

初始实现仅支持 USB 传输。与基于网络的连接相比,这将限制潜在的攻击方法。此外,adb 守护程序本身就是一个组件,因此其中的任何漏洞都将沙盒化到该特定进程,并且仅影响 adb 操作。

隐私注意事项

adb 服务公开的数据与 ffx component explore 或 SSH 的数据相同,这两者均已经过审查,检查了是否存在隐私问题。此外,这项技术将仅限于开发者 build 或测试 build,不会部署在用户/正式版 build 中。但是,USB adb 接口会公开设备序列号,该序列号与 CDC 以太网接口等其他 USB 接口使用的序列号相同。如果不是从 MAC 地址派生的,则这主要由引导加载程序配置。在配置产品时必须格外小心,不得直接使用非常重要的设备 ID。

测试

adb 堆栈的所有部分都将进行单元测试。最终,系统将添加 adb 守护程序与 adb 服务之间的集成测试。由于 adb 子系统之间的协定基于 FIDL(USB adb 驱动程序除外),因此测试可以是封闭的。将为 USB adb 接口添加设备枚举测试。如果需要,系统将添加针对 adb 的主机端 E2E 测试。对于端到端测试,我们可能需要在测试主机上安装 adb。端到端测试 / 集成测试可用于性能测试和命令延迟测试。系统会考虑通过频繁插入/拔下 USB 来定期对 adb 连接进行压力测试,以便进行可靠性测试。系统也会考虑对 adb 守护程序实现进行模糊测试。

文档

您需要添加以下文件:

  • 支持的 adb 功能列表
  • 扩展 adb 服务的指南
  • 用户指南

缺点、替代方案和未知情况

支持 adb 需要维护维护成本。使用两组通信和设备控制工具(即 ffx 和 adb)会产生开销。虽然它们具有重叠的功能,但它们的用例是可区分的,并且它们将共享相同的后端实现。ffx 适用于各种开发者工作流,但目前在主机端脚本和各种平台支持方面存在限制。adb 可用于填补这些缺口,以便进行硬件测试。通过在 ffx 和 adb 之间共享设备上的服务,可以进一步降低维护成本。例如,信息中心启动器、Overnetstack、日志接收器等也可与 adb 搭配使用。

替代方案:将 ffx 端口移植到 Windows

目前的阻碍是获得对 Windows 的 Rust 工具链支持,并将 USB 链接添加到 ffx。此外,必须将依赖于 adb 的现有测试框架改为使用 ffx,或者必须在 adb 和 ffx 之间提供转换 shim。将来可以重新考虑此策略。在开发适用于 Windows 的 ffx 的过程中,adb 提供了方便的解决方案。

替代方案:在 Linux 虚拟机中运行主机端 ffx

使用在 Windows 上运行的 Linux 虚拟机(VM),并通过设备的 USB 连接。使用此设置后,现有的 ffx 工作流将同时适用于设备发现和互动。但是,设置虚拟机所花费的时间可能很长,并且可能不稳定/可靠。此外,部分组织会限制受管 Windows 机器上的虚拟机使用。另一种方法是使用 Docker 容器,但 USB 转发可能不起作用,具体取决于 Windows 版本。

替代方案:USB 串行设备

向 Fuchsia 添加了对 USB CDC ACM 外围设备的支持。Windows 装箱内包含一个 USB 串行驱动程序,该驱动程序适用于任何 USB CDC ACM 接口。这样一来,我们就可以将 USB 端口用作串行通信设备。这种方法的缺点是缺少丰富的命令集(只有 shell 可用)、日志和 shell 无法分离,以及支持单个实例。此外,还必须更新基于 adb 的现有测试框架。

早期技术和参考资料