Merge "Revert "Update storage permission policy to use AppCompat APIs."" into rvc-dev am: 7d647467f5

Change-Id: I239a09670d19628e817a999b82f13754350fc7b7
This commit is contained in:
Automerger Merge Worker
2020-03-01 13:13:45 +00:00

View File

@@ -27,23 +27,18 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYST
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static java.lang.Integer.min;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Binder; import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.storage.StorageManagerInternal; import android.os.storage.StorageManagerInternal;
import android.util.Log;
import com.android.internal.compat.IPlatformCompat;
import com.android.server.LocalServices; import com.android.server.LocalServices;
import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -55,27 +50,6 @@ import com.android.server.pm.parsing.pkg.AndroidPackage;
* {@link com.android.packageinstaller.permission.utils.SoftRestrictedPermissionPolicy} * {@link com.android.packageinstaller.permission.utils.SoftRestrictedPermissionPolicy}
*/ */
public abstract class SoftRestrictedPermissionPolicy { public abstract class SoftRestrictedPermissionPolicy {
/**
* Enables scoped storage, with exceptions for apps that explicitly request legacy access, or
* apps that hold the {@code android.Manifest.permission#WRITE_MEDIA_STORAGE} permission.
* See https://developer.android.com/training/data-storage#scoped-storage for more information.
*/
@ChangeId
// This change is enabled for apps with targetSDK > {@link android.os.Build.VERSION_CODES.P}
@EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.P)
static final long ENABLE_SCOPED_STORAGE = 144914977L;
/**
* Enforces scoped storage for all apps, preventing individual apps from opting out. This change
* has precedence over {@code ENABLE_SCOPED_STORAGE}.
*/
@ChangeId
// This change is enabled for apps with targetSDK > {@link android.os.Build.VERSION_CODES.Q}.
@EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q)
static final long REQUIRE_SCOPED_STORAGE = 131432978L;
private static final String LOG_TAG = SoftRestrictedPermissionPolicy.class.getSimpleName();
private static final int FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT = private static final int FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT =
FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
| FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT
@@ -89,6 +63,41 @@ public abstract class SoftRestrictedPermissionPolicy {
} }
}; };
/**
* TargetSDK is per package. To make sure two apps int the same shared UID do not fight over
* what to set, always compute the combined targetSDK.
*
* @param context A context
* @param appInfo The app that is changed
* @param user The user the app belongs to
*
* @return The minimum targetSDK of all apps sharing the uid of the app
*/
private static int getMinimumTargetSDK(@NonNull Context context,
@NonNull ApplicationInfo appInfo, @NonNull UserHandle user) {
PackageManager pm = context.getPackageManager();
int minimumTargetSDK = appInfo.targetSdkVersion;
String[] uidPkgs = pm.getPackagesForUid(appInfo.uid);
if (uidPkgs != null) {
for (String uidPkg : uidPkgs) {
if (!uidPkg.equals(appInfo.packageName)) {
ApplicationInfo uidPkgInfo;
try {
uidPkgInfo = pm.getApplicationInfoAsUser(uidPkg, 0, user);
} catch (PackageManager.NameNotFoundException e) {
continue;
}
minimumTargetSDK = min(minimumTargetSDK, uidPkgInfo.targetSdkVersion);
}
}
}
return minimumTargetSDK;
}
/** /**
* Get the policy for a soft restricted permission. * Get the policy for a soft restricted permission.
* *
@@ -109,10 +118,10 @@ public abstract class SoftRestrictedPermissionPolicy {
case READ_EXTERNAL_STORAGE: { case READ_EXTERNAL_STORAGE: {
final boolean isWhiteListed; final boolean isWhiteListed;
boolean shouldApplyRestriction; boolean shouldApplyRestriction;
final int targetSDK;
final boolean hasRequestedLegacyExternalStorage; final boolean hasRequestedLegacyExternalStorage;
final boolean shouldPreserveLegacyExternalStorage; final boolean shouldPreserveLegacyExternalStorage;
final boolean hasWriteMediaStorageGrantedForUid; final boolean hasWriteMediaStorageGrantedForUid;
final boolean isScopedStorageEnabled;
if (appInfo != null) { if (appInfo != null) {
PackageManager pm = context.getPackageManager(); PackageManager pm = context.getPackageManager();
@@ -124,22 +133,19 @@ public abstract class SoftRestrictedPermissionPolicy {
appInfo.uid, context); appInfo.uid, context);
hasWriteMediaStorageGrantedForUid = hasWriteMediaStorageGrantedForUid( hasWriteMediaStorageGrantedForUid = hasWriteMediaStorageGrantedForUid(
appInfo.uid, context); appInfo.uid, context);
final boolean isScopedStorageRequired =
isChangeEnabledForUid(context, appInfo, user, REQUIRE_SCOPED_STORAGE);
isScopedStorageEnabled =
isChangeEnabledForUid(context, appInfo, user, ENABLE_SCOPED_STORAGE)
|| isScopedStorageRequired;
shouldPreserveLegacyExternalStorage = pkg.hasPreserveLegacyExternalStorage() shouldPreserveLegacyExternalStorage = pkg.hasPreserveLegacyExternalStorage()
&& smInternal.hasLegacyExternalStorage(appInfo.uid); && smInternal.hasLegacyExternalStorage(appInfo.uid);
targetSDK = getMinimumTargetSDK(context, appInfo, user);
shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0 shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0
|| (isScopedStorageRequired && !shouldPreserveLegacyExternalStorage); || (targetSDK > Build.VERSION_CODES.Q
&& !shouldPreserveLegacyExternalStorage);
} else { } else {
isWhiteListed = false; isWhiteListed = false;
shouldApplyRestriction = false; shouldApplyRestriction = false;
targetSDK = 0;
hasRequestedLegacyExternalStorage = false; hasRequestedLegacyExternalStorage = false;
shouldPreserveLegacyExternalStorage = false; shouldPreserveLegacyExternalStorage = false;
hasWriteMediaStorageGrantedForUid = false; hasWriteMediaStorageGrantedForUid = false;
isScopedStorageEnabled = false;
} }
// We have a check in PermissionPolicyService.PermissionToOpSynchroniser.setUidMode // We have a check in PermissionPolicyService.PermissionToOpSynchroniser.setUidMode
@@ -149,7 +155,7 @@ public abstract class SoftRestrictedPermissionPolicy {
return new SoftRestrictedPermissionPolicy() { return new SoftRestrictedPermissionPolicy() {
@Override @Override
public boolean mayGrantPermission() { public boolean mayGrantPermission() {
return isWhiteListed || isScopedStorageEnabled; return isWhiteListed || targetSDK >= Build.VERSION_CODES.Q;
} }
@Override @Override
public int getExtraAppOpCode() { public int getExtraAppOpCode() {
@@ -157,7 +163,7 @@ public abstract class SoftRestrictedPermissionPolicy {
} }
@Override @Override
public boolean mayAllowExtraAppOp() { public boolean mayAllowExtraAppOp() {
return !shouldApplyRestriction return !shouldApplyRestriction && targetSDK <= Build.VERSION_CODES.Q
&& (hasRequestedLegacyExternalStorage && (hasRequestedLegacyExternalStorage
|| hasWriteMediaStorageGrantedForUid || hasWriteMediaStorageGrantedForUid
|| shouldPreserveLegacyExternalStorage); || shouldPreserveLegacyExternalStorage);
@@ -170,26 +176,22 @@ public abstract class SoftRestrictedPermissionPolicy {
} }
case WRITE_EXTERNAL_STORAGE: { case WRITE_EXTERNAL_STORAGE: {
final boolean isWhiteListed; final boolean isWhiteListed;
final boolean isScopedStorageEnabled; final int targetSDK;
if (appInfo != null) { if (appInfo != null) {
final int flags = context.getPackageManager().getPermissionFlags(permission, final int flags = context.getPackageManager().getPermissionFlags(permission,
appInfo.packageName, user); appInfo.packageName, user);
isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0; isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
final boolean isScopedStorageRequired = targetSDK = getMinimumTargetSDK(context, appInfo, user);
isChangeEnabledForUid(context, appInfo, user, REQUIRE_SCOPED_STORAGE);
isScopedStorageEnabled =
isChangeEnabledForUid(context, appInfo, user, ENABLE_SCOPED_STORAGE)
|| isScopedStorageRequired;
} else { } else {
isWhiteListed = false; isWhiteListed = false;
isScopedStorageEnabled = false; targetSDK = 0;
} }
return new SoftRestrictedPermissionPolicy() { return new SoftRestrictedPermissionPolicy() {
@Override @Override
public boolean mayGrantPermission() { public boolean mayGrantPermission() {
return isWhiteListed || isScopedStorageEnabled; return isWhiteListed || targetSDK >= Build.VERSION_CODES.Q;
} }
}; };
} }
@@ -198,62 +200,6 @@ public abstract class SoftRestrictedPermissionPolicy {
} }
} }
/**
* Checks whether an AppCompat change is enabled for all packages sharing a UID with the
* provided application.
*
* @param context A context to use.
* @param appInfo The application for which to check whether the compat change is enabled.
* @param user The user the app belongs to.
* @param changeId A {@link android.compat.annotation.ChangeId} corresponding to the change.
*
* @return true if this change is enabled for all apps sharing the UID of the provided app,
* false otherwise.
*/
private static boolean isChangeEnabledForUid(@NonNull Context context,
@NonNull ApplicationInfo appInfo, @NonNull UserHandle user, long changeId) {
PackageManager pm = context.getPackageManager();
String[] uidPackages = pm.getPackagesForUid(appInfo.uid);
if (uidPackages != null) {
for (String uidPackage : uidPackages) {
ApplicationInfo uidPackageInfo;
try {
uidPackageInfo = pm.getApplicationInfoAsUser(uidPackage, 0, user);
} catch (PackageManager.NameNotFoundException e) {
continue;
}
if (!isChangeEnabled(uidPackageInfo, changeId)) {
// At least one package sharing this UID does not have this change enabled.
return false;
}
}
// All packages sharing this UID returned true for {@link #isChangeEnabled()}.
return true;
} else {
Log.w(LOG_TAG, "Check for change " + changeId + " for uid " + appInfo.uid
+ " produced no packages. Defaulting to using the information for "
+ appInfo.packageName + " only.");
return isChangeEnabled(appInfo, changeId);
}
}
private static boolean isChangeEnabled(@NonNull ApplicationInfo appInfo, long changeId) {
IBinder binder = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(binder);
final long callingId = Binder.clearCallingIdentity();
try {
return platformCompat.isChangeEnabled(changeId, appInfo);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Check for change " + changeId + " failed. Defaulting to enabled.", e);
return true;
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
private static boolean hasUidRequestedLegacyExternalStorage(int uid, @NonNull Context context) { private static boolean hasUidRequestedLegacyExternalStorage(int uid, @NonNull Context context) {
PackageManager packageManager = context.getPackageManager(); PackageManager packageManager = context.getPackageManager();
String[] packageNames = packageManager.getPackagesForUid(uid); String[] packageNames = packageManager.getPackagesForUid(uid);