Skip to content

Commit b049e21

Browse files
committed
Include user identifier in external storage paths.
When building external storage paths, always include user in path to enable cross-user paths and aid debugging. Each Zygote process continues to only have access to the appropriate user-specific emulated storage through bind mounts. A second set of mounts continue supporting legacy /sdcard-style paths. For example, a process running as owner has these mount points: /storage/emulated_legacy /storage/emulated_legacy/Android/obb /storage/emulated/0 /storage/emulated/obb Since Environment is created before Zygote forks, we need to update its internal paths after each process launches. Bug: 7131382 Change-Id: I6f8c6971f2a8edfb415c14cb4ed05ff97e587a21
1 parent b1ee588 commit b049e21

File tree

13 files changed

+645
-285
lines changed

13 files changed

+645
-285
lines changed

core/java/android/app/ActivityThread.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import android.os.Binder;
5353
import android.os.Bundle;
5454
import android.os.Debug;
55+
import android.os.Environment;
5556
import android.os.Handler;
5657
import android.os.IBinder;
5758
import android.os.Looper;
@@ -4877,6 +4878,8 @@ public static void main(String[] args) {
48774878
// StrictMode) on debug builds, but using DropBox, not logs.
48784879
CloseGuard.setEnabled(false);
48794880

4881+
Environment.initForCurrentUser();
4882+
48804883
Security.addProvider(new AndroidKeyStoreProvider());
48814884

48824885
Process.setArgV0("<pre-initialized>");

core/java/android/content/pm/UserInfo.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import android.os.Parcel;
2020
import android.os.Parcelable;
21-
import android.os.Parcelable.Creator;
21+
import android.os.UserHandle;
2222

2323
/**
2424
* Per-user information.
@@ -92,6 +92,10 @@ public UserInfo(UserInfo orig) {
9292
serialNumber = orig.serialNumber;
9393
}
9494

95+
public UserHandle getUserHandle() {
96+
return new UserHandle(id);
97+
}
98+
9599
@Override
96100
public String toString() {
97101
return "UserInfo{" + id + ":" + name + ":" + Integer.toHexString(flags) + "}";

core/java/android/os/Debug.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ private Debug() {}
9595
* Default trace file path and file
9696
*/
9797
private static final String DEFAULT_TRACE_PATH_PREFIX =
98-
Environment.getExternalStorageDirectory().getPath() + "/";
98+
Environment.getLegacyExternalStorageDirectory().getPath() + "/";
9999
private static final String DEFAULT_TRACE_BODY = "dmtrace";
100100
private static final String DEFAULT_TRACE_EXTENSION = ".trace";
101101
private static final String DEFAULT_TRACE_FILE_PATH =

core/java/android/os/Environment.java

Lines changed: 153 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616

1717
package android.os;
1818

19-
import android.content.res.Resources;
2019
import android.os.storage.IMountService;
20+
import android.os.storage.StorageManager;
2121
import android.os.storage.StorageVolume;
22+
import android.text.TextUtils;
2223
import android.util.Log;
2324

2425
import java.io.File;
@@ -29,31 +30,125 @@
2930
public class Environment {
3031
private static final String TAG = "Environment";
3132

33+
private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
34+
private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET";
35+
3236
private static final File ROOT_DIRECTORY
3337
= getDirectory("ANDROID_ROOT", "/system");
3438

3539
private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
3640

37-
private static final Object mLock = new Object();
41+
private static UserEnvironment sCurrentUser;
42+
43+
private static final Object sLock = new Object();
3844

39-
private volatile static StorageVolume mPrimaryVolume = null;
45+
// @GuardedBy("sLock")
46+
private static volatile StorageVolume sPrimaryVolume;
4047

4148
private static StorageVolume getPrimaryVolume() {
42-
if (mPrimaryVolume == null) {
43-
synchronized (mLock) {
44-
if (mPrimaryVolume == null) {
49+
if (sPrimaryVolume == null) {
50+
synchronized (sLock) {
51+
if (sPrimaryVolume == null) {
4552
try {
4653
IMountService mountService = IMountService.Stub.asInterface(ServiceManager
4754
.getService("mount"));
48-
Parcelable[] volumes = mountService.getVolumeList();
49-
mPrimaryVolume = (StorageVolume)volumes[0];
55+
final StorageVolume[] volumes = mountService.getVolumeList();
56+
sPrimaryVolume = StorageManager.getPrimaryVolume(volumes);
5057
} catch (Exception e) {
5158
Log.e(TAG, "couldn't talk to MountService", e);
5259
}
5360
}
5461
}
5562
}
56-
return mPrimaryVolume;
63+
return sPrimaryVolume;
64+
}
65+
66+
static {
67+
initForCurrentUser();
68+
}
69+
70+
/** {@hide} */
71+
public static void initForCurrentUser() {
72+
final int userId = UserHandle.myUserId();
73+
sCurrentUser = new UserEnvironment(userId);
74+
75+
synchronized (sLock) {
76+
sPrimaryVolume = null;
77+
}
78+
}
79+
80+
/** {@hide} */
81+
public static class UserEnvironment {
82+
// TODO: generalize further to create package-specific environment
83+
84+
private final File mExternalStorage;
85+
private final File mExternalStorageAndroidData;
86+
private final File mExternalStorageAndroidMedia;
87+
private final File mExternalStorageAndroidObb;
88+
89+
public UserEnvironment(int userId) {
90+
// See storage config details at http://source.android.com/tech/storage/
91+
String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE);
92+
String rawEmulatedStorageTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);
93+
94+
if (!TextUtils.isEmpty(rawEmulatedStorageTarget)) {
95+
// Device has emulated storage; external storage paths should have
96+
// userId burned into them.
97+
final File emulatedBase = new File(rawEmulatedStorageTarget);
98+
99+
// /storage/emulated/0
100+
mExternalStorage = buildPath(emulatedBase, Integer.toString(userId));
101+
// /storage/emulated/obb
102+
mExternalStorageAndroidObb = buildPath(emulatedBase, "obb");
103+
104+
} else {
105+
// Device has physical external storage; use plain paths.
106+
if (TextUtils.isEmpty(rawExternalStorage)) {
107+
Log.w(TAG, "EXTERNAL_STORAGE undefined; falling back to default");
108+
rawExternalStorage = "/storage/sdcard0";
109+
}
110+
111+
// /storage/sdcard0
112+
mExternalStorage = new File(rawExternalStorage);
113+
// /storage/sdcard0/Android/obb
114+
mExternalStorageAndroidObb = buildPath(mExternalStorage, "Android", "obb");
115+
}
116+
117+
mExternalStorageAndroidData = buildPath(mExternalStorage, "Android", "data");
118+
mExternalStorageAndroidMedia = buildPath(mExternalStorage, "Android", "media");
119+
}
120+
121+
public File getExternalStorageDirectory() {
122+
return mExternalStorage;
123+
}
124+
125+
public File getExternalStoragePublicDirectory(String type) {
126+
return new File(mExternalStorage, type);
127+
}
128+
129+
public File getExternalStorageAndroidDataDir() {
130+
return mExternalStorageAndroidData;
131+
}
132+
133+
public File getExternalStorageAppDataDirectory(String packageName) {
134+
return new File(mExternalStorageAndroidData, packageName);
135+
}
136+
137+
public File getExternalStorageAppMediaDirectory(String packageName) {
138+
return new File(mExternalStorageAndroidMedia, packageName);
139+
}
140+
141+
public File getExternalStorageAppObbDirectory(String packageName) {
142+
return new File(mExternalStorageAndroidObb, packageName);
143+
}
144+
145+
public File getExternalStorageAppFilesDirectory(String packageName) {
146+
return new File(new File(mExternalStorageAndroidData, packageName), "files");
147+
}
148+
149+
public File getExternalStorageAppCacheDirectory(String packageName) {
150+
return new File(new File(mExternalStorageAndroidData, packageName), "cache");
151+
}
57152
}
58153

59154
/**
@@ -137,20 +232,7 @@ public static boolean isEncryptedFilesystemEnabled() {
137232
private static final File MEDIA_STORAGE_DIRECTORY
138233
= getDirectory("MEDIA_STORAGE", "/data/media");
139234

140-
private static final File EXTERNAL_STORAGE_DIRECTORY
141-
= getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0");
142-
143-
private static final File EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY = new File(new File(
144-
getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0"), "Android"), "data");
145-
146-
private static final File EXTERNAL_STORAGE_ANDROID_MEDIA_DIRECTORY = new File(new File(
147-
getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0"), "Android"), "media");
148-
149-
private static final File EXTERNAL_STORAGE_ANDROID_OBB_DIRECTORY = new File(new File(
150-
getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0"), "Android"), "obb");
151-
152-
private static final File DOWNLOAD_CACHE_DIRECTORY
153-
= getDirectory("DOWNLOAD_CACHE", "/cache");
235+
private static final File DOWNLOAD_CACHE_DIRECTORY = getDirectory("DOWNLOAD_CACHE", "/cache");
154236

155237
/**
156238
* Gets the Android data directory.
@@ -198,7 +280,13 @@ public static File getDataDirectory() {
198280
* @see #isExternalStorageRemovable()
199281
*/
200282
public static File getExternalStorageDirectory() {
201-
return EXTERNAL_STORAGE_DIRECTORY;
283+
throwIfSystem();
284+
return sCurrentUser.getExternalStorageDirectory();
285+
}
286+
287+
/** {@hide} */
288+
public static File getLegacyExternalStorageDirectory() {
289+
return new File(System.getenv(ENV_EXTERNAL_STORAGE));
202290
}
203291

204292
/**
@@ -318,57 +406,62 @@ public static File getExternalStorageDirectory() {
318406
* using it such as with {@link File#mkdirs File.mkdirs()}.
319407
*/
320408
public static File getExternalStoragePublicDirectory(String type) {
321-
return new File(getExternalStorageDirectory(), type);
409+
throwIfSystem();
410+
return sCurrentUser.getExternalStoragePublicDirectory(type);
322411
}
323412

324413
/**
325414
* Returns the path for android-specific data on the SD card.
326415
* @hide
327416
*/
328417
public static File getExternalStorageAndroidDataDir() {
329-
return EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY;
418+
throwIfSystem();
419+
return sCurrentUser.getExternalStorageAndroidDataDir();
330420
}
331421

332422
/**
333423
* Generates the raw path to an application's data
334424
* @hide
335425
*/
336426
public static File getExternalStorageAppDataDirectory(String packageName) {
337-
return new File(EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY, packageName);
427+
throwIfSystem();
428+
return sCurrentUser.getExternalStorageAppDataDirectory(packageName);
338429
}
339430

340431
/**
341432
* Generates the raw path to an application's media
342433
* @hide
343434
*/
344435
public static File getExternalStorageAppMediaDirectory(String packageName) {
345-
return new File(EXTERNAL_STORAGE_ANDROID_MEDIA_DIRECTORY, packageName);
436+
throwIfSystem();
437+
return sCurrentUser.getExternalStorageAppMediaDirectory(packageName);
346438
}
347439

348440
/**
349441
* Generates the raw path to an application's OBB files
350442
* @hide
351443
*/
352444
public static File getExternalStorageAppObbDirectory(String packageName) {
353-
return new File(EXTERNAL_STORAGE_ANDROID_OBB_DIRECTORY, packageName);
445+
throwIfSystem();
446+
return sCurrentUser.getExternalStorageAppObbDirectory(packageName);
354447
}
355448

356449
/**
357450
* Generates the path to an application's files.
358451
* @hide
359452
*/
360453
public static File getExternalStorageAppFilesDirectory(String packageName) {
361-
return new File(new File(EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY,
362-
packageName), "files");
454+
throwIfSystem();
455+
return sCurrentUser.getExternalStorageAppFilesDirectory(packageName);
363456
}
364-
457+
365458
/**
366459
* Generates the path to an application's cache.
367460
* @hide
368461
*/
369462
public static File getExternalStorageAppCacheDirectory(String packageName) {
370-
return new File(new File(EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY,
371-
packageName), "cache");
463+
throwIfSystem();
464+
return sCurrentUser.getExternalStorageAppCacheDirectory(packageName);
372465
}
373466

374467
/**
@@ -441,9 +534,10 @@ public static String getExternalStorageState() {
441534
try {
442535
IMountService mountService = IMountService.Stub.asInterface(ServiceManager
443536
.getService("mount"));
444-
return mountService.getVolumeState(getExternalStorageDirectory()
445-
.toString());
446-
} catch (Exception rex) {
537+
final StorageVolume primary = getPrimaryVolume();
538+
return mountService.getVolumeState(primary.getPath());
539+
} catch (RemoteException rex) {
540+
Log.w(TAG, "Failed to read external storage state; assuming REMOVED: " + rex);
447541
return Environment.MEDIA_REMOVED;
448542
}
449543
}
@@ -457,8 +551,8 @@ public static String getExternalStorageState() {
457551
* <p>See {@link #getExternalStorageDirectory()} for more information.
458552
*/
459553
public static boolean isExternalStorageRemovable() {
460-
StorageVolume volume = getPrimaryVolume();
461-
return (volume != null && volume.isRemovable());
554+
final StorageVolume primary = getPrimaryVolume();
555+
return (primary != null && primary.isRemovable());
462556
}
463557

464558
/**
@@ -475,12 +569,30 @@ public static boolean isExternalStorageRemovable() {
475569
* android.content.ComponentName, boolean)} for additional details.
476570
*/
477571
public static boolean isExternalStorageEmulated() {
478-
StorageVolume volume = getPrimaryVolume();
479-
return (volume != null && volume.isEmulated());
572+
final StorageVolume primary = getPrimaryVolume();
573+
return (primary != null && primary.isEmulated());
480574
}
481575

482576
static File getDirectory(String variableName, String defaultPath) {
483577
String path = System.getenv(variableName);
484578
return path == null ? new File(defaultPath) : new File(path);
485579
}
580+
581+
private static void throwIfSystem() {
582+
if (Process.myUid() == Process.SYSTEM_UID) {
583+
Log.wtf(TAG, "Static storage paths aren't available from AID_SYSTEM", new Throwable());
584+
}
585+
}
586+
587+
private static File buildPath(File base, String... segments) {
588+
File cur = base;
589+
for (String segment : segments) {
590+
if (cur == null) {
591+
cur = new File(segment);
592+
} else {
593+
cur = new File(cur, segment);
594+
}
595+
}
596+
return cur;
597+
}
486598
}

core/java/android/os/storage/IMountService.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -677,15 +677,15 @@ public int verifyEncryptionPassword(String password) throws RemoteException {
677677
return _result;
678678
}
679679

680-
public Parcelable[] getVolumeList() throws RemoteException {
680+
public StorageVolume[] getVolumeList() throws RemoteException {
681681
Parcel _data = Parcel.obtain();
682682
Parcel _reply = Parcel.obtain();
683-
Parcelable[] _result;
683+
StorageVolume[] _result;
684684
try {
685685
_data.writeInterfaceToken(DESCRIPTOR);
686686
mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0);
687687
_reply.readException();
688-
_result = _reply.readParcelableArray(StorageVolume.class.getClassLoader());
688+
_result = _reply.createTypedArray(StorageVolume.CREATOR);
689689
} finally {
690690
_reply.recycle();
691691
_data.recycle();
@@ -1119,9 +1119,9 @@ public boolean onTransact(int code, Parcel data, Parcel reply,
11191119
}
11201120
case TRANSACTION_getVolumeList: {
11211121
data.enforceInterface(DESCRIPTOR);
1122-
Parcelable[] result = getVolumeList();
1122+
StorageVolume[] result = getVolumeList();
11231123
reply.writeNoException();
1124-
reply.writeParcelableArray(result, 0);
1124+
reply.writeTypedArray(result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
11251125
return true;
11261126
}
11271127
case TRANSACTION_getSecureContainerFilesystemPath: {
@@ -1358,7 +1358,7 @@ public void unmountVolume(String mountPoint, boolean force, boolean removeEncryp
13581358
/**
13591359
* Returns list of all mountable volumes.
13601360
*/
1361-
public Parcelable[] getVolumeList() throws RemoteException;
1361+
public StorageVolume[] getVolumeList() throws RemoteException;
13621362

13631363
/**
13641364
* Gets the path on the filesystem for the ASEC container itself.

0 commit comments

Comments
 (0)