[automerger] DO NOT MERGE (M) Revoke permision when group changed am: d87a1a7d53 am: 5630564178 am: 90cb8f7b6e

Change-Id: I12743702ec15b7d92b0197496e8a3426777ed4db
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9d79325..b84ccd2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -144,6 +144,7 @@
 import android.content.res.Resources;
 import android.hardware.display.DisplayManager;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Debug;
 import android.os.Binder;
 import android.os.Build;
@@ -3634,6 +3635,81 @@
         killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
     }
 
+    /**
+     * We might auto-grant permissions if any permission of the group is already granted. Hence if
+     * the group of a granted permission changes we need to revoke it to avoid having permissions of
+     * the new group auto-granted.
+     *
+     * @param newPackage The new package that was installed
+     * @param oldPackage The old package that was updated
+     * @param allPackageNames All package names
+     */
+    private void revokeRuntimePermissionsIfGroupChanged(
+            PackageParser.Package newPackage,
+            PackageParser.Package oldPackage,
+            ArrayList<String> allPackageNames) {
+        final int numOldPackagePermissions = oldPackage.permissions.size();
+        final ArrayMap<String, String> oldPermissionNameToGroupName
+                = new ArrayMap<>(numOldPackagePermissions);
+
+        for (int i = 0; i < numOldPackagePermissions; i++) {
+            final PackageParser.Permission permission = oldPackage.permissions.get(i);
+
+            if (permission.group != null) {
+                oldPermissionNameToGroupName.put(permission.info.name,
+                        permission.group.info.name);
+            }
+        }
+
+        final int numNewPackagePermissions = newPackage.permissions.size();
+        for (int newPermissionNum = 0; newPermissionNum < numNewPackagePermissions;
+                newPermissionNum++) {
+            final PackageParser.Permission newPermission =
+                    newPackage.permissions.get(newPermissionNum);
+            final int newProtection = newPermission.info.protectionLevel;
+
+            if ((newProtection & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
+                final String permissionName = newPermission.info.name;
+                final String newPermissionGroupName =
+                        newPermission.group == null ? null : newPermission.group.info.name;
+                final String oldPermissionGroupName = oldPermissionNameToGroupName.get(
+                        permissionName);
+
+                if (newPermissionGroupName != null
+                        && !newPermissionGroupName.equals(oldPermissionGroupName)) {
+                    final List<UserInfo> users = mContext.getSystemService(UserManager.class)
+                            .getUsers();
+
+                    final int numUsers = users.size();
+                    for (int userNum = 0; userNum < numUsers; userNum++) {
+                        final int userId = users.get(userNum).id;
+                        final int numPackages = allPackageNames.size();
+                        for (int packageNum = 0; packageNum < numPackages; packageNum++) {
+                            final String packageName = allPackageNames.get(packageNum);
+
+                            if (checkPermission(permissionName, packageName, userId)
+                                    == PackageManager.PERMISSION_GRANTED) {
+                                EventLog.writeEvent(0x534e4554, "72710897",
+                                        newPackage.applicationInfo.uid,
+                                        "Revoking permission", permissionName, "from package",
+                                        packageName, "as the group changed from",
+                                        oldPermissionGroupName, "to", newPermissionGroupName);
+
+                                try {
+                                    revokeRuntimePermission(packageName, permissionName, userId);
+                                } catch (IllegalArgumentException e) {
+                                    Slog.e(TAG, "Could not revoke " + permissionName + " from "
+                                            + packageName, e);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
     @Override
     public void resetRuntimePermissions() {
         mContext.enforceCallingOrSelfPermission(
@@ -6479,7 +6555,7 @@
         }
     }
 
-    private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
+    private PackageParser.Package scanPackageDirtyLI(final PackageParser.Package pkg, int parseFlags,
             int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
         final File scanFile = new File(pkg.codePath);
         if (pkg.applicationInfo.getCodePath() == null ||
@@ -6599,6 +6675,8 @@
             pkg.mAdoptPermissions = null;
         }
 
+        final PackageParser.Package oldPkg;
+
         // writer
         synchronized (mPackages) {
             if (pkg.mSharedUserId != null) {
@@ -6615,6 +6693,14 @@
                 }
             }
 
+            final PackageSetting oldPkgSetting = mSettings.peekPackageLPr(pkg.packageName);
+            if (oldPkgSetting == null) {
+                oldPkg = null;
+            } else {
+                oldPkg = oldPkgSetting.pkg;
+            }
+
+
             // Check if we are renaming from an original package name.
             PackageSetting origPackage = null;
             String realName = null;
@@ -7539,6 +7625,24 @@
                 // This is a regular package, with one or more known overlay packages.
                 createIdmapsForPackageLI(pkg);
             }
+
+            if (oldPkg != null) {
+                // We need to call revokeRuntimePermissionsIfGroupChanged async as permission
+                // revokation 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(new Runnable() {
+                    public void run() {
+                        revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg, allPackageNames);
+                    }
+                });
+            }
         }
 
         return pkg;