测试多用户

本页面介绍了在 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> 针对特定用户运行 instrumentation 测试。默认情况下,此命令使用当前用户。
  • 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 路径。如需详细了解如何在测试期间检索文件,请参阅多用户数据的内容提供程序

多用户数据的内容提供程序

由于 adb 以系统用户身份运行,并且数据在 Android 9 及更高版本中采用沙盒机制,因此您必须使用内容提供程序来推送或拉取非系统用户的任何测试数据。在以下情况下,没有必要这样做:

  • adbd 以 root 身份运行(通过 adb root),这仅在使用 userdebugusereng build 时才有可能。

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

当内容提供程序在辅助用户中运行时,您可以使用 adb shell content 命令以及指定的相应 useruri 和其他参数来访问它。

应用开发者适用的解决方法

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

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

媒体文件适用的解决方法

要将媒体文件推送到 SD 卡的媒体分区,请使用 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

安装通用内容提供程序

安装并使用现有的内容提供程序,该提供程序可读取文件并将文件写入用户专属的 /sdcard 路径。

使用 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>

目标准备程序

目标准备程序通常用于使用特定配置来设置设备。在多用户测试中,准备程序可用于创建特定类型的用户以及切换到其他用户。

对于没有辅助用户的设备类型,您可以使用 CreateUserPreparerAndroidTest.xml 中创建并切换到辅助用户。在测试结束时,准备程序会切换回并删除辅助用户。

<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(在状态检查程序中描述),因为它确保测试在自身结束后正确清理。