Merge "Check that Account Parcel has name and type." into oc-dev
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index af74b03..7e41dbe 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -16,16 +16,23 @@
 package android.accounts;
 
 import android.app.Activity;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.widget.TextView;
-import android.widget.LinearLayout;
-import android.view.View;
-import android.view.LayoutInflater;
+import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
 import com.android.internal.R;
 
 import java.io.IOException;
@@ -42,6 +49,7 @@
     private Account mAccount;
     private String mAuthTokenType;
     private int mUid;
+    private int mCallingUid;
     private Bundle mResultBundle = null;
     protected LayoutInflater mInflater;
 
@@ -74,6 +82,20 @@
             return;
         }
 
+        try {
+            IBinder activityToken = getActivityToken();
+            mCallingUid = ActivityManager.getService().getLaunchedFromUid(activityToken);
+        } catch (RemoteException re) {
+            // Couldn't figure out caller details
+            Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re);
+        }
+
+        if (!UserHandle.isSameApp(mCallingUid, Process.SYSTEM_UID) && mCallingUid != mUid) {
+            setResult(Activity.RESULT_CANCELED);
+            finish();
+            return;
+        }
+
         String accountTypeLabel;
         try {
             accountTypeLabel = getAccountLabel(mAccount);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 2d47c7b..da1fae1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -91,6 +91,7 @@
         imageUri = null;
         iconSize = 0;
     }
+
     void clearContext() {
         context = null;
     }
@@ -338,21 +339,23 @@
             mPublicNotificationBuilder
                     .setContentTitle(r.getString(R.string.screenshot_saved_title))
                     .setContentText(r.getString(R.string.screenshot_saved_text))
-                    .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent, 0))
+                    .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent,
+                            PendingIntent.FLAG_IMMUTABLE))
                     .setWhen(now)
                     .setAutoCancel(true)
                     .setColor(context.getColor(
                             com.android.internal.R.color.system_notification_accent_color));
             mNotificationBuilder
-                .setContentTitle(r.getString(R.string.screenshot_saved_title))
-                .setContentText(r.getString(R.string.screenshot_saved_text))
-                .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent, 0))
-                .setWhen(now)
-                .setAutoCancel(true)
-                .setColor(context.getColor(
-                        com.android.internal.R.color.system_notification_accent_color))
-                .setPublicVersion(mPublicNotificationBuilder.build())
-                .setFlag(Notification.FLAG_NO_CLEAR, false);
+                    .setContentTitle(r.getString(R.string.screenshot_saved_title))
+                    .setContentText(r.getString(R.string.screenshot_saved_text))
+                    .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent,
+                            PendingIntent.FLAG_IMMUTABLE))
+                    .setWhen(now)
+                    .setAutoCancel(true)
+                    .setColor(context.getColor(
+                            com.android.internal.R.color.system_notification_accent_color))
+                    .setPublicVersion(mPublicNotificationBuilder.build())
+                    .setFlag(Notification.FLAG_NO_CLEAR, false);
 
             mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT,
                     mNotificationBuilder.build());
@@ -454,7 +457,8 @@
         // Inflate the screenshot layout
         mDisplayMatrix = new Matrix();
         mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);
-        mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);
+        mBackgroundView = (ImageView) mScreenshotLayout.findViewById(
+                R.id.global_screenshot_background);
         mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);
         mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
         mScreenshotSelectorView = (ScreenshotSelectorView) mScreenshotLayout.findViewById(
@@ -483,17 +487,18 @@
         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         mNotificationManager =
             (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+
         mDisplay = mWindowManager.getDefaultDisplay();
         mDisplayMetrics = new DisplayMetrics();
         mDisplay.getRealMetrics(mDisplayMetrics);
 
         // Get the various target sizes
         mNotificationIconSize =
-            r.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
+                r.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
 
         // Scale has to account for both sides of the bg
         mBgPadding = (float) r.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding);
-        mBgPaddingScale = mBgPadding /  mDisplayMetrics.widthPixels;
+        mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels;
 
         // determine the optimal preview size
         int panelWidth = 0;
@@ -719,6 +724,7 @@
             }
         });
     }
+
     private ValueAnimator createScreenshotDropInAnimation() {
         final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION)
                 / SCREENSHOT_DROP_IN_DURATION);
@@ -759,6 +765,7 @@
                 mScreenshotFlash.setAlpha(0f);
                 mScreenshotFlash.setVisibility(View.VISIBLE);
             }
+
             @Override
             public void onAnimationEnd(android.animation.Animator animation) {
                 mScreenshotFlash.setVisibility(View.GONE);
@@ -769,7 +776,7 @@
             public void onAnimationUpdate(ValueAnimator animation) {
                 float t = (Float) animation.getAnimatedValue();
                 float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale)
-                    - scaleInterpolator.getInterpolation(t)
+                        - scaleInterpolator.getInterpolation(t)
                         * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE);
                 mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);
                 mScreenshotView.setAlpha(t);
@@ -780,6 +787,7 @@
         });
         return anim;
     }
+
     private ValueAnimator createScreenshotDropOutAnimation(int w, int h, boolean statusBarVisible,
             boolean navBarVisible) {
         ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
@@ -801,7 +809,8 @@
                 public void onAnimationUpdate(ValueAnimator animation) {
                     float t = (Float) animation.getAnimatedValue();
                     float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
-                            - t * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);
+                            - t * (SCREENSHOT_DROP_IN_MIN_SCALE
+                            - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);
                     mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
                     mScreenshotView.setAlpha(1f - t);
                     mScreenshotView.setScaleX(scaleT);
@@ -828,8 +837,10 @@
             float halfScreenHeight = (h - 2f * mBgPadding) / 2f;
             final float offsetPct = SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET;
             final PointF finalPos = new PointF(
-                -halfScreenWidth + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth,
-                -halfScreenHeight + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight);
+                    -halfScreenWidth
+                            + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth,
+                    -halfScreenHeight
+                            + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight);
 
             // Animate the screenshot to the status bar
             anim.setDuration(SCREENSHOT_DROP_OUT_DURATION);
@@ -838,7 +849,7 @@
                 public void onAnimationUpdate(ValueAnimator animation) {
                     float t = (Float) animation.getAnimatedValue();
                     float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
-                        - scaleInterpolator.getInterpolation(t)
+                            - scaleInterpolator.getInterpolation(t)
                             * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE);
                     mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
                     mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t));
@@ -858,15 +869,15 @@
 
         // Repurpose the existing notification to notify the user of the error
         Notification.Builder b = new Notification.Builder(context, NotificationChannels.ALERTS)
-            .setTicker(r.getString(R.string.screenshot_failed_title))
-            .setContentTitle(r.getString(R.string.screenshot_failed_title))
-            .setContentText(errorMsg)
-            .setSmallIcon(R.drawable.stat_notify_image_error)
-            .setWhen(System.currentTimeMillis())
-            .setVisibility(Notification.VISIBILITY_PUBLIC) // ok to show outside lockscreen
-            .setCategory(Notification.CATEGORY_ERROR)
-            .setAutoCancel(true)
-            .setColor(context.getColor(
+                .setTicker(r.getString(R.string.screenshot_failed_title))
+                .setContentTitle(r.getString(R.string.screenshot_failed_title))
+                .setContentText(errorMsg)
+                .setSmallIcon(R.drawable.stat_notify_image_error)
+                .setWhen(System.currentTimeMillis())
+                .setVisibility(Notification.VISIBILITY_PUBLIC) // ok to show outside lockscreen
+                .setCategory(Notification.CATEGORY_ERROR)
+                .setAutoCancel(true)
+                .setColor(context.getColor(
                         com.android.internal.R.color.system_notification_accent_color));
         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
@@ -874,7 +885,7 @@
                 DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE);
         if (intent != null) {
             final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
-                    context, 0, intent, 0, null, UserHandle.CURRENT);
+                    context, 0, intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
             b.setContentIntent(pendingIntent);
         }
 
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
index 5339bac..3f1dbe4 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -16,18 +16,29 @@
 
 package com.android.server.fingerprint;
 
-import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import static android.Manifest.permission.USE_FINGERPRINT;
 
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.EventLog;
 import android.util.Slog;
 
+import com.android.internal.R;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import java.util.List;
+
 /**
  * A class to keep track of the authentication state for a given client.
  */
@@ -53,6 +64,56 @@
         boolean result = false;
         boolean authenticated = fingerId != 0;
 
+        // Ensure authentication only succeeds if the client activity is on top or is keyguard.
+        boolean isBackgroundAuth = false;
+        if (authenticated && !isKeyguard(getContext(), getOwnerString())) {
+            final ActivityManager activityManager =
+                    (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
+            final IActivityManager activityManagerService = activityManager != null
+                    ? activityManager.getService()
+                    : null;
+            if (activityManagerService == null) {
+                Slog.e(TAG, "Unable to get activity manager service");
+                isBackgroundAuth = true;
+            } else {
+                try {
+                    final List<ActivityManager.RunningTaskInfo> tasks =
+                            activityManagerService.getTasks(1, 0 /* flags */);
+                    if (tasks == null || tasks.isEmpty()) {
+                        Slog.e(TAG, "No running tasks reported");
+                        isBackgroundAuth = true;
+                    } else {
+                        final ComponentName topActivity = tasks.get(0).topActivity;
+                        if (topActivity == null) {
+                            Slog.e(TAG, "Unable to get top activity");
+                            isBackgroundAuth = true;
+                        } else {
+                            final String topPackage = topActivity.getPackageName();
+                            if (!topPackage.contentEquals(getOwnerString())) {
+                                Slog.e(TAG, "Background authentication detected, top: " + topPackage
+                                        + ", client: " + this);
+                                isBackgroundAuth = true;
+                            }
+                        }
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to get running tasks", e);
+                    isBackgroundAuth = true;
+                }
+            }
+        }
+
+        // Fail authentication if we can't confirm the client activity is on top.
+        if (isBackgroundAuth) {
+            Slog.e(TAG, "Failing possible background authentication");
+            authenticated = false;
+
+            // SafetyNet logging for exploitation attempts of b/159249069.
+            final ApplicationInfo appInfo = getContext().getApplicationInfo();
+            EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1,
+                    "Attempted background authentication");
+        }
+
         IFingerprintServiceReceiver receiver = getReceiver();
         if (receiver != null) {
             try {
@@ -61,6 +122,14 @@
                 if (!authenticated) {
                     receiver.onAuthenticationFailed(getHalDeviceId());
                 } else {
+                    // SafetyNet logging for b/159249069 if constraint is violated.
+                    if (isBackgroundAuth) {
+                        final ApplicationInfo appInfo = getContext().getApplicationInfo();
+                        EventLog.writeEvent(0x534e4554, "159249069",
+                                appInfo != null ? appInfo.uid : -1,
+                                "Successful background authentication! Receiver notified");
+                    }
+
                     if (DEBUG) {
                         Slog.v(TAG, "onAuthenticated(owner=" + getOwnerString()
                                 + ", id=" + fingerId + ", gp=" + groupId + ")");
@@ -98,6 +167,14 @@
             }
             result |= lockoutMode != LOCKOUT_NONE; // in a lockout mode
         } else {
+            // SafetyNet logging for b/159249069 if constraint is violated.
+            if (isBackgroundAuth) {
+                final ApplicationInfo appInfo = getContext().getApplicationInfo();
+                EventLog.writeEvent(0x534e4554, "159249069",
+                        appInfo != null ? appInfo.uid : -1,
+                        "Successful background authentication! Lockout reset");
+            }
+
             if (receiver != null) {
                 FingerprintUtils.vibrateFingerprintSuccess(getContext());
             }
@@ -107,6 +184,17 @@
         return result;
     }
 
+    private static boolean isKeyguard(Context context, String clientPackage) {
+        final boolean hasPermission = context.checkCallingOrSelfPermission(USE_FINGERPRINT)
+                == PackageManager.PERMISSION_GRANTED;
+
+        final ComponentName keyguardComponent = ComponentName.unflattenFromString(
+                context.getResources().getString(R.string.config_keyguardComponent));
+        final String keyguardPackage = keyguardComponent != null
+                ? keyguardComponent.getPackageName() : null;
+        return hasPermission && keyguardPackage != null && keyguardPackage.equals(clientPackage);
+    }
+
     /**
      * Start authentication
      */
diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
index 2100038..f609db0 100644
--- a/services/core/java/com/android/server/pm/BasePermission.java
+++ b/services/core/java/com/android/server/pm/BasePermission.java
@@ -35,6 +35,8 @@
 
     final int type;
 
+    private boolean mPermissionDefinitionChanged;
+
     int protectionLevel;
 
     PackageParser.Permission perm;
@@ -67,11 +69,19 @@
                 + "}";
     }
 
+    public boolean isPermissionDefinitionChanged() {
+        return mPermissionDefinitionChanged;
+    }
+
     public void setGids(int[] gids, boolean perUser) {
         this.gids = gids;
         this.perUser = perUser;
     }
 
+    public void setPermissionDefinitionChanged(boolean shouldOverride) {
+        mPermissionDefinitionChanged = shouldOverride;
+    }
+
     public int[] computeGids(int userId) {
         if (perUser) {
             final int[] userGids = new int[gids.length];
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b4f5218..a2607e1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -10784,7 +10784,7 @@
         } else {
             final int userId = user == null ? 0 : user.getIdentifier();
             // Modify state for the given package setting
-            commitPackageSettings(pkg, pkgSetting, user, scanFlags,
+            commitPackageSettings(pkg, oldPkg, pkgSetting, user, scanFlags,
                     (policyFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/);
             if (pkgSetting.getInstantApp(userId)) {
                 mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
@@ -11147,10 +11147,73 @@
     }
 
     /**
+     * If permissions are upgraded to runtime, or their owner changes to the system, then any
+     * granted permissions must be revoked.
+     *
+     * @param permissionsToRevoke A list of permission names to revoke
+     * @param allPackageNames All package names
+     */
+    private void revokeRuntimePermissionsIfPermissionDefinitionChanged(
+            @NonNull List<String> permissionsToRevoke,
+            @NonNull ArrayList<String> allPackageNames) {
+
+        final int[] userIds = UserManagerService.getInstance().getUserIds();
+        final int numPermissions = permissionsToRevoke.size();
+        final int numUserIds = userIds.length;
+        final int numPackages = allPackageNames.size();
+        final int callingUid = Binder.getCallingUid();
+
+        for (int permNum = 0; permNum < numPermissions; permNum++) {
+            String permName = permissionsToRevoke.get(permNum);
+
+            BasePermission bp = mSettings.mPermissions.get(permName);
+            if (bp == null || !bp.isRuntime()) {
+                continue;
+            }
+            for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) {
+                final int userId = userIds[userIdNum];
+                for (int packageNum = 0; packageNum < numPackages; packageNum++) {
+                    final String packageName = allPackageNames.get(packageNum);
+                    final int uid = getPackageUid(packageName, 0, userId);
+                    if (uid < Process.FIRST_APPLICATION_UID) {
+                        // do not revoke from system apps
+                        continue;
+                    }
+                    final int permissionState = checkPermission(permName, packageName,
+                            userId);
+                    final int flags = getPermissionFlags(permName, packageName, userId);
+                    final int flagMask = FLAG_PERMISSION_SYSTEM_FIXED
+                            | FLAG_PERMISSION_POLICY_FIXED
+                            | FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+                    if (permissionState == PackageManager.PERMISSION_GRANTED
+                            && (flags & flagMask) == 0) {
+                        EventLog.writeEvent(0x534e4554, "154505240", uid,
+                                "Revoking permission " + permName + " from package "
+                                        + packageName + " due to definition change");
+                        EventLog.writeEvent(0x534e4554, "168319670", uid,
+                                "Revoking permission " + permName + " from package "
+                                        + packageName + " due to definition change");
+                        Slog.e(TAG, "Revoking permission " + permName + " from package "
+                                + packageName + " due to definition change");
+                        try {
+                            revokeRuntimePermission(packageName, permName, userId, false);
+                        } catch (Exception e) {
+                            Slog.e(TAG, "Could not revoke " + permName + " from "
+                                    + packageName, e);
+                        }
+                    }
+                }
+            }
+            bp.setPermissionDefinitionChanged(false);
+        }
+    }
+
+    /**
      * Adds a scanned package to the system. When this method is finished, the package will
      * be available for query, resolution, etc...
      */
-    private void commitPackageSettings(PackageParser.Package pkg, PackageSetting pkgSetting,
+    private void commitPackageSettings(PackageParser.Package pkg, PackageParser.Package oldPkg,
+            PackageSetting pkgSetting,
             UserHandle user, int scanFlags, boolean chatty) throws PackageManagerException {
         final String pkgName = pkg.packageName;
         if (mCustomResolverComponentName != null &&
@@ -11482,6 +11545,10 @@
                 if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Permission Groups: " + r);
             }
 
+            // If a permission has had its defining app changed, or it has had its protection
+            // upgraded, we need to revoke apps that hold it
+            final List<String> permissionsWithChangedDefinition = new ArrayList<String>();
+
             N = pkg.permissions.size();
             r = null;
             for (i=0; i<N; i++) {
@@ -11517,6 +11584,7 @@
                 BasePermission bp = permissionMap.get(p.info.name);
 
                 // Allow system apps to redefine non-system permissions
+                boolean ownerChanged = false;
                 if (bp != null && !Objects.equals(bp.sourcePackage, p.info.packageName)) {
                     final boolean currentOwnerIsSystem = (bp.perm != null
                             && isSystemApp(bp.perm.owner));
@@ -11532,6 +11600,7 @@
                             String msg = "New decl " + p.owner + " of permission  "
                                     + p.info.name + " is system; overriding " + bp.sourcePackage;
                             reportSettingsProblem(Log.WARN, msg);
+                            ownerChanged = true;
                             bp = null;
                         }
                     }
@@ -11543,6 +11612,7 @@
                     permissionMap.put(p.info.name, bp);
                 }
 
+                boolean wasNonRuntime = !bp.isRuntime();
                 if (bp.perm == null) {
                     if (bp.sourcePackage == null
                             || bp.sourcePackage.equals(p.info.packageName)) {
@@ -11585,8 +11655,15 @@
                 if (bp.perm == p) {
                     bp.protectionLevel = p.info.protectionLevel;
                 }
-            }
 
+                if (bp.isRuntime() && (ownerChanged || wasNonRuntime)) {
+                    // If this is a runtime permission and the owner has changed, or this was a normal
+                    // permission, then permission state should be cleaned up
+                    bp.setPermissionDefinitionChanged(true);
+
+                    permissionsWithChangedDefinition.add(p.info.name);
+                }
+            }
             if (r != null) {
                 if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Permissions: " + r);
             }
@@ -11627,6 +11704,28 @@
                     mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
                 }
             }
+
+            boolean hasOldPkg = oldPkg != null;
+            boolean hasPermissionDefinitionChanges = !permissionsWithChangedDefinition.isEmpty();
+            if (hasOldPkg || hasPermissionDefinitionChanges) {
+                // We need to call revokeRuntimePermissionsIfPermissionDefinitionChanged async
+                // as permission
+                // revoke callbacks from this method might need to kill apps which need the
+                // mPackages lock on a different thread. This would dead lock.
+                //
+                // Hence create a copy of all package names and pass it into
+                // revokeRuntimePermissionsIfGroupChanged. Only for those permissions might get
+                // revoked. If a new package is added before the async code runs the permission
+                // won't be granted yet, hence new packages are no problem.
+                final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());
+
+                AsyncTask.execute(() -> {
+                    if (hasPermissionDefinitionChanges) {
+                        revokeRuntimePermissionsIfPermissionDefinitionChanged(
+                                permissionsWithChangedDefinition, allPackageNames);
+                    }
+                });
+            }
         }
 
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);