Loading core/java/android/os/Environment.java +2 −1 Original line number Diff line number Diff line Loading @@ -80,7 +80,8 @@ public class Environment { } public File[] getExternalDirs() { final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId); final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId, StorageManager.FLAG_FOR_WRITE); final File[] files = new File[volumes.length]; for (int i = 0; i < volumes.length; i++) { files[i] = volumes[i].getPathFile(); Loading core/java/android/os/storage/IMountService.java +5 −3 Original line number Diff line number Diff line Loading @@ -758,7 +758,7 @@ public interface IMountService extends IInterface { return _result; } public StorageVolume[] getVolumeList(int uid, String packageName) public StorageVolume[] getVolumeList(int uid, String packageName, int flags) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); Loading @@ -767,6 +767,7 @@ public interface IMountService extends IInterface { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(uid); _data.writeString(packageName); _data.writeInt(flags); mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArray(StorageVolume.CREATOR); Loading Loading @@ -1609,7 +1610,8 @@ public interface IMountService extends IInterface { data.enforceInterface(DESCRIPTOR); int uid = data.readInt(); String packageName = data.readString(); StorageVolume[] result = getVolumeList(uid, packageName); int _flags = data.readInt(); StorageVolume[] result = getVolumeList(uid, packageName, _flags); reply.writeNoException(); reply.writeTypedArray(result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); return true; Loading Loading @@ -2059,7 +2061,7 @@ public interface IMountService extends IInterface { /** * Returns list of all mountable volumes. */ public StorageVolume[] getVolumeList(int uid, String packageName) throws RemoteException; public StorageVolume[] getVolumeList(int uid, String packageName, int flags) throws RemoteException; /** * Gets the path on the filesystem for the ASEC container itself. Loading core/java/android/os/storage/StorageManager.java +7 −4 Original line number Diff line number Diff line Loading @@ -86,6 +86,9 @@ public class StorageManager { /** {@hide} */ public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0; /** {@hide} */ public static final int FLAG_FOR_WRITE = 1 << 0; private final Context mContext; private final ContentResolver mResolver; Loading Loading @@ -812,7 +815,7 @@ public class StorageManager { /** {@hide} */ public static @Nullable StorageVolume getStorageVolume(File file, int userId) { return getStorageVolume(getVolumeList(userId), file); return getStorageVolume(getVolumeList(userId, 0), file); } /** {@hide} */ Loading Loading @@ -852,11 +855,11 @@ public class StorageManager { /** {@hide} */ public @NonNull StorageVolume[] getVolumeList() { return getVolumeList(mContext.getUserId()); return getVolumeList(mContext.getUserId(), 0); } /** {@hide} */ public static @NonNull StorageVolume[] getVolumeList(int userId) { public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) { final IMountService mountService = IMountService.Stub.asInterface( ServiceManager.getService("mount")); try { Loading @@ -877,7 +880,7 @@ public class StorageManager { if (uid <= 0) { return new StorageVolume[0]; } return mountService.getVolumeList(uid, packageName); return mountService.getVolumeList(uid, packageName, flags); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } Loading core/java/android/os/storage/VolumeInfo.java +32 −3 Original line number Diff line number Diff line Loading @@ -46,6 +46,19 @@ import java.util.Objects; * Information about a storage volume that may be mounted. A volume may be a * partition on a physical {@link DiskInfo}, an emulated volume above some other * storage medium, or a standalone container like an ASEC or OBB. * <p> * Volumes may be mounted with various flags: * <ul> * <li>{@link #MOUNT_FLAG_PRIMARY} means the volume provides primary external * storage, historically found at {@code /sdcard}. * <li>{@link #MOUNT_FLAG_VISIBLE} means the volume is visible to third-party * apps for direct filesystem access. The system should send out relevant * storage broadcasts and index any media on visible volumes. Visible volumes * are considered a more stable part of the device, which is why we take the * time to index them. In particular, transient volumes like USB OTG devices * <em>should not</em> be marked as visible; their contents should be surfaced * to apps through the Storage Access Framework. * </ul> * * @hide */ Loading Loading @@ -255,8 +268,23 @@ public class VolumeInfo implements Parcelable { return (mountFlags & MOUNT_FLAG_VISIBLE) != 0; } public boolean isVisibleToUser(int userId) { if (type == TYPE_PUBLIC && userId == this.mountUserId) { public boolean isVisibleForRead(int userId) { if (type == TYPE_PUBLIC) { if (isPrimary() && mountUserId != userId) { // Primary physical is only visible to single user return false; } else { return isVisible(); } } else if (type == TYPE_EMULATED) { return isVisible(); } else { return false; } } public boolean isVisibleForWrite(int userId) { if (type == TYPE_PUBLIC && mountUserId == userId) { return isVisible(); } else if (type == TYPE_EMULATED) { return isVisible(); Loading @@ -276,7 +304,7 @@ public class VolumeInfo implements Parcelable { public File getPathForUser(int userId) { if (path == null) { return null; } else if (type == TYPE_PUBLIC && userId == this.mountUserId) { } else if (type == TYPE_PUBLIC) { return new File(path); } else if (type == TYPE_EMULATED) { return new File(path, Integer.toString(userId)); Loading Loading @@ -306,6 +334,7 @@ public class VolumeInfo implements Parcelable { final boolean allowMassStorage = false; final String envState = reportUnmounted ? Environment.MEDIA_UNMOUNTED : getEnvironmentForState(state); File userPath = getPathForUser(userId); if (userPath == null) { userPath = new File("/dev/null"); Loading services/core/java/com/android/server/MountService.java +6 −6 Original line number Diff line number Diff line Loading @@ -69,7 +69,6 @@ import android.os.storage.IMountServiceListener; import android.os.storage.IMountShutdownObserver; import android.os.storage.IObbActionListener; import android.os.storage.MountServiceInternal; import android.os.storage.MountServiceInternal.ExternalStorageMountPolicy; import android.os.storage.OnObbStateChangeListener; import android.os.storage.StorageManager; import android.os.storage.StorageResultCode; Loading Loading @@ -809,7 +808,7 @@ class MountService extends IMountService.Stub synchronized (mVolumes) { for (int i = 0; i < mVolumes.size(); i++) { final VolumeInfo vol = mVolumes.valueAt(i); if (vol.isVisibleToUser(userId) && vol.isMountedReadable()) { if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) { final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget(); Loading Loading @@ -1252,7 +1251,7 @@ class MountService extends IMountService.Stub // started after this point will trigger additional // user-specific broadcasts. for (int userId : mStartedUsers) { if (vol.isVisibleToUser(userId)) { if (vol.isVisibleForRead(userId)) { final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget(); Loading Loading @@ -2610,13 +2609,14 @@ class MountService extends IMountService.Stub } @Override public StorageVolume[] getVolumeList(int uid, String packageName) { public StorageVolume[] getVolumeList(int uid, String packageName, int flags) { final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0; final ArrayList<StorageVolume> res = new ArrayList<>(); boolean foundPrimary = false; final int userId = UserHandle.getUserId(uid); final boolean reportUnmounted; final long identity = Binder.clearCallingIdentity(); try { reportUnmounted = !mMountServiceInternal.hasExternalStorage( Loading @@ -2628,7 +2628,7 @@ class MountService extends IMountService.Stub synchronized (mLock) { for (int i = 0; i < mVolumes.size(); i++) { final VolumeInfo vol = mVolumes.valueAt(i); if (vol.isVisibleToUser(userId)) { if (forWrite ? vol.isVisibleForWrite(userId) : vol.isVisibleForRead(userId)) { final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, reportUnmounted); if (vol.isPrimary()) { Loading Loading
core/java/android/os/Environment.java +2 −1 Original line number Diff line number Diff line Loading @@ -80,7 +80,8 @@ public class Environment { } public File[] getExternalDirs() { final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId); final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId, StorageManager.FLAG_FOR_WRITE); final File[] files = new File[volumes.length]; for (int i = 0; i < volumes.length; i++) { files[i] = volumes[i].getPathFile(); Loading
core/java/android/os/storage/IMountService.java +5 −3 Original line number Diff line number Diff line Loading @@ -758,7 +758,7 @@ public interface IMountService extends IInterface { return _result; } public StorageVolume[] getVolumeList(int uid, String packageName) public StorageVolume[] getVolumeList(int uid, String packageName, int flags) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); Loading @@ -767,6 +767,7 @@ public interface IMountService extends IInterface { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(uid); _data.writeString(packageName); _data.writeInt(flags); mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArray(StorageVolume.CREATOR); Loading Loading @@ -1609,7 +1610,8 @@ public interface IMountService extends IInterface { data.enforceInterface(DESCRIPTOR); int uid = data.readInt(); String packageName = data.readString(); StorageVolume[] result = getVolumeList(uid, packageName); int _flags = data.readInt(); StorageVolume[] result = getVolumeList(uid, packageName, _flags); reply.writeNoException(); reply.writeTypedArray(result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); return true; Loading Loading @@ -2059,7 +2061,7 @@ public interface IMountService extends IInterface { /** * Returns list of all mountable volumes. */ public StorageVolume[] getVolumeList(int uid, String packageName) throws RemoteException; public StorageVolume[] getVolumeList(int uid, String packageName, int flags) throws RemoteException; /** * Gets the path on the filesystem for the ASEC container itself. Loading
core/java/android/os/storage/StorageManager.java +7 −4 Original line number Diff line number Diff line Loading @@ -86,6 +86,9 @@ public class StorageManager { /** {@hide} */ public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0; /** {@hide} */ public static final int FLAG_FOR_WRITE = 1 << 0; private final Context mContext; private final ContentResolver mResolver; Loading Loading @@ -812,7 +815,7 @@ public class StorageManager { /** {@hide} */ public static @Nullable StorageVolume getStorageVolume(File file, int userId) { return getStorageVolume(getVolumeList(userId), file); return getStorageVolume(getVolumeList(userId, 0), file); } /** {@hide} */ Loading Loading @@ -852,11 +855,11 @@ public class StorageManager { /** {@hide} */ public @NonNull StorageVolume[] getVolumeList() { return getVolumeList(mContext.getUserId()); return getVolumeList(mContext.getUserId(), 0); } /** {@hide} */ public static @NonNull StorageVolume[] getVolumeList(int userId) { public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) { final IMountService mountService = IMountService.Stub.asInterface( ServiceManager.getService("mount")); try { Loading @@ -877,7 +880,7 @@ public class StorageManager { if (uid <= 0) { return new StorageVolume[0]; } return mountService.getVolumeList(uid, packageName); return mountService.getVolumeList(uid, packageName, flags); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } Loading
core/java/android/os/storage/VolumeInfo.java +32 −3 Original line number Diff line number Diff line Loading @@ -46,6 +46,19 @@ import java.util.Objects; * Information about a storage volume that may be mounted. A volume may be a * partition on a physical {@link DiskInfo}, an emulated volume above some other * storage medium, or a standalone container like an ASEC or OBB. * <p> * Volumes may be mounted with various flags: * <ul> * <li>{@link #MOUNT_FLAG_PRIMARY} means the volume provides primary external * storage, historically found at {@code /sdcard}. * <li>{@link #MOUNT_FLAG_VISIBLE} means the volume is visible to third-party * apps for direct filesystem access. The system should send out relevant * storage broadcasts and index any media on visible volumes. Visible volumes * are considered a more stable part of the device, which is why we take the * time to index them. In particular, transient volumes like USB OTG devices * <em>should not</em> be marked as visible; their contents should be surfaced * to apps through the Storage Access Framework. * </ul> * * @hide */ Loading Loading @@ -255,8 +268,23 @@ public class VolumeInfo implements Parcelable { return (mountFlags & MOUNT_FLAG_VISIBLE) != 0; } public boolean isVisibleToUser(int userId) { if (type == TYPE_PUBLIC && userId == this.mountUserId) { public boolean isVisibleForRead(int userId) { if (type == TYPE_PUBLIC) { if (isPrimary() && mountUserId != userId) { // Primary physical is only visible to single user return false; } else { return isVisible(); } } else if (type == TYPE_EMULATED) { return isVisible(); } else { return false; } } public boolean isVisibleForWrite(int userId) { if (type == TYPE_PUBLIC && mountUserId == userId) { return isVisible(); } else if (type == TYPE_EMULATED) { return isVisible(); Loading @@ -276,7 +304,7 @@ public class VolumeInfo implements Parcelable { public File getPathForUser(int userId) { if (path == null) { return null; } else if (type == TYPE_PUBLIC && userId == this.mountUserId) { } else if (type == TYPE_PUBLIC) { return new File(path); } else if (type == TYPE_EMULATED) { return new File(path, Integer.toString(userId)); Loading Loading @@ -306,6 +334,7 @@ public class VolumeInfo implements Parcelable { final boolean allowMassStorage = false; final String envState = reportUnmounted ? Environment.MEDIA_UNMOUNTED : getEnvironmentForState(state); File userPath = getPathForUser(userId); if (userPath == null) { userPath = new File("/dev/null"); Loading
services/core/java/com/android/server/MountService.java +6 −6 Original line number Diff line number Diff line Loading @@ -69,7 +69,6 @@ import android.os.storage.IMountServiceListener; import android.os.storage.IMountShutdownObserver; import android.os.storage.IObbActionListener; import android.os.storage.MountServiceInternal; import android.os.storage.MountServiceInternal.ExternalStorageMountPolicy; import android.os.storage.OnObbStateChangeListener; import android.os.storage.StorageManager; import android.os.storage.StorageResultCode; Loading Loading @@ -809,7 +808,7 @@ class MountService extends IMountService.Stub synchronized (mVolumes) { for (int i = 0; i < mVolumes.size(); i++) { final VolumeInfo vol = mVolumes.valueAt(i); if (vol.isVisibleToUser(userId) && vol.isMountedReadable()) { if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) { final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget(); Loading Loading @@ -1252,7 +1251,7 @@ class MountService extends IMountService.Stub // started after this point will trigger additional // user-specific broadcasts. for (int userId : mStartedUsers) { if (vol.isVisibleToUser(userId)) { if (vol.isVisibleForRead(userId)) { final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget(); Loading Loading @@ -2610,13 +2609,14 @@ class MountService extends IMountService.Stub } @Override public StorageVolume[] getVolumeList(int uid, String packageName) { public StorageVolume[] getVolumeList(int uid, String packageName, int flags) { final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0; final ArrayList<StorageVolume> res = new ArrayList<>(); boolean foundPrimary = false; final int userId = UserHandle.getUserId(uid); final boolean reportUnmounted; final long identity = Binder.clearCallingIdentity(); try { reportUnmounted = !mMountServiceInternal.hasExternalStorage( Loading @@ -2628,7 +2628,7 @@ class MountService extends IMountService.Stub synchronized (mLock) { for (int i = 0; i < mVolumes.size(); i++) { final VolumeInfo vol = mVolumes.valueAt(i); if (vol.isVisibleToUser(userId)) { if (forWrite ? vol.isVisibleForWrite(userId) : vol.isVisibleForRead(userId)) { final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, reportUnmounted); if (vol.isPrimary()) { Loading