From e53e4c5e3c29b6414c6284eb6b62e7a1c29d0887 Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Tue, 8 Oct 2019 18:57:01 -0700 Subject: [PATCH] Update REVOKED_COMPAT before setting app op for runtime permission. To maintain compatibility. Bug: 136503238 Fixes: 142299067 Test: presubmit Test: atest MediaStore_Images_MediaTest#testLocationRedaction Test: atest MediaStore_Videos_MediaTest#testLocationRedaction Change-Id: Idf9c180bf255dedc2f504f215af782c1b15f55b9 --- .../android/server/appop/AppOpsService.java | 87 ++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 798185ad88f76..6c4cc2d43866f 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -65,7 +65,6 @@ import android.content.pm.PermissionInfo; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION; -import android.media.AudioAttributes; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; @@ -109,6 +108,7 @@ import com.android.internal.app.IAppOpsNotedCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.os.Zygote; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.Preconditions; @@ -257,6 +257,9 @@ public class AppOpsService extends IAppOpsService.Stub { @GuardedBy("this") private CheckOpsDelegate mCheckOpsDelegate; + @GuardedBy("this") + private SparseArray> mSwitchOpToOps; + /** * All times are in milliseconds. These constants are kept synchronized with the system * global Settings. Any access to this class or its fields should be done while @@ -1291,6 +1294,8 @@ public class AppOpsService extends IAppOpsService.Stub { verifyIncomingOp(code); code = AppOpsManager.opToSwitch(code); + updatePermissionRevokedCompat(uid, code, mode); + synchronized (this) { final int defaultMode = AppOpsManager.opToDefaultMode(code); @@ -1392,6 +1397,86 @@ public class AppOpsService extends IAppOpsService.Stub { notifyOpChangedSync(code, uid, null, mode); } + private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) { + PackageManager packageManager = mContext.getPackageManager(); + String[] packageNames = packageManager.getPackagesForUid(uid); + if (ArrayUtils.isEmpty(packageNames)) { + return; + } + String packageName = packageNames[0]; + + List ops = getSwitchOpToOps().get(switchCode); + int opsSize = CollectionUtils.size(ops); + for (int i = 0; i < opsSize; i++) { + int code = ops.get(i); + + String permissionName = AppOpsManager.opToPermission(code); + if (permissionName == null) { + continue; + } + + PermissionInfo permissionInfo; + try { + permissionInfo = packageManager.getPermissionInfo(permissionName, 0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + continue; + } + + if (!permissionInfo.isRuntime()) { + continue; + } + + UserHandle user = UserHandle.getUserHandleForUid(uid); + boolean isRevokedCompat; + if (permissionInfo.backgroundPermission != null) { + boolean isBackgroundRevokedCompat = mode != AppOpsManager.MODE_ALLOWED; + long identity = Binder.clearCallingIdentity(); + try { + packageManager.updatePermissionFlags(permissionInfo.backgroundPermission, + packageName, PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, + isBackgroundRevokedCompat + ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user); + } finally { + Binder.restoreCallingIdentity(identity); + } + + isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED + && mode != AppOpsManager.MODE_FOREGROUND; + } else { + isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED; + } + + long identity = Binder.clearCallingIdentity(); + try { + packageManager.updatePermissionFlags(permissionName, packageName, + PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, isRevokedCompat + ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @NonNull + private SparseArray> getSwitchOpToOps() { + synchronized (this) { + if (mSwitchOpToOps == null) { + mSwitchOpToOps = new SparseArray<>(); + for (int op = 0; op < _NUM_OP; op++) { + int switchOp = AppOpsManager.opToSwitch(op); + List ops = mSwitchOpToOps.get(switchOp); + if (ops == null) { + ops = new ArrayList<>(); + mSwitchOpToOps.put(switchOp, ops); + } + ops.add(op); + } + } + return mSwitchOpToOps; + } + } + private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) { final StorageManagerInternal storageManagerInternal = LocalServices.getService(StorageManagerInternal.class);