This page describes important aspects of testing multiple users on the Android platform. For information about implementing multi-user support, see Supporting Multiple Users.
The following table lists several of the device paths and how they are resolved. All values in the Path column are a user-specific sandboxed storage. Android's storage story has changed over time; read the Storage documentation for more information.
|Path||System path (optional)||Purpose|
||Shared internal storage|
||none||User media data (for example, music, videos)|
||none||System configuration/state per user
Accessible only by system apps
Here's an example of using a user-specific path:
# to access user 10's private application data for app com.bar.foo: $ adb shell ls /data/user/10/com.bar.foo/
adb interactions across users
adb commands are useful when dealing with multiple users. Some of
these commands are supported only in Android 9 and
adb shell instrument --user <userId>runs an instrumentation test against a specific user. By default this uses the current user.
adb install --user <userId>installs a package for a specific user. To guarantee that a package is installed for all users, you must call this for every user.
adb uninstall --user <userId>uninstalls a package for a specific user. Call without the
--userflag to uninstall for all users.
adb shell am get-current-usergets the current (foreground) user ID.
adb shell pm list usersgets a list of all existing users.
adb shell pm create-usercreates a new user, returning the ID.
adb shell pm remove-userremoves a specific user by ID.
adb shell pm disable --user <userId>disables a package for a specific user.
adb shell pm enable --user <userId>enables a package for a specific user.
adb shell pm list packages --user <userId>lists packages (
-dfor disabled) for a specific user. By default this always lists for the system user.
The following information helps explain how
adb behaves with multiple users:
adb(or more accurately the
adbddaemon) always runs as the system user (user ID = 0) regardless of which user is current. Therefore device paths that are user dependent (such as
/sdcard/) always resolve as the system user. See Device paths for more details.
If a default user isn't specified, each
adbsubcommand has a different user. The best practice is to retrieve the user ID with
am get-current-userand then explicitly use
--user <userId>for any command that supports it. Explicit user flags weren't supported for all commands until Android 9.
/sdcardpaths of secondary users is denied starting in Android 9. See Content provider for multi-user data for details on how to retrieve files during testing.
Content provider for multi-user data
adb runs as the system user and data is sandboxed in Android 9 and higher, you must use content providers to push or
pull any test data from a nonsystem user. This is not necessary if:
adbdis running as root (through
adb root), which is only possible using
You're using Trade Federation's (Tradefed's)
ITestDeviceto push/pull the files, in which case use
/sdcard/paths in your test config (for example, see the source code for
When a content provider is running in the secondary user, you can access it by
adb shell content command with the appropriate
other parameters specified.
Workaround for app developers
Interact with test files using
adb content and an instance of
instead of the
- Create an instance of
ContentProviderhosted by the app that can serve/store files where needed. Use the app’s internal storage.
adb shell content
writecommands to push/pull the files.
Workaround for media files
To push media files to the media partition of the SD card, use
APIs. For example:
# 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
Installing a generic content provider
Install and use an existing content provider that reads and writes files to the
TradefedContentProvider.apk in one of these ways:
TradefedContentProvider.apkfile from the Android Git Repository
Or build it from the source using
# 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 multi-user support
Tradefed is the official Android test harness. This section summarizes some of Tradefed's builtin support for multi-user test scenarios.
System status checkers (SSCs) are run before the target preparers, and their cleanup is run after those preparers.
is defined explicitly to aid developers when testing multiple users. It tracks
whether a test has changed the state of the users on the device (for example,
created users without removing them in teardown). In addition, if
is set, it automatically attempts to clean up after the test, while still
providing helpful errors so that the test can be fixed.
<system_checker class="com.android.tradefed.suite.checker.UserChecker" > <option name="user-cleanup" value="true" /> </system_checker>
Target preparers are typically used to set up a device with a particular configuration. In the case of multi-user testing preparers can be used to create users of a specific type as well as switch to other users.
For device types that don't have a secondary user, you can use
CreateUserPreparer to create and switch to a secondary user in
AndroidTest.xml. At the end of the test, the preparer switches back and
deletes the secondary user.
<target_preparer class="com.google.android.tradefed.targetprep.CreateUserPreparer" > </target_preparer>
If the user type you want already exists on the device, use
SwitchUserTargetPreparer to switch to the existing user. Common values for
<target_preparer class="com.android.tradefed.targetprep.SwitchUserTargetPreparer"> <option name="user-type" value="secondary" /> </target_preparer>
In some instances, a test needs to switch users within the test. Don't
make the switch from within a device-side test framework, such as
because the test process may be killed at any time. Instead, use a host-side test framework like Tradefed's
Host-Driven Test Framework,
which gives access to
allowing for any user manipulation that is needed.
UserChecker (described in
Status checkers) for host-driven tests that change
the user state because it ensures that the test properly cleans up after itself.