在 VTS 测试期间,shell 命令用于执行目标端测试二进制文件、获取/设置属性、环境变量和系统信息,以及启动/停止 Android 框架。您可以使用 adb shell
命令或设备上运行的 VTS shell 驱动程序(推荐)执行 VTS 设备 shell 命令。
使用 ADB shell
在测试期间需要关闭 USB 端口或重启设备的测试必须使用 ADB shell,因为 VTS shell 驱动程序在没有持久 USB 连接的情况下不可用。您可以从 Python 测试脚本中的 AndroidDevice
对象调用 ADB shell。示例
- 获取 Android 设备对象
self.device = self.android_devices[0]
- 发出单个 shell 命令
result = self.device.adb.shell(‘ls')
使用 VTS shell 驱动程序
VTS shell 驱动程序是在设备上运行并执行 shell 命令的代理二进制文件。默认情况下,如果驱动程序在设备上运行,VTS 会使用 shell 驱动程序,因为此方法比使用 adb shell
命令延迟更低。
VTS 框架支持多设备测试,其中每个 Android 设备在基本运行程序中都表示为一个 AndroidDevice 对象。默认情况下,VTS 框架会将 VTS 代理和 VTS shell 驱动程序二进制文件推送到每个 Android 设备,并建立与这些设备上 VTS 代理的 TCP 连接。
要执行 shell 命令,主机端 Python 脚本会向 AndroidDevice 对象内的 ShellMirror 对象发出函数调用。ShellMirror 对象将 shell 命令文本打包到 protobuf 消息中,并通过 TCP 通道将其发送到 Android 设备上的 VTS 代理。设备上运行的代理随后通过 Unix 套接字将 shell 命令转发到 VTS shell 驱动程序。
当 VTS shell 驱动程序收到 shell 命令时,它会通过设备 shell 上的 nohup 执行该命令以防止挂起。然后从 nohup
检索 stdout、stderr 和返回代码,并将其发回 VTS 代理。最后,代理通过将命令结果包装到 protobuf
消息中来回复主机。
优势
使用 VTS shell 驱动程序而不是 adb shell
的优势包括:
- 可靠性。VTS shell 驱动程序使用
nohup
在默认设置下执行命令。由于 VTS 测试主要为较低级别的 HAL 和内核测试,nohup
可确保 shell 命令在执行期间不会挂起。 - 性能。虽然
adb shell
命令会缓存一些结果(例如列出目录中的文件),但在执行测试二进制文件等任务时,它具有连接开销。VTS shell 驱动程序在整个测试过程中保持活动连接,因此唯一的开销是 USB 通信。在我们的测试中,使用 VTS shell 驱动程序执行对空 gtest 二进制文件进行 100 次调用的命令比使用adb shell
快约 20%;由于 VTS shell 通信具有广泛的日志记录,因此实际差异更大。 - 状态保持。VTS shell 驱动程序为每个终端名称(默认终端名称为default)维护一个终端会话。在一个终端会话中设置的环境变量仅对同一会话中的后续命令可用。
- 可扩展性。VTS 框架和设备驱动程序之间的 Shell 命令通信封装在 protobuf 中,以便将来实现潜在的压缩、远程处理、加密等功能。还提供了其他提高性能的可能性,包括当通信开销变得大于结果字符串解析时,在设备端进行结果解析。
缺点
使用 VTS shell 驱动程序而不是 adb shell
的缺点包括
- 额外的二进制文件。VTS 代理文件必须推送到设备并在测试执行后清理。
- 需要活动连接。如果在测试期间主机和代理之间的 TCP 连接丢失(由于 USB 断开、端口关闭、设备崩溃等,无论是故意的还是无意的),则 shell 命令无法传输到 VTS 代理。即使自动切换到
adb shell
,断开连接之前命令的结果和状态也将是未知的。
示例
在 VTS 主机端 Python 测试脚本中使用 shell 命令的示例
- 获取 Android 设备对象
self.device = self.android_devices[0]
- 获取所选设备的 shell 对象
self.shell = self.device.shell
- 发出单个 shell 命令
results = self.shell.Execute(‘ls')
- 发出一系列 shell 命令
results = self.shell.Execute([‘cd /data/local/tmp', ‘ls'])
命令结果对象
从 shell 命令执行返回的对象是一个字典,其中包含键 stdouts
、stderrs
和 return_codes
。无论 shell 命令是作为单个字符串还是命令字符串列表提供,结果字典的每个值始终都是一个列表。
要验证命令列表的返回代码,测试脚本必须检查索引。示例
asserts.assertFalse(any(results[‘return_codes']), ‘some command failed.')
或者,脚本可以单独检查每个命令索引。示例
asserts.assertEqual(results[‘return_codes'][0], 0, ‘first command failed')
asserts.assertEqual(results[‘return_codes'][1], 0, ‘second command failed')