Apply fg/bg state in default grant policy

The fg/bg state is encoded in the app-op of the foreground permission.
I.e. depending whether the background permission is granted, the
foregrounds app-op state need to be different.

Test: Checked that default browser has both fg and bg location
Change-Id: I1428b65f95b23c921a3a5f69d84efe9124b51cd1
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 030e148..32b2bf0 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.AppOpsManager;
 import android.app.DownloadManager;
 import android.app.SearchManager;
 import android.app.admin.DevicePolicyManager;
@@ -1027,6 +1028,23 @@
                 | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0;
     }
 
+    /**
+     * Return the background permission for a permission.
+     *
+     * @param permission The name of the foreground permission
+     *
+     * @return The name of the background permission or {@code null} if the permission has no
+     *         background permission
+     */
+    private @Nullable String getBackgroundPermission(@NonNull String permission) {
+        try {
+            return mContext.getPackageManager().getPermissionInfo(permission,
+                    0).backgroundPermission;
+        } catch (NameNotFoundException e) {
+            return null;
+        }
+    }
+
     private void grantRuntimePermissions(PackageInfo pkg,
             Set<String> permissionsWithoutSplits, boolean systemFixed, boolean ignoreSystemPackage,
             int userId) {
@@ -1039,9 +1057,15 @@
             return;
         }
 
+        PackageManager pm = mContext.getPackageManager();
         final ArraySet<String> permissions = new ArraySet<>(permissionsWithoutSplits);
         ApplicationInfo applicationInfo = pkg.applicationInfo;
 
+        int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+        if (systemFixed) {
+            newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+        }
+
         // Automatically attempt to grant split permissions to older APKs
         final List<PermissionManager.SplitPermissionInfo> splitPermissions =
                 mContext.getSystemService(PermissionManager.class).getSplitPermissions();
@@ -1081,9 +1105,28 @@
             }
         }
 
-        final int grantablePermissionCount = requestedPermissions.length;
-        for (int i = 0; i < grantablePermissionCount; i++) {
+        final int numRequestedPermissions = requestedPermissions.length;
+
+        // Sort requested permissions so that all permissions that are a foreground permission (i.e.
+        // permisions that have background permission) are before their background permissions.
+        final String[] sortedRequestedPermissions = new String[numRequestedPermissions];
+        int numForeground = 0;
+        int numOther = 0;
+        for (int i = 0; i < numRequestedPermissions; i++) {
             String permission = requestedPermissions[i];
+            if (getBackgroundPermission(permission) != null) {
+                sortedRequestedPermissions[numForeground] = permission;
+                numForeground++;
+            } else {
+                sortedRequestedPermissions[numRequestedPermissions - 1 - numOther] =
+                        permission;
+                numOther++;
+            }
+        }
+
+        for (int requestedPermissionNum = 0; requestedPermissionNum < numRequestedPermissions;
+                requestedPermissionNum++) {
+            String permission = requestedPermissions[requestedPermissionNum];
 
             // If there is a disabled system app it may request a permission the updated
             // version ot the data partition doesn't, In this case skip the permission.
@@ -1111,20 +1154,58 @@
                         continue;
                     }
 
+                    int uid = UserHandle.getUid(userId,
+                            UserHandle.getAppId(pkg.applicationInfo.uid));
+                    String op = AppOpsManager.permissionToOp(permission);
+
                     mContext.getPackageManager()
                             .grantRuntimePermission(pkg.packageName, permission, user);
+
+                    mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
+                            newFlags, newFlags, user);
+
+                    List<String> fgPerms = mPermissionManager.getBackgroundPermissions()
+                            .get(permission);
+                    if (fgPerms != null) {
+                        int numFgPerms = fgPerms.size();
+                        for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
+                            String fgPerm = fgPerms.get(fgPermNum);
+
+                            if (pm.checkPermission(fgPerm, pkg.packageName)
+                                    == PackageManager.PERMISSION_GRANTED) {
+                                // Upgrade the app-op state of the fg permission to allow bg access
+                                mContext.getSystemService(AppOpsManager.class).setMode(
+                                        AppOpsManager.permissionToOp(fgPerm), uid,
+                                        pkg.packageName, AppOpsManager.MODE_ALLOWED);
+
+                                break;
+                            }
+                        }
+                    }
+
+                    String bgPerm = getBackgroundPermission(permission);
+                    if (bgPerm == null) {
+                        if (op != null) {
+                            mContext.getSystemService(AppOpsManager.class).setMode(op, uid,
+                                    pkg.packageName, AppOpsManager.MODE_ALLOWED);
+                        }
+                    } else {
+                        int mode;
+                        if (pm.checkPermission(bgPerm, pkg.packageName)
+                                == PackageManager.PERMISSION_GRANTED) {
+                            mode = AppOpsManager.MODE_ALLOWED;
+                        } else {
+                            mode = AppOpsManager.MODE_FOREGROUND;
+                        }
+
+                        mContext.getSystemService(AppOpsManager.class).setMode(op, uid,
+                                pkg.packageName, mode);
+                    }
+
                     if (DEBUG) {
                         Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
                                 + permission + " to default handler " + pkg);
                     }
-
-                    int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
-                    if (systemFixed) {
-                        newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
-                    }
-
-                    mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
-                            newFlags, newFlags, user);
                 }
 
                 // If a component gets a permission for being the default handler A