测试多用户

本页介绍了在 Android 平台上测试多用户的一些重要方面。如需了解如何实现多用户支持,请参阅支持多用户

设备路径

下表列出了几条设备路径及其解析方式。路径列中的所有值都是用户专用的沙盒化存储空间。Android 的存储方案多年间历有变化;如需了解详情,请阅读存储文档。

路径 系统路径(可选) 用途
/data/user/{userId}/{app.path} /data/data 应用存储空间
/storage/emulated/{userId} /sdcard 共享内部存储空间
/data/media/{userId} 用户媒体数据(例如,音乐和视频)
/data/system/users/{userId} 每个用户的系统配置/状态

只能由系统应用访问

下面是一个使用用户专用路径的示例:

# to access user 10's private application data for app com.bar.foo:
$ adb shell ls /data/user/10/com.bar.foo/

跨用户的 adb 互动

在处理多用户时,有几个 adb 命令很有用。但其中部分命令仅 Android 9 及更高版本才支持:

  • adb shell am instrument --user <userId> 可针对特定用户运行插桩测试。默认情况下,此命令使用当前用户。
  • adb install --user <userId> 可为特定用户安装软件包。要确保为所有用户安装软件包,您必须为每个用户调用此命令。
  • adb uninstall --user <userId> 可为特定用户卸载软件包。如果调用此命令时不带 --user 标记,可为所有用户卸载软件包。
  • adb shell am get-current-user 可获取当前(前台)用户 ID。
  • adb shell pm list users 可获取所有现有用户的列表。
  • adb shell pm create-user 可创建新用户并返回 ID。
  • adb shell pm remove-user 可按 ID 移除特定用户。
  • adb shell pm disable --user <userId> 可为特定用户停用软件包。
  • adb shell pm enable --user <userId> 可为特定用户启用软件包。
  • adb shell pm list packages --user <userId> 可为特定用户列出软件包(-e 可列出已启用的软件包,-d 可列出已停用的软件包)。默认情况下,此命令始终为系统用户列出软件包。

以下信息有助于说明 adb 在多用户条件下的行为方式:

  • adb(或者更准确地说,是 adbd 守护程序)始终以系统用户(用户 ID = 0)身份运行,而不管当前用户是哪个用户。因此,取决于用户的设备路径(如 /sdcard/)始终会被解析为系统用户的路径。如需了解详情,请参阅设备路径

  • 如果未指定默认用户,则每个 adb 子命令都有一个不同的用户。最佳做法是使用 am get-current-user 检索用户 ID,然后明确地对支持 --user <userId> 的所有命令使用该标记。在 Android 9 之前,并非所有命令都支持显式用户标记。

  • 从 Android 9 开始,访问次要用户的 /sdcard 路径的请求会被拒。如需详细了解如何在测试期间检索文件,请参阅多用户数据的内容提供程序

多用户数据的 content provider

由于 adb 以系统用户身份运行且数据在 Android 9 及更高版本中进行了沙盒化处理,因此您必须使用 content provider,才能向非系统用户推送测试数据或从此类用户处提取测试数据。但在以下情况下,没有必要这样做:

  • adbd 正在以 root 用户身份运行(通过 adb root),这只有使用 userdebugusereng build 才能做到。

  • 您正在使用 Trade Federation (Tradefed) 的 ITestDevice 来推送或提取文件,在这种情况下,会在您的测试配置中使用 /sdcard/ 路径(如需查看示例,请参阅 NativeDevice.javapushFile 的源代码)。

当 content provider 正在由次要用户运行时,您可以使用 adb shell content 命令(指定了适当的 useruri 及其他参数)对其进行访问。

应用开发者可用的权宜解决方案

使用 adb contentContentProvider 实例(而不是 pushpull 命令)与测试文件互动。

  1. 创建由应用托管的 ContentProvider 实例,该实例可在需要时提供和存储文件。使用应用的内部存储空间。
  2. 使用 adb shell content readwrite 命令来推送或提取文件。

针对媒体文件的权宜解决方案

如需将媒体文件推送到 SD 卡的 media 分区,请使用 MediaStore 公共 API。例如:

# push MVIMG_20190129_142956.jpg to /storage/emulated/10/Pictures
# step 1
$ adb shell content insert --user 10 --uri content://media/external/images/media/ --bind _display_name:s:foo.jpg

# step 2
$ adb shell content query --user 10 --projection _id --uri content://media/external/images/media/ --where "_display_name=\'foo.jpg\'"

# step 3
$ adb shell content write --user 10 --uri content://media/external/images/media/8022 < MVIMG_20190129_142956.jpg

安装通用 content provider

安装并使用可从用户专用 /sdcard 路径读取文件并向其中写入文件的现有 content provider。

使用 make TradefedContentProvider 根据源代码构建 TradefedContentProvider.apk

```
# install content provider apk
$ adb install --user 10 -g TradefedContentProvider.apk

# pull some_file.txt
$ adb shell content read --user 10 --uri content://android.tradefed.contentprovider/sdcard/some_file.txt > local_file.txt

# push local_file.txt
$ adb shell content write --user 10 --uri content://android.tradefed.contentprovider/sdcard/some_file.txt < local_file.txt
```

Trade Federation 多用户支持

Tradefed 是官方的 Android 自动化测试框架。本部分总结了 Tradefed 针对多用户测试场景提供的一些内置支持。

状态检查器

系统状态检查器 (SSC) 在目标准备器之前运行,而其清理任务在这些准备器之后运行。

明确定义了 UserChecker,以便在测试多用户时协助开发者。它会跟踪测试是否改变了设备上用户的状态(例如,创建了用户而未在拆解阶段将其移除)。此外,如果设置了 user-cleanup,它会在测试后自动尝试清理,同时仍提供有用的错误消息,以便您修复测试。

<system_checker class="com.android.tradefed.suite.checker.UserChecker" >
    <option name="user-cleanup" value="true" />
</system_checker>

目标准备器

目标准备器通常用于设置具有特定配置的设备。对于多用户测试,准备器可用于创建特定类型的用户以及切换到其他用户。

对于没有次要用户的设备类型,您可以在 AndroidTest.xml 中使用 CreateUserPreparer 创建并切换到次要用户。在测试结束时,准备器会切换回系统用户并删除次要用户。

<target_preparer
  class="com.google.android.tradefed.targetprep.CreateUserPreparer" >
</target_preparer>

如果设备上已存在您想要的用户类型,请使用 SwitchUserTargetPreparer 切换到现有用户。user-type 的常见值包括 systemsecondary

<target_preparer
  class="com.android.tradefed.targetprep.SwitchUserTargetPreparer">
    <option name="user-type" value="secondary" />
</target_preparer>

主机驱动的测试

在某些情况下,测试需要在测试过程中切换用户。请不要在设备端测试框架(如 UI Automator)中进行切换,因为测试过程可能会随时终止。应使用主机端测试框架(如 Tradefed 的主机驱动型测试框架),通过此类框架可访问 ITestDevice,从而能够进行所需的任何用户操控。

对于会改变用户状态的主机驱动型测试,应使用 UserChecker(在状态检查器中做了介绍),因为它可确保测试在结束后正确地自行清理。