If INTERACT_ACROSS_USERS_FULL is granted, so is INTERACT_ACROSS_USERS

Bug: 77717079
Test: None
Change-Id: I9252603b5d9ec86cac1fd205a44e5d1c6b36ddcb
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index d3526f7..7b44a04 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -19,12 +19,13 @@
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
 import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
 import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
 import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
-import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -33,9 +34,9 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.Package;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
-import android.content.pm.PackageParser.Package;
 import android.metrics.LogMaker;
 import android.os.Binder;
 import android.os.Build;
@@ -69,17 +70,19 @@
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.SharedUserSetting;
 import com.android.server.pm.UserManagerService;
-import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy
+        .DefaultPermissionGrantedCallback;
 import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
 import com.android.server.pm.permission.PermissionsState.PermissionState;
 
 import libcore.util.EmptyArray;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
@@ -103,6 +106,16 @@
     /** Empty array to avoid allocations */
     private static final int[] EMPTY_INT_ARRAY = new int[0];
 
+    /** If the permission of the value is granted, so is the key */
+    private static final Map<String, String> FULLER_PERMISSION_MAP = new HashMap<>();
+
+    static {
+        FULLER_PERMISSION_MAP.put(Manifest.permission.ACCESS_COARSE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
+        FULLER_PERMISSION_MAP.put(Manifest.permission.INTERACT_ACROSS_USERS,
+                Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+    }
+
     /** Lock to protect internal data access */
     private final Object mLock;
 
@@ -233,9 +246,7 @@
                     return PackageManager.PERMISSION_GRANTED;
                 }
             }
-            // Special case: ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION
-            if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState
-                    .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) {
+            if (isImpliedPermissionGranted(permissionsState, permName, userId)) {
                 return PackageManager.PERMISSION_GRANTED;
             }
         }
@@ -274,9 +285,7 @@
                     return PackageManager.PERMISSION_GRANTED;
                 }
             }
-            // Special case: ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION
-            if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState
-                    .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) {
+            if (isImpliedPermissionGranted(permissionsState, permName, userId)) {
                 return PackageManager.PERMISSION_GRANTED;
             }
         } else {
@@ -285,8 +294,8 @@
                 if (perms.contains(permName)) {
                     return PackageManager.PERMISSION_GRANTED;
                 }
-                if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && perms
-                        .contains(Manifest.permission.ACCESS_FINE_LOCATION)) {
+                if (FULLER_PERMISSION_MAP.containsKey(permName)
+                        && perms.contains(FULLER_PERMISSION_MAP.get(permName))) {
                     return PackageManager.PERMISSION_GRANTED;
                 }
             }
@@ -294,6 +303,18 @@
         return PackageManager.PERMISSION_DENIED;
     }
 
+    /**
+     * Returns {@code true} if the permission can be implied from another granted permission.
+     * <p>Some permissions, such as ACCESS_FINE_LOCATION, imply other permissions,
+     * such as ACCESS_COURSE_LOCATION. If the caller holds an umbrella permission, give
+     * it access to any implied permissions.
+     */
+    private static boolean isImpliedPermissionGranted(PermissionsState permissionsState,
+            String permName, int userId) {
+        return FULLER_PERMISSION_MAP.containsKey(permName)
+                && permissionsState.hasPermission(FULLER_PERMISSION_MAP.get(permName), userId);
+    }
+
     private PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags,
             int callingUid) {
         if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {