测试多用户

本页介绍了在 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 路径的请求会被拒。如需详细了解如何在测试期间检索文件,请参阅多用户数据的内容提供程序

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

由于 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

安装通用内容提供程序

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

通过以下某种方式来获取 TradefedContentProvider.apk

  • 从 Android Git 代码库中下载 TradefedContentProvider.apk 文件

  • 或者,使用 make TradefedContentProvider 根据源代码构建该文件。

    # 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(在状态检查器中做了介绍),因为它可确保测试在结束后正确地自行清理。