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 Merged-In: I51bc7bd3f355fadd9de56ac267469c2352eb0ffa
This commit is contained in:
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user