summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/Environment.java3
-rw-r--r--core/java/android/os/storage/IMountService.java8
-rw-r--r--core/java/android/os/storage/StorageManager.java11
-rw-r--r--core/java/android/os/storage/VolumeInfo.java35
-rw-r--r--services/core/java/com/android/server/MountService.java12
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()) {