diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 8124e1c422461..d9e9a0a143a11 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -8670,9 +8670,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 @@ -8997,6 +9003,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 5fe870fc57e64..d42b147e7ca5a 100644 --- a/core/java/android/os/storage/IStorageManager.aidl +++ b/core/java/android/os/storage/IStorageManager.aidl @@ -201,4 +201,5 @@ interface IStorageManager { PendingIntent getManageSpaceActivityIntent(in String packageName, int requestCode) = 91; void notifyAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 92; void notifyAppIoResumed(in String volumeUuid, int uid, int tid, int reason) = 93; + int getExternalStorageMountMode(int uid, in String packageName) = 94; } diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index c967deb5e810e..6fa59696fe1d9 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 fac6431e1520b..ff7f2b2d41c49 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; @@ -4259,31 +4258,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) @@ -4291,7 +4296,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) == @@ -4301,7 +4306,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; } } @@ -4326,13 +4331,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 { @@ -4702,7 +4707,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) {