diff --git a/core/api/system-current.txt b/core/api/system-current.txt index d54526d1c52b2..55dd8b2d81b49 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -8687,9 +8687,15 @@ package android.os.storage { method @WorkerThread public void allocateBytes(@NonNull java.util.UUID, long, @RequiresPermission int) throws java.io.IOException; method @WorkerThread public void allocateBytes(java.io.FileDescriptor, long, @RequiresPermission int) throws java.io.IOException; method @WorkerThread public long getAllocatableBytes(@NonNull java.util.UUID, @RequiresPermission int) throws java.io.IOException; + method @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public int getExternalStorageMountMode(int, @NonNull String); method public static boolean hasIsolatedStorage(); method public void updateExternalStorageFileQuotaType(@NonNull java.io.File, int) throws java.io.IOException; field @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1 + field public static final int MOUNT_MODE_EXTERNAL_ANDROID_WRITABLE = 4; // 0x4 + field public static final int MOUNT_MODE_EXTERNAL_DEFAULT = 1; // 0x1 + field public static final int MOUNT_MODE_EXTERNAL_INSTALLER = 2; // 0x2 + field public static final int MOUNT_MODE_EXTERNAL_NONE = 0; // 0x0 + field public static final int MOUNT_MODE_EXTERNAL_PASS_THROUGH = 3; // 0x3 field public static final int QUOTA_TYPE_MEDIA_AUDIO = 2; // 0x2 field public static final int QUOTA_TYPE_MEDIA_IMAGE = 1; // 0x1 field public static final int QUOTA_TYPE_MEDIA_NONE = 0; // 0x0 @@ -9014,6 +9020,8 @@ package android.provider { method @NonNull public static android.net.Uri setManageMode(@NonNull android.net.Uri); field public static final String ACTION_DOCUMENT_ROOT_SETTINGS = "android.provider.action.DOCUMENT_ROOT_SETTINGS"; field public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT"; + field public static final String DOWNLOADS_PROVIDER_AUTHORITY = "downloads"; + field public static final String EXTERNAL_STORAGE_PROVIDER_AUTHORITY = "com.android.externalstorage.documents"; field public static final String EXTRA_SHOW_ADVANCED = "android.provider.extra.SHOW_ADVANCED"; } diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl index 81c38f84849e0..9385402c3d72d 100644 --- a/core/java/android/os/storage/IStorageManager.aidl +++ b/core/java/android/os/storage/IStorageManager.aidl @@ -202,4 +202,5 @@ interface IStorageManager { void notifyAppIoResumed(in String volumeUuid, int uid, int tid, int reason) = 92; PendingIntent getManageSpaceActivityIntent(in String packageName, int requestCode) = 93; boolean isAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 94; - } + int getExternalStorageMountMode(int uid, in String packageName) = 95; +} diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index cae20ed90aa1f..81071682ab7e5 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -2124,6 +2124,52 @@ public class StorageManager { } } + + /** @hide */ + @IntDef(prefix = { "MOUNT_MODE_" }, value = { + MOUNT_MODE_EXTERNAL_NONE, + MOUNT_MODE_EXTERNAL_DEFAULT, + MOUNT_MODE_EXTERNAL_INSTALLER, + MOUNT_MODE_EXTERNAL_PASS_THROUGH, + MOUNT_MODE_EXTERNAL_ANDROID_WRITABLE + }) + /** @hide */ + public @interface MountMode {} + + /** + * No external storage should be mounted. + * @hide + */ + @SystemApi + public static final int MOUNT_MODE_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE; + /** + * Default external storage should be mounted. + * @hide + */ + @SystemApi + public static final int MOUNT_MODE_EXTERNAL_DEFAULT = IVold.REMOUNT_MODE_DEFAULT; + /** + * Mount mode for package installers which should give them access to + * all obb dirs in addition to their package sandboxes + * @hide + */ + @SystemApi + public static final int MOUNT_MODE_EXTERNAL_INSTALLER = IVold.REMOUNT_MODE_INSTALLER; + /** + * The lower file system should be bind mounted directly on external storage + * @hide + */ + @SystemApi + public static final int MOUNT_MODE_EXTERNAL_PASS_THROUGH = IVold.REMOUNT_MODE_PASS_THROUGH; + + /** + * Use the regular scoped storage filesystem, but Android/ should be writable. + * Used to support the applications hosting DownloadManager and the MTP server. + * @hide + */ + @SystemApi + public static final int MOUNT_MODE_EXTERNAL_ANDROID_WRITABLE = + IVold.REMOUNT_MODE_ANDROID_WRITABLE; /** * Flag indicating that a disk space allocation request should operate in an * aggressive mode. This flag should only be rarely used in situations that @@ -2300,6 +2346,28 @@ public class StorageManager { } } + /** + * Returns the External Storage mount mode corresponding to the given uid and packageName. + * These mount modes specify different views and access levels for + * different apps on external storage. + * + * @params uid UID of the application + * @params packageName name of the package + * @return {@code MountMode} for the given uid and packageName. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) + @SystemApi + @MountMode + public int getExternalStorageMountMode(int uid, @NonNull String packageName) { + try { + return mStorageManager.getExternalStorageMountMode(uid, packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Allocate the requested number of bytes for your application to use in the * given open file. This will cause the system to delete any cached files diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 0fea484429419..620fa6517ca58 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -236,10 +236,21 @@ public final class DocumentsContract { public static final String ACTION_DOCUMENT_ROOT_SETTINGS = "android.provider.action.DOCUMENT_ROOT_SETTINGS"; - /** {@hide} */ + /** + * External Storage Provider's authority string + * {@hide} + */ + @SystemApi public static final String EXTERNAL_STORAGE_PROVIDER_AUTHORITY = "com.android.externalstorage.documents"; + /** + * Download Manager's authority string + * {@hide} + */ + @SystemApi + public static final String DOWNLOADS_PROVIDER_AUTHORITY = Downloads.Impl.AUTHORITY; + /** {@hide} */ public static final String EXTERNAL_STORAGE_PRIMARY_EMULATED_ROOT_ID = "primary"; diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 5d1ca3336fa7c..09f4c221f3fe1 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -143,7 +143,6 @@ import com.android.internal.os.AppFuseMount; import com.android.internal.os.BackgroundThread; import com.android.internal.os.FuseUnavailableMountException; import com.android.internal.os.SomeArgs; -import com.android.internal.os.Zygote; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; @@ -4268,31 +4267,37 @@ class StorageManagerService extends IStorageManager.Stub } } + @Override + public int getExternalStorageMountMode(int uid, String packageName) { + enforcePermission(android.Manifest.permission.WRITE_MEDIA_STORAGE); + return mStorageManagerInternal.getExternalStorageMountMode(uid, packageName); + } + private int getMountModeInternal(int uid, String packageName) { try { // Get some easy cases out of the way first if (Process.isIsolated(uid)) { - return Zygote.MOUNT_EXTERNAL_NONE; + return StorageManager.MOUNT_MODE_EXTERNAL_NONE; } final String[] packagesForUid = mIPackageManager.getPackagesForUid(uid); if (ArrayUtils.isEmpty(packagesForUid)) { // It's possible the package got uninstalled already, so just ignore. - return Zygote.MOUNT_EXTERNAL_NONE; + return StorageManager.MOUNT_MODE_EXTERNAL_NONE; } if (packageName == null) { packageName = packagesForUid[0]; } if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) { - return Zygote.MOUNT_EXTERNAL_NONE; + return StorageManager.MOUNT_MODE_EXTERNAL_NONE; } if (mStorageManagerInternal.isExternalStorageService(uid)) { // Determine if caller requires pass_through mount; note that we do this for // all processes that share a UID with MediaProvider; but this is fine, since // those processes anyway share the same rights as MediaProvider. - return Zygote.MOUNT_EXTERNAL_PASS_THROUGH; + return StorageManager.MOUNT_MODE_EXTERNAL_PASS_THROUGH; } if ((mDownloadsAuthorityAppId == UserHandle.getAppId(uid) @@ -4300,7 +4305,7 @@ class StorageManagerService extends IStorageManager.Stub // DownloadManager can write in app-private directories on behalf of apps; // give it write access to Android/ // ExternalStorageProvider can access Android/{data,obb} dirs in managed mode - return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE; + return StorageManager.MOUNT_MODE_EXTERNAL_ANDROID_WRITABLE; } final boolean hasMtp = mIPackageManager.checkUidPermission(ACCESS_MTP, uid) == @@ -4310,7 +4315,7 @@ class StorageManagerService extends IStorageManager.Stub 0, UserHandle.getUserId(uid)); if (ai != null && ai.isSignedWithPlatformKey()) { // Platform processes hosting the MTP server should be able to write in Android/ - return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE; + return StorageManager.MOUNT_MODE_EXTERNAL_ANDROID_WRITABLE; } } @@ -4335,13 +4340,13 @@ class StorageManagerService extends IStorageManager.Stub } } if ((hasInstall || hasInstallOp) && hasWrite) { - return Zygote.MOUNT_EXTERNAL_INSTALLER; + return StorageManager.MOUNT_MODE_EXTERNAL_INSTALLER; } - return Zygote.MOUNT_EXTERNAL_DEFAULT; + return StorageManager.MOUNT_MODE_EXTERNAL_DEFAULT; } catch (RemoteException e) { // Should not happen } - return Zygote.MOUNT_EXTERNAL_NONE; + return StorageManager.MOUNT_MODE_EXTERNAL_NONE; } private static class Callbacks extends Handler { @@ -4711,7 +4716,8 @@ class StorageManagerService extends IStorageManager.Stub return true; } - return getExternalStorageMountMode(uid, packageName) != Zygote.MOUNT_EXTERNAL_NONE; + return getExternalStorageMountMode(uid, packageName) + != StorageManager.MOUNT_MODE_EXTERNAL_NONE; } private void killAppForOpChange(int code, int uid) {