1

I have two Android system users configured.

$ pm list users
Users:
    UserInfo{0:Owner:13} running
    UserInfo{10:security space:13} running
    UserInfo{999:XSpace:800010} running

When the mobile is running at Android 8.1, I can access the secondary user's space /storage/emulated/10 easily in adb shell.

But after I upgrade to Android 9, I can no longer do it:

$ ls /storage/emulated/10
ls: /storage/emulated/10: Permission denied

Any ideas how I can access my second user's space in adb shell?

Btw, my /sdcard/ always points to the first user's space /storage/emulated/0 at adb shell regardless what my current user is at mobile UI. The adb shell connection remains the same when I switch users at mobile UI too.

When I switch users at mobile UI level, my adb connection remains the same. And I do see the current user changes with the following command:

$ dumpsys activity | grep mCurrentUser
    mCurrentUser=0
$ dumpsys activity | grep mCurrentUser
    mCurrentUser=10
1

WHY IS ADB DENIED ACCESS TO MULTI-USER STORAGE?

Access to /storage/emulated/10 is denied from adb shell due to this change in Android 9:

Add "default_normal" support to vold.
This new flag isolates each user on a multi-user device for security reasons.

What the mount option default_normal does in sdcardfs is explained here:

The default_normal option causes mounts with the gid set to AID_SDCARD_RW to have user specific gids, as in the normal case.

The whole story is about Android's filesystem emulation in order to have a permission-less directory (/sdcard) which makes file sharing among multiple UNIX users (apps) possible. It's achieved through mount namespaces and different VIEWs of /data/media mounted in /mnt/runtime/. Apps belonging to secondary as well as primary user have isolated mount namespaces. For details please see What is the “u#_everybody” UID? and What is /storage/emulated/0/?.

Btw, my /sdcard/ always points to the first user's space /storage/emulated/0 at adb shell regardless what my current user is at mobile UI.

For all native processes running in root mount namespace (including adbd), /sdcard is a symlink to /storage/emulated/0 and /storage/emulated is bind mounted from /mnt/runtime/default. The device owner's (User_ID: 0) files in /storage/emulated/0 have ownership root:sdcard_rw (0:1015) and permission mode 0771, while secondary profile/user's (say with User_ID: 10) files in /storage/emulated/10 have ownership 0:1001015.

It means that non-root processes can read the directories only if they are members of supplementary groups: 0001015, 1001015, 11001015 and so on, "others" can only traverse the directories. Since adbd is member of only 1015 GID, it can read only device owner's files, not of secondary users.

However up to Android 8 there was an exception to the above rule: to all the processes running in root mount namespace (non-app processes), sdcardfs always returned the directories /storage/emulated/[N] owned by GID 1015. So adb was able to read these directories. However the exception has been removed in Android 9 using mount option default_normal.


HOW TO ACCESS MULTIPLE-USERS FILES FROM ADB?

WITH ROOT ACCESS:

You can mount the emulated filesystem without default_normal option:

~# umount /mnt/runtime/*/emulated
~# /system/bin/sdcard -u 1023 -g 1023 -m -w -G /data/media emulated

Or to make changes permanent, replace sdcard binary with a shell script:

~# cd /system/bin/; mv sdcard sdcard.bin; touch sdcard
~# chown 0.2000 sdcard*; chmod 0755 sdcard*
~# chcon u:object_r:system_file:s0 sdcard
~# chcon u:object_r:sdcardd_exec:s0 sdcard.bin

/system/bin/sdcard (remove -i argument passed by vold):

#!/system/bin/sh

set -- $(echo "$*" | sed 's/-i //')
/system/bin/sdcard.bin $*

After reboot you should be able to read files in /storage/emulated/10 from adb shell.

WITHOUT ROOT ACCESS:

On Android 9+ filesystem level access to secondary users/profiles is not possible from adb on user builds of ROMs (i.e. without root). Only interaction through adb commands which support --user option (am, pm, content etc.) is possible. Documented in What’s in Android 9 for enterprise apps:

"To help keep work data in the work profile, the Android Debug Bridge (adb) tool can’t access directories and files in the work profile."

If the files owned by secondary users are accessible to primary user (through adb or any other means, except through Device/Work Policy Controller app), it breaks the intended isolation between users/profiles which is controlled through Android APIs. See more details in How to share files between regular account and work account?

It should be noted that Android Debugging Bridge (adb) is meant to be used by developers for debugging, not by end users. That's why a fully-managed device owner can completely disable adb.

There's a suggested workaround to transfer data with secondary users/profiles as explained in Testing Multiple Users:

"adb (or more accurately the adbd daemon) 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."
...
"Access to /sdcard paths of secondary users is denied starting in Android 9."
...
"Because 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."

For instance to transfer test.jpg file to /storage/emulated/10/Pictures/ run the following commands from adb shell:

~$ content insert --user 10 --uri content://media/external/images/media/ --bind _display_name:s:test.jpg
~$ ID=$(content query --user 10 --projection _id --uri content://media/external/images/media/ --where _display_name=\'test.jpg\' | grep -o '_id=[0-9]*' | cut -d= -f2)
~$ content write --user 10 --uri content://media/external/images/media/$ID < test.jpg

However it's not a practical approach for bulk data transfers on a regular basis.

| improve this answer | |
  • Thanks a lot for this answer. I have upvoted it because it provides very detail explanation about this problem. But due to I want to access the directory without root access, I can not mark it as the answer for now. In theory, I know the 2nd user password (I am the 2nd user), I should be able to access my own files/photos. If there is no way to achieve it, google did something extremely wrong here. Thanks. – sgon00 Feb 25 at 10:57
  • @sgon00 personally I neither use adb for data transfer, nor Work Profiles. Also I'm not sure what's Google's stance on this issue. But in my opinion if the files owned by secondary user are accessible to primary user (through adb or any other means, except through Device/Work Policy Controller app), it nullifies the whole purpose of Work Profile. Note that the Work Profiles are not to use duplicate apps, but for isolation. So this enhanced isolation in Android 9 is justified. I wanted to write a few lines on this in my answer but keeping in view the length of the answer I didn't. – Irfan Latif Feb 25 at 18:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.