Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 839aa852 authored by Abhijeet Kaur's avatar Abhijeet Kaur
Browse files

Make getExternalStorageMountMode as SystemApi

Secondary volumes are FUSE mounted, whereas Android/data and Android/obb
on primary volumes are not FUSE mounted. Access to these private app
directories on primary volumes is restricted using the mount modes, but
access for these on secondary volumes need to be regulated by
MediaProvider.

Make getExternalStorageMountMode as SystemApi so that MediaProvider
can leverage the same mount logic for Secondary volumes.
Expose relevant mount modes as SystemApi as well.

This change saves us the maintenance overhead for Secondary volumes for
Android S+. Otherwise we would have to check if an app is a signature
app through APIs which would basically be the duplication for the
logic in StorageManagerService.java.

Expose ExternalStorageProvider and downloads Authority for MediaProvider
to rely only on APIs. This is also required for CDD modifications that
these 2 providers are given exceptional access to private app dirs.

Bug: 175796984
Bug: 173505864
Bug: 173505864
Test: atest DownloadProviderTest
Test: atest CtsScopedStorageHostTest
Test: atest android.scopedstorage.cts.host.PublicVolumeHostTest#testCheckInstallerAppAccessToObbDirs
Test: atest android.scopedstorage.cts.host.PublicVolumeHostTest#testCantAccessOtherAppsExternalDirs
Change-Id: I51bc7bd3f355fadd9de56ac267469c2352eb0ffa
parent 20be4016
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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";
  }
+1 −0
Original line number Diff line number Diff line
@@ -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;
}
+68 −0
Original line number Diff line number Diff line
@@ -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
+12 −1
Original line number Diff line number Diff line
@@ -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";

+17 −11
Original line number Diff line number Diff line
@@ -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) {