diff options
-rw-r--r-- | core/java/android/os/Environment.java | 3 | ||||
-rw-r--r-- | core/java/android/os/storage/IMountService.java | 8 | ||||
-rw-r--r-- | core/java/android/os/storage/StorageManager.java | 11 | ||||
-rw-r--r-- | core/java/android/os/storage/VolumeInfo.java | 35 | ||||
-rw-r--r-- | services/core/java/com/android/server/MountService.java | 12 |
5 files changed, 52 insertions, 17 deletions
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 2080856..64d6da5 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -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(); diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index c3b098b..fce09dd 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -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(); @@ -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); @@ -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; @@ -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. diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index b2cec60..d1f3743 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -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; @@ -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} */ @@ -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 { @@ -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(); } diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java index 8d603a1..ef54d84 100644 --- a/core/java/android/os/storage/VolumeInfo.java +++ b/core/java/android/os/storage/VolumeInfo.java @@ -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 */ @@ -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(); @@ -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)); @@ -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"); diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index 857394f..6ab2fd7 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -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; @@ -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(); @@ -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(); @@ -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( @@ -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()) { |