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

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

添加了 adb 协议和接口支持,以便 Fuchsia 设备与标准 adb 客户端进行互动,以实现硬件测试用例。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)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 以太网接口一起使用)现有 USB CDC 以太网接口。adb 协议支持将仅限于硬件验证和制造用例认为必要的功能。支持的 adb 服务将是 Fuchsia 专有的,不会尝试模仿 Android adb 服务。

设计初衷

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

  • 围绕 adb 构建了多个工具、库和框架(123 等),这些工具、库和框架可重复使用。
  • 适用于各种平台的 adb 客户端的预构建二进制发行版广泛可用,并且易于设置。
  • 依赖 adb 提供设备发现、连接和命令执行服务的现有测试框架无需进行任何更改即可正常运行。
  • 由于 adb 的普及性,开发者对其非常熟悉,并且开源社区对其的支持也非常广泛。
  • 它可以通过在目前不受支持的环境(例如 Windows)中隧道传输 overnet 连接,进一步扩展 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-peripheral 驱动程序之上添加了新驱动程序 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 接口仅在硬件测试产品中启用。不应在用户 build 或正式版 build 中启用 adb,以限制这些 build 的攻击面。

Fuchsia 的 USB 外围设备配置将更新为使用新的 adb 接口,该接口将在启用了 adb 的 build 中替换(或与现有 USB CDC 以太网接口一起使用)现有 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 组件打开 Dash Shell 并管理 adb 传输层与 Dash 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、sync(适用于 adb push/pull)。这些服务可能无法模拟其他平台上 adb 的所有行为,并且将专为 Fuchsia 量身定制,例如,shell 命令必须与 Fuchsia 支持的命令匹配,日志可能采用 Fuchsia 系统日志格式。下一部分将详细介绍 adb shell 服务。我们会根据具体情况考虑日后为更多服务添加支持。

adb 服务示例:adb shell

本部分将通过 adb shell 服务示例介绍 adb 服务与 adb 守护程序之间的交互。adb shell 组件将负责通过 Dash 启动器服务将 adb shell I/O 桥接到 Dash 壳 I/O,从而提供 adb shell 服务。默认情况下,adb-shell.cm 将提供一个类似于通过 sshd-host.cm 使用 ffx component explore 的 shell,或者提供功能更受限的 shell。如果我们在 Fuchsia 中迁移到其他界面,adb-shell 也可以迁移到该界面。如需针对特定产品配置和特定用例限制功能,您可以使用功能受限的自定义 shell 提供程序来替代此组件。这与使用 ffx component explore <specific-moniker> 类似。

每当用户请求新的 adb shell 实例时,adb 守护程序都会请求新的 adb shell 会话(因此也是新的 Dash 会话)。从 adb 客户端或 Dash 关闭连接会关闭整个会话。互动顺序如下序列图所示:

备注:显示 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 反过来会调用 debug-dash-launcher.cm 提供的 LaunchWIthSocket 协议,该协议会生成 dash shell 和 pty 设备。adb.cm 会向 adb 服务器发送 READY() 消息作为响应。现在,adb 客户端和 dash 之间的 adb 传输通道已建立。

身份验证和加密

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

维护

当前的 adb 协议版本 0x01000000 将受支持。我们日后会根据具体情况更新该协议。adb 协议不会经常更改,并且始终向后兼容。

实现

实现可分为三个部分。

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

目前已经有了概念验证,可作为实现的参考。

性能

计算影响:添加 adb 支持后,计算开销应该不会有任何显著增加。系统将使用 adb 而非 ssh 守护程序和/或 overnetstack,这两者都依赖于类似类型的驱动程序和组件,因此系统的总 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,而不适用于用户 build,因此这不应成为一个主要问题。

关于通过 adb 公开的服务的安全注意事项,这些与 Fuchsia 上的现有服务没有什么不同。该 adb-shell / adb-ffx 公开的交互界面与 dash-shell /ffx 相同或更小。对于特定用例,您可以将 shell 提供程序从 adb-shell 替换为 custom-shell,从而使用专为该用例量身定制的严格限定范围的 shell。

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

隐私注意事项

adb 服务公开的数据与 ffx component explore 或 SSH 公开的数据相同,这两者都经过了隐私权审核。此外,此技术将仅限于开发者 build 或测试 build,不会部署在用户/正式版 build 中。不过,USB adb 接口会公开设备序列号,而此序列号与用于其他 USB 接口(例如 CDC 以太网接口)的序列号相同。此参数通常由引导加载程序配置(如果不是从 MAC 地址派生)。在产品配置期间,请务必小心,不要直接使用具有重要意义的设备 ID。

测试

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

文档

您需要添加以下文件:

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

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

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

替代方案:将 ffx 移植到 Windows

目前,实现此目标的障碍是获得适用于 Windows 的 Rust 工具链支持,以及向 ffx 添加 USB 链接。此外,依赖于 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 的现有测试框架也必须更新。

在先技术和参考文档