Add support for excluding tags from restrictions

Allow user restrictions to provide an excluded map of packages and tags
rather than just packages.

Bug: 187421886
Test: manual
Change-Id: I8f90ba6cdd288068664b352fdb540d0f11fe3dfc
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 010f4e4..ed00436 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7394,20 +7394,27 @@
 
     /** @hide */
     public void setUserRestriction(int code, boolean restricted, IBinder token) {
-        setUserRestriction(code, restricted, token, /*exceptionPackages*/null);
+        setUserRestriction(code, restricted, token, (Map<String, String[]>) null);
     }
 
-    /** @hide */
+    /**
+     * An empty array of attribution tags means exclude all tags under that package.
+     * @hide
+     */
     public void setUserRestriction(int code, boolean restricted, IBinder token,
-            String[] exceptionPackages) {
-        setUserRestrictionForUser(code, restricted, token, exceptionPackages, mContext.getUserId());
+            @Nullable Map<String, String[]> excludedPackageTags) {
+        setUserRestrictionForUser(code, restricted, token, excludedPackageTags,
+                mContext.getUserId());
     }
 
-    /** @hide */
+    /**
+     * An empty array of attribution tags means exclude all tags under that package.
+     * @hide
+     */
     public void setUserRestrictionForUser(int code, boolean restricted, IBinder token,
-            String[] exceptionPackages, int userId) {
+            @Nullable Map<String, String[]> excludedPackageTags, int userId) {
         try {
-            mService.setUserRestriction(code, restricted, token, userId, exceptionPackages);
+            mService.setUserRestriction(code, restricted, token, userId, excludedPackageTags);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -7949,7 +7956,7 @@
      */
     public int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName) {
         try {
-            return mService.checkOperationRaw(op, uid, packageName);
+            return mService.checkOperationRaw(op, uid, packageName, null);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index 341b9c5..2de0ddb 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -29,6 +29,7 @@
 import com.android.internal.util.function.NonaFunction;
 import com.android.internal.util.function.OctFunction;
 import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.QuintFunction;
 import com.android.internal.util.function.TriFunction;
 
 /**
@@ -45,12 +46,14 @@
          * @param code The op code to check.
          * @param uid The UID for which to check.
          * @param packageName The package for which to check.
-         * @param superImpl The super implementation.
+         * @param attributionTag The attribution tag for which to check.
          * @param raw Whether to check the raw op i.e. not interpret the mode based on UID state.
+         * @param superImpl The super implementation.
          * @return The app op check result.
          */
-        int checkOperation(int code, int uid, String packageName, boolean raw,
-                QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl);
+        int checkOperation(int code, int uid, String packageName, @Nullable String attributionTag,
+                boolean raw,
+                QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl);
 
         /**
          * Allows overriding check audio operation behavior.
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 281702e..3cf4621 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -92,7 +92,7 @@
     void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages);
 
     void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle);
-    void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in String[] exceptionPackages);
+    void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in Map<String, String[]> excludedPackageTags);
     void removeUser(int userHandle);
 
     void startWatchingActive(in int[] ops, IAppOpsActiveCallback callback);
@@ -113,7 +113,7 @@
     void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback);
     List<AsyncNotedAppOp> extractAsyncOps(String packageName);
 
-    int checkOperationRaw(int code, int uid, String packageName);
+    int checkOperationRaw(int code, int uid, String packageName, @nullable String attributionTag);
 
     void reloadNonHistoricalState();
 
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index ca59ce3..baec544 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -1320,12 +1320,12 @@
     private void setUserRestriction(int userId, int sensor, boolean enabled) {
         if (sensor == CAMERA) {
             mAppOpsManager.setUserRestrictionForUser(OP_CAMERA, enabled,
-                    mAppOpsRestrictionToken, new String[]{}, userId);
+                    mAppOpsRestrictionToken, null, userId);
         } else if (sensor == MICROPHONE) {
             mAppOpsManager.setUserRestrictionForUser(OP_RECORD_AUDIO, enabled,
-                    mAppOpsRestrictionToken, new String[]{}, userId);
+                    mAppOpsRestrictionToken, null, userId);
             mAppOpsManager.setUserRestrictionForUser(OP_RECORD_AUDIO_HOTWORD, enabled,
-                    mAppOpsRestrictionToken, new String[]{}, userId);
+                    mAppOpsRestrictionToken, null, userId);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6661f88..5d1243b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -351,6 +351,7 @@
 import com.android.internal.util.function.NonaFunction;
 import com.android.internal.util.function.OctFunction;
 import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.QuintFunction;
 import com.android.internal.util.function.TriFunction;
 import com.android.server.AlarmManagerInternal;
 import com.android.server.DeviceIdleInternal;
@@ -16741,19 +16742,20 @@
         }
 
         @Override
-        public int checkOperation(int code, int uid, String packageName, boolean raw,
-                QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl) {
+        public int checkOperation(int code, int uid, String packageName,
+                String attributionTag, boolean raw,
+                QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl) {
             if (uid == mTargetUid && isTargetOp(code)) {
                 final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid),
                         Process.SHELL_UID);
                 final long identity = Binder.clearCallingIdentity();
                 try {
-                    return superImpl.apply(code, shellUid, "com.android.shell", raw);
+                    return superImpl.apply(code, shellUid, "com.android.shell", null, raw);
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            return superImpl.apply(code, uid, packageName, raw);
+            return superImpl.apply(code, uid, packageName, attributionTag, raw);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index a23b5eb..76abfbf 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3059,16 +3059,20 @@
     }
 
     @Override
-    public int checkOperationRaw(int code, int uid, String packageName) {
-        return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, true /*raw*/);
+    public int checkOperationRaw(int code, int uid, String packageName,
+            @Nullable String attributionTag) {
+        return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, attributionTag,
+                true /*raw*/);
     }
 
     @Override
     public int checkOperation(int code, int uid, String packageName) {
-        return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, false /*raw*/);
+        return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, null,
+                false /*raw*/);
     }
 
-    private int checkOperationImpl(int code, int uid, String packageName, boolean raw) {
+    private int checkOperationImpl(int code, int uid, String packageName,
+            @Nullable String attributionTag, boolean raw) {
         verifyIncomingOp(code);
         verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
 
@@ -3076,7 +3080,7 @@
         if (resolvedPackageName == null) {
             return AppOpsManager.MODE_IGNORED;
         }
-        return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
+        return checkOperationUnchecked(code, uid, resolvedPackageName, attributionTag, raw);
     }
 
     /**
@@ -3090,7 +3094,7 @@
      * @return The mode of the op
      */
     private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
-                boolean raw) {
+            @Nullable String attributionTag, boolean raw) {
         RestrictionBypass bypass;
         try {
             bypass = verifyAndGetBypass(uid, packageName, null);
@@ -3103,7 +3107,7 @@
             return AppOpsManager.MODE_IGNORED;
         }
         synchronized (this) {
-            if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
+            if (isOpRestrictedLocked(uid, code, packageName, attributionTag, bypass)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             code = AppOpsManager.opToSwitch(code);
@@ -3322,7 +3326,7 @@
 
             final int switchCode = AppOpsManager.opToSwitch(code);
             final UidState uidState = ops.uidState;
-            if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
+            if (isOpRestrictedLocked(uid, code, packageName, attributionTag, bypass)) {
                 attributedOp.rejected(uidState.state, flags);
                 scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
                         AppOpsManager.MODE_IGNORED);
@@ -3809,7 +3813,7 @@
             final Op op = getOpLocked(ops, code, uid, true);
             final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
             final UidState uidState = ops.uidState;
-            isRestricted = isOpRestrictedLocked(uid, code, packageName, bypass);
+            isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, bypass);
             final int switchCode = AppOpsManager.opToSwitch(code);
             // If there is a non-default per UID policy (we set UID op mode only if
             // non-default) it takes over, otherwise use the per package policy.
@@ -4551,7 +4555,7 @@
     }
 
     private boolean isOpRestrictedLocked(int uid, int code, String packageName,
-            @Nullable RestrictionBypass appBypass) {
+            String attributionTag, @Nullable RestrictionBypass appBypass) {
         int userHandle = UserHandle.getUserId(uid);
         final int restrictionSetCount = mOpUserRestrictions.size();
 
@@ -4559,7 +4563,7 @@
             // For each client, check that the given op is not restricted, or that the given
             // package is exempt from the restriction.
             ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
-            if (restrictionState.hasRestriction(code, packageName, userHandle)) {
+            if (restrictionState.hasRestriction(code, packageName, attributionTag, userHandle)) {
                 RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
                 if (opBypass != null) {
                     // If we are the system, bypass user restrictions for certain codes
@@ -6173,25 +6177,20 @@
                     }
                 }
 
-                final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
-                        ? restrictionState.perUserExcludedPackages.size() : 0;
+                final int excludedPackageCount = restrictionState.perUserExcludedPackageTags != null
+                        ? restrictionState.perUserExcludedPackageTags.size() : 0;
                 if (excludedPackageCount > 0 && dumpOp < 0) {
                     boolean printedPackagesHeader = false;
                     for (int j = 0; j < excludedPackageCount; j++) {
-                        int userId = restrictionState.perUserExcludedPackages.keyAt(j);
-                        String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
+                        int userId = restrictionState.perUserExcludedPackageTags.keyAt(j);
+                        Map<String, String[]> packageNames =
+                                restrictionState.perUserExcludedPackageTags.valueAt(j);
                         if (packageNames == null) {
                             continue;
                         }
                         boolean hasPackage;
                         if (dumpPackage != null) {
-                            hasPackage = false;
-                            for (String pkg : packageNames) {
-                                if (dumpPackage.equals(pkg)) {
-                                    hasPackage = true;
-                                    break;
-                                }
-                            }
+                            hasPackage = packageNames.containsKey(dumpPackage);
                         } else {
                             hasPackage = true;
                         }
@@ -6206,8 +6205,24 @@
                             pw.println("      Excluded packages:");
                             printedPackagesHeader = true;
                         }
-                        pw.print("        "); pw.print("user: "); pw.print(userId);
-                                pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
+                        pw.print("        ");
+                        pw.print("user: ");
+                        pw.print(userId);
+                        pw.println(" packages: ");
+                        for (Map.Entry<String, String[]> entry : packageNames.entrySet()) {
+                            if (entry.getValue() == null) {
+                                continue;
+                            }
+                            pw.print("          ");
+                            pw.print(entry.getKey());
+                            pw.print(": ");
+                            if (entry.getValue().length == 0) {
+                                pw.print("*");
+                            } else {
+                                pw.print(Arrays.toString(entry.getValue()));
+                            }
+                            pw.println();
+                        }
                     }
                 }
             }
@@ -6241,7 +6256,7 @@
 
     @Override
     public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
-            String[] exceptionPackages) {
+            Map<String, String[]> excludedPackageTags) {
         if (Binder.getCallingPid() != Process.myPid()) {
             mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
                     Binder.getCallingPid(), Binder.getCallingUid(), null);
@@ -6257,11 +6272,11 @@
         }
         verifyIncomingOp(code);
         Objects.requireNonNull(token);
-        setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
+        setUserRestrictionNoCheck(code, restricted, token, userHandle, excludedPackageTags);
     }
 
     private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
-            int userHandle, String[] exceptionPackages) {
+            int userHandle, Map<String, String[]> excludedPackageTags) {
         synchronized (AppOpsService.this) {
             ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
 
@@ -6274,7 +6289,8 @@
                 mOpUserRestrictions.put(token, restrictionState);
             }
 
-            if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
+            if (restrictionState.setRestriction(code, restricted, excludedPackageTags,
+                    userHandle)) {
                 mHandler.sendMessage(PooledLambda.obtainMessage(
                         AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
                 mHandler.sendMessage(PooledLambda.obtainMessage(
@@ -6804,7 +6820,7 @@
     private final class ClientRestrictionState implements DeathRecipient {
         private final IBinder token;
         SparseArray<boolean[]> perUserRestrictions;
-        SparseArray<String[]> perUserExcludedPackages;
+        SparseArray<Map<String, String[]>> perUserExcludedPackageTags;
 
         public ClientRestrictionState(IBinder token)
                 throws RemoteException {
@@ -6813,7 +6829,7 @@
         }
 
         public boolean setRestriction(int code, boolean restricted,
-                String[] excludedPackages, int userId) {
+                Map<String, String[]> excludedPackageTags, int userId) {
             boolean changed = false;
 
             if (perUserRestrictions == null && restricted) {
@@ -6855,19 +6871,27 @@
                     }
 
                     if (userRestrictions != null) {
-                        final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
-                        if (perUserExcludedPackages == null && !noExcludedPackages) {
-                            perUserExcludedPackages = new SparseArray<>();
+                        final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackageTags);
+                        if (perUserExcludedPackageTags == null && !noExcludedPackages) {
+                            perUserExcludedPackageTags = new SparseArray<>();
                         }
-                        if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
-                                perUserExcludedPackages.get(thisUserId))) {
+                        if (perUserExcludedPackageTags != null) {
                             if (noExcludedPackages) {
-                                perUserExcludedPackages.remove(thisUserId);
-                                if (perUserExcludedPackages.size() <= 0) {
-                                    perUserExcludedPackages = null;
+                                perUserExcludedPackageTags.remove(thisUserId);
+                                if (perUserExcludedPackageTags.size() <= 0) {
+                                    perUserExcludedPackageTags = null;
                                 }
                             } else {
-                                perUserExcludedPackages.put(thisUserId, excludedPackages);
+                                Map<String, String[]> userExcludedPackageTags =
+                                        perUserExcludedPackageTags.get(thisUserId);
+                                if (userExcludedPackageTags == null) {
+                                    userExcludedPackageTags = new ArrayMap<>(
+                                            excludedPackageTags.size());
+                                    perUserExcludedPackageTags.put(thisUserId,
+                                            userExcludedPackageTags);
+                                }
+                                userExcludedPackageTags.clear();
+                                userExcludedPackageTags.putAll(excludedPackageTags);
                             }
                             changed = true;
                         }
@@ -6878,7 +6902,8 @@
             return changed;
         }
 
-        public boolean hasRestriction(int restriction, String packageName, int userId) {
+        public boolean hasRestriction(int restriction, String packageName, String attributionTag,
+                int userId) {
             if (perUserRestrictions == null) {
                 return false;
             }
@@ -6889,21 +6914,29 @@
             if (!restrictions[restriction]) {
                 return false;
             }
-            if (perUserExcludedPackages == null) {
+            if (perUserExcludedPackageTags == null) {
                 return true;
             }
-            String[] perUserExclusions = perUserExcludedPackages.get(userId);
+            Map<String, String[]> perUserExclusions = perUserExcludedPackageTags.get(userId);
             if (perUserExclusions == null) {
                 return true;
             }
-            return !ArrayUtils.contains(perUserExclusions, packageName);
+            String[] excludedTags = perUserExclusions.get(packageName);
+            if (excludedTags == null) {
+                return true;
+            }
+            if (excludedTags.length == 0) {
+                // all attribution tags within the package are excluded
+                return false;
+            }
+            return !ArrayUtils.contains(excludedTags, attributionTag);
         }
 
         public void removeUser(int userId) {
-            if (perUserExcludedPackages != null) {
-                perUserExcludedPackages.remove(userId);
-                if (perUserExcludedPackages.size() <= 0) {
-                    perUserExcludedPackages = null;
+            if (perUserExcludedPackageTags != null) {
+                perUserExcludedPackageTags.remove(userId);
+                if (perUserExcludedPackageTags.size() <= 0) {
+                    perUserExcludedPackageTags = null;
                 }
             }
             if (perUserRestrictions != null) {
@@ -7135,23 +7168,25 @@
             return mCheckOpsDelegate;
         }
 
-        public int checkOperation(int code, int uid, String packageName, boolean raw) {
+        public int checkOperation(int code, int uid, String packageName,
+                @Nullable String attributionTag, boolean raw) {
             if (mPolicy != null) {
                 if (mCheckOpsDelegate != null) {
-                    return mPolicy.checkOperation(code, uid, packageName, raw,
+                    return mPolicy.checkOperation(code, uid, packageName, attributionTag, raw,
                             this::checkDelegateOperationImpl);
                 } else {
-                    return mPolicy.checkOperation(code, uid, packageName, raw,
+                    return mPolicy.checkOperation(code, uid, packageName, attributionTag, raw,
                             AppOpsService.this::checkOperationImpl);
                 }
             } else if (mCheckOpsDelegate != null) {
-                return checkDelegateOperationImpl(code, uid, packageName, raw);
+                return checkDelegateOperationImpl(code, uid, packageName, attributionTag, raw);
             }
-            return checkOperationImpl(code, uid, packageName, raw);
+            return checkOperationImpl(code, uid, packageName, attributionTag, raw);
         }
 
-        private int checkDelegateOperationImpl(int code, int uid, String packageName, boolean raw) {
-            return mCheckOpsDelegate.checkOperation(code, uid, packageName, raw,
+        private int checkDelegateOperationImpl(int code, int uid, String packageName,
+                @Nullable String attributionTag, boolean raw) {
+            return mCheckOpsDelegate.checkOperation(code, uid, packageName, attributionTag, raw,
                     AppOpsService.this::checkOperationImpl);
         }
 
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 8829fa9..1e8d904 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -139,6 +139,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.CopyOnWriteArrayList;
 
@@ -1405,21 +1406,28 @@
 
         Preconditions.checkArgument(userId >= 0);
 
-
         boolean enabled = mInjector.getSettingsHelper().isLocationEnabled(userId);
 
-        String[] allowedPackages = null;
+        ArrayMap<String, String[]> allowedPackages = null;
         if (!enabled) {
-            ArraySet<String> packages = new ArraySet<>();
+            ArrayMap<String, ArraySet<String>> packages = new ArrayMap<>();
             for (LocationProviderManager manager : mProviderManagers) {
                 CallerIdentity identity = manager.getIdentity();
                 if (identity != null) {
-                    packages.add(identity.getPackageName());
+                    packages.computeIfAbsent(identity.getPackageName(), k -> new ArraySet<>()).add(
+                            identity.getAttributionTag());
                 }
             }
-            packages.add(mContext.getPackageName());
-            packages.addAll(mInjector.getSettingsHelper().getIgnoreSettingsPackageWhitelist());
-            allowedPackages = packages.toArray(new String[0]);
+            for (String packageName :
+                    mInjector.getSettingsHelper().getIgnoreSettingsPackageWhitelist()) {
+                packages.computeIfAbsent(packageName, k -> new ArraySet<>());
+            }
+            packages.computeIfAbsent(mContext.getPackageName(), k -> new ArraySet<>());
+
+            allowedPackages = new ArrayMap<>();
+            for (Map.Entry<String, ArraySet<String>> entry : packages.entrySet()) {
+                allowedPackages.put(entry.getKey(), entry.getValue().toArray(new String[0]));
+            }
         }
 
         AppOpsManager appOpsManager = Objects.requireNonNull(
diff --git a/services/core/java/com/android/server/location/LocationShellCommand.java b/services/core/java/com/android/server/location/LocationShellCommand.java
index 5dc3ed8..9378493 100644
--- a/services/core/java/com/android/server/location/LocationShellCommand.java
+++ b/services/core/java/com/android/server/location/LocationShellCommand.java
@@ -20,6 +20,7 @@
 import android.location.Criteria;
 import android.location.Location;
 import android.location.provider.ProviderProperties;
+import android.os.SystemClock;
 import android.os.UserHandle;
 
 import com.android.modules.utils.BasicShellCommandHandler;
@@ -236,7 +237,7 @@
         Location location = new Location(provider);
         location.setAccuracy(DEFAULT_TEST_LOCATION_ACCURACY);
         location.setTime(System.currentTimeMillis());
-        location.setElapsedRealtimeNanos(System.nanoTime());
+        location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
 
         do {
             String option = getNextOption();
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index 3a097a7..2cfbf26 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -44,6 +44,7 @@
 import com.android.internal.util.function.NonaFunction;
 import com.android.internal.util.function.OctFunction;
 import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.QuintFunction;
 import com.android.internal.util.function.TriFunction;
 import com.android.server.LocalServices;
 
@@ -140,9 +141,10 @@
     }
 
     @Override
-    public int checkOperation(int code, int uid, String packageName, boolean raw,
-            QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl) {
-        return superImpl.apply(code, uid, packageName, raw);
+    public int checkOperation(int code, int uid, String packageName,
+            @Nullable String attributionTag, boolean raw,
+            QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl) {
+        return superImpl.apply(code, uid, packageName, attributionTag, raw);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index ae873e2..2ac50b6 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -66,7 +66,6 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
 import com.android.server.utils.ManagedApplicationService;
 import com.android.server.utils.ManagedApplicationService.BinderChecker;
 import com.android.server.utils.ManagedApplicationService.LogEvent;
@@ -86,6 +85,7 @@
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -856,12 +856,15 @@
         // If user changed drop restrictions for the old user.
         if (oldUserId != newUserId) {
             appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
-                    false, mOverlayToken, null, oldUserId);
+                    false, mOverlayToken, (Map<String, String[]>) null, oldUserId);
         }
 
         // Apply the restrictions for the current user based on vr state
-        String[] exemptions = (exemptedPackage == null) ? new String[0] :
-                new String[] { exemptedPackage };
+        ArrayMap<String, String[]> exemptions = null;
+        if (exemptedPackage != null) {
+            exemptions = new ArrayMap<>(1);
+            exemptions.put(exemptedPackage, new String[0]);
+        }
 
         appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
                 mVrModeEnabled, mOverlayToken, exemptions, newUserId);