Merge "Apps using storage must have runtime permission."
This commit is contained in:
@@ -135,6 +135,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
@SystemService(Context.STORAGE_SERVICE)
|
||||
public class StorageManager {
|
||||
private static final String TAG = "StorageManager";
|
||||
private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
/** {@hide} */
|
||||
public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
|
||||
@@ -1652,13 +1653,11 @@ public class StorageManager {
|
||||
|
||||
/**
|
||||
* Check that given app holds both permission and appop.
|
||||
*
|
||||
* @return {@code null} if the permission and appop are held, otherwise
|
||||
* returns a string indicating why access was denied.
|
||||
* @hide
|
||||
*/
|
||||
private boolean checkPermissionAndAppOp(boolean enforce, int pid, int uid, String packageName,
|
||||
String permission, int op) {
|
||||
if (mContext.checkPermission(permission, pid, uid) != PERMISSION_GRANTED) {
|
||||
public static boolean checkPermissionAndAppOp(Context context, boolean enforce,
|
||||
int pid, int uid, String packageName, String permission, int op) {
|
||||
if (context.checkPermission(permission, pid, uid) != PERMISSION_GRANTED) {
|
||||
if (enforce) {
|
||||
throw new SecurityException(
|
||||
"Permission " + permission + " denied for package " + packageName);
|
||||
@@ -1667,7 +1666,7 @@ public class StorageManager {
|
||||
}
|
||||
}
|
||||
|
||||
final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
|
||||
final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
|
||||
final int mode = appOps.noteOpNoThrow(op, uid, packageName);
|
||||
switch (mode) {
|
||||
case AppOpsManager.MODE_ALLOWED:
|
||||
@@ -1688,6 +1687,11 @@ public class StorageManager {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkPermissionAndAppOp(boolean enforce,
|
||||
int pid, int uid, String packageName, String permission, int op) {
|
||||
return checkPermissionAndAppOp(mContext, enforce, pid, uid, packageName, permission, op);
|
||||
}
|
||||
|
||||
// Callers must hold both the old and new permissions, so that we can
|
||||
// handle obscure cases like when an app targets Q but was installed on
|
||||
// a device that was originally running on P before being upgraded to Q.
|
||||
|
||||
@@ -17,10 +17,14 @@
|
||||
package com.android.server;
|
||||
|
||||
import static android.Manifest.permission.INSTALL_PACKAGES;
|
||||
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
|
||||
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||
import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
|
||||
import static android.app.AppOpsManager.MODE_ALLOWED;
|
||||
import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
|
||||
import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE;
|
||||
import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
|
||||
import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE;
|
||||
import static android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN;
|
||||
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
|
||||
import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
||||
@@ -280,6 +284,7 @@ class StorageManagerService extends IStorageManager.Stub
|
||||
private static final boolean EMULATE_FBE_SUPPORTED = true;
|
||||
|
||||
private static final String TAG = "StorageManagerService";
|
||||
private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
|
||||
private static final String TAG_STORAGE_TRIM = "storage_trim";
|
||||
@@ -3863,44 +3868,57 @@ class StorageManagerService extends IStorageManager.Stub
|
||||
}
|
||||
|
||||
private int getMountMode(int uid, String packageName) {
|
||||
final int mode = getMountModeInternal(uid, packageName);
|
||||
if (LOCAL_LOGV) {
|
||||
Slog.v(TAG, "Resolved mode " + mode + " for " + packageName + "/"
|
||||
+ UserHandle.formatUid(uid));
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE, uid)
|
||||
== PERMISSION_GRANTED) {
|
||||
return Zygote.MOUNT_EXTERNAL_FULL;
|
||||
} else if (mIAppOpsService.checkOperation(OP_LEGACY_STORAGE, uid,
|
||||
packageName) == MODE_ALLOWED) {
|
||||
return Zygote.MOUNT_EXTERNAL_LEGACY;
|
||||
} else if (mIPackageManager.checkUidPermission(INSTALL_PACKAGES, uid)
|
||||
== PERMISSION_GRANTED || mIAppOpsService.checkOperation(
|
||||
OP_REQUEST_INSTALL_PACKAGES, uid, packageName) == MODE_ALLOWED) {
|
||||
return Zygote.MOUNT_EXTERNAL_INSTALLER;
|
||||
} else if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
|
||||
if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
|
||||
return Zygote.MOUNT_EXTERNAL_NONE;
|
||||
}
|
||||
|
||||
// Determine if caller is holding runtime permission
|
||||
final boolean hasRead = StorageManager.checkPermissionAndAppOp(mContext, false, 0,
|
||||
uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
|
||||
final boolean hasWrite = StorageManager.checkPermissionAndAppOp(mContext, false, 0,
|
||||
uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE);
|
||||
final boolean hasStorage = hasRead || hasWrite;
|
||||
|
||||
// We're only willing to give out broad access if they also hold
|
||||
// runtime permission; this is a firm CDD requirement
|
||||
final boolean hasFull = mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE,
|
||||
uid) == PERMISSION_GRANTED;
|
||||
if (hasFull && hasStorage) {
|
||||
return Zygote.MOUNT_EXTERNAL_FULL;
|
||||
}
|
||||
|
||||
// We're only willing to give out installer access if they also hold
|
||||
// runtime permission; this is a firm CDD requirement
|
||||
final boolean hasInstall = mIPackageManager.checkUidPermission(INSTALL_PACKAGES,
|
||||
uid) == PERMISSION_GRANTED;
|
||||
final boolean hasInstallOp = mIAppOpsService.checkOperation(OP_REQUEST_INSTALL_PACKAGES,
|
||||
uid, packageName) == MODE_ALLOWED;
|
||||
if ((hasInstall || hasInstallOp) && hasStorage) {
|
||||
return Zygote.MOUNT_EXTERNAL_INSTALLER;
|
||||
}
|
||||
|
||||
// Otherwise we're willing to give out sandboxed or non-sandboxed if
|
||||
// they hold the runtime permission
|
||||
final boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE,
|
||||
uid, packageName) == MODE_ALLOWED;
|
||||
final boolean hasGreylist = isLegacyGreylisted(packageName);
|
||||
if ((hasLegacy || hasGreylist) && hasStorage) {
|
||||
return Zygote.MOUNT_EXTERNAL_LEGACY;
|
||||
} else {
|
||||
if (ENABLE_LEGACY_GREYLIST) {
|
||||
// STOPSHIP: remove this temporary workaround once developers
|
||||
// fix bugs where they're opening _data paths in native code
|
||||
switch (packageName) {
|
||||
case "com.facebook.katana": // b/123996076
|
||||
case "jp.naver.line.android": // b/124767356
|
||||
case "com.mxtech.videoplayer.ad": // b/124531483
|
||||
case "com.whatsapp": // b/124766614
|
||||
case "com.maxmpz.audioplayer": // b/127886230
|
||||
case "com.estrongs.android.pop": // b/127926473
|
||||
case "com.roidapp.photogrid": // b/128269119
|
||||
case "com.cleanmaster.mguard": // b/128384413
|
||||
case "com.skype.raider": // b/128487044
|
||||
case "org.telegram.messenger": // b/128652960
|
||||
case "com.jrtstudio.AnotherMusicPlayer": // b/129084562
|
||||
case "ak.alizandro.smartaudiobookplayer": // b/129084042
|
||||
case "com.campmobile.snow": // b/128803870
|
||||
case "com.qnap.qfile": // b/126374406
|
||||
return Zygote.MOUNT_EXTERNAL_LEGACY;
|
||||
}
|
||||
}
|
||||
return Zygote.MOUNT_EXTERNAL_WRITE;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
@@ -3909,6 +3927,32 @@ class StorageManagerService extends IStorageManager.Stub
|
||||
return Zygote.MOUNT_EXTERNAL_NONE;
|
||||
}
|
||||
|
||||
private boolean isLegacyGreylisted(String packageName) {
|
||||
// TODO: decide legacy defaults at install time based on signals
|
||||
if (ENABLE_LEGACY_GREYLIST) {
|
||||
// STOPSHIP: remove this temporary workaround once developers
|
||||
// fix bugs where they're opening _data paths in native code
|
||||
switch (packageName) {
|
||||
case "com.facebook.katana": // b/123996076
|
||||
case "jp.naver.line.android": // b/124767356
|
||||
case "com.mxtech.videoplayer.ad": // b/124531483
|
||||
case "com.whatsapp": // b/124766614
|
||||
case "com.maxmpz.audioplayer": // b/127886230
|
||||
case "com.estrongs.android.pop": // b/127926473
|
||||
case "com.roidapp.photogrid": // b/128269119
|
||||
case "com.cleanmaster.mguard": // b/128384413
|
||||
case "com.skype.raider": // b/128487044
|
||||
case "org.telegram.messenger": // b/128652960
|
||||
case "com.jrtstudio.AnotherMusicPlayer": // b/129084562
|
||||
case "ak.alizandro.smartaudiobookplayer": // b/129084042
|
||||
case "com.campmobile.snow": // b/128803870
|
||||
case "com.qnap.qfile": // b/126374406
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class Callbacks extends Handler {
|
||||
private static final int MSG_STORAGE_STATE_CHANGED = 1;
|
||||
private static final int MSG_VOLUME_STATE_CHANGED = 2;
|
||||
|
||||
Reference in New Issue
Block a user