Pipe start op throught app ops policy and delegate

bug: 185504196

Test: atest CtsAppOpsTestCases
      atest CtsPermissionTestCases
      atest CtsPermission2TestCases
      atest CtsPermission3TestCases
      atest CtsPermission4TestCases
      atest CtsPermission5TestCases

Change-Id: I5869a3e9719830f59624519f2d54f0765119cf5f
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index 6af4d93..341b9c5 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -26,6 +26,7 @@
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.util.function.HeptFunction;
 import com.android.internal.util.function.HexFunction;
+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.TriFunction;
@@ -101,8 +102,31 @@
                         Boolean, SyncNotedAppOp> superImpl);
 
         /**
+         * Allows overriding start operation behavior.
+         *
+         * @param token The client state.
+         * @param code The op code to start.
+         * @param uid The UID for which to note.
+         * @param packageName The package for which to note. {@code null} for system package.
+         * @param attributionTag the attribution tag.
+         * @param startIfModeDefault Whether to start the op of the mode is default.
+         * @param shouldCollectAsyncNotedOp If an {@link AsyncNotedAppOp} should be collected
+         * @param message The message in the async noted op
+         * @param shouldCollectMessage whether to collect messages
+         * @param superImpl The super implementation.
+         * @return The app op note result.
+         */
+        SyncNotedAppOp startOperation(IBinder token, int code, int uid,
+                @Nullable String packageName, @Nullable String attributionTag,
+                boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
+                @Nullable String message, boolean shouldCollectMessage, @NonNull NonaFunction<
+                        IBinder, Integer, Integer, String, String, Boolean, Boolean, String,
+                        Boolean, SyncNotedAppOp> superImpl);
+
+        /**
          * Allows overriding start proxy operation behavior.
          *
+         * @param token The client state.
          * @param code The op code to start.
          * @param attributionSource The permission identity of the caller.
          * @param startIfModeDefault Whether to start the op of the mode is default.
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 64c914e..890f982 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -344,6 +344,7 @@
         <permission name="android.permission.ACTIVITY_EMBEDDING"/>
         <permission name="android.permission.FORCE_STOP_PACKAGES"/>
         <permission name="android.permission.GET_APP_OPS_STATS"/>
+        <permission name="android.permission.WATCH_APPOPS"/>
         <permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/>
         <permission name="android.permission.INSTALL_LOCATION_PROVIDER"/>
         <permission name="android.permission.INSTALL_PACKAGES"/>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0958e54..8cfa0cf 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -299,6 +299,7 @@
     <uses-permission android:name="android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS" />
 
     <uses-permission android:name="android.permission.MANAGE_APPOPS" />
+    <uses-permission android:name="android.permission.WATCH_APPOPS" />
 
     <!-- Permission required for IncrementalLogCollectionTest -->
     <uses-permission android:name="android.permission.LOADER_USAGE_STATS" />
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4b640a6..8094566 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -346,6 +346,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.HeptFunction;
 import com.android.internal.util.function.HexFunction;
+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.TriFunction;
@@ -16737,6 +16738,29 @@
         }
 
         @Override
+        public SyncNotedAppOp startOperation(IBinder token, int code, int uid,
+                @Nullable String packageName, @Nullable String attributionTag,
+                boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
+                @Nullable String message, boolean shouldCollectMessage,
+                @NonNull NonaFunction<IBinder, Integer, Integer, String, String, Boolean,
+                        Boolean, String, Boolean, SyncNotedAppOp> 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(token, code, shellUid, "com.android.shell",
+                            attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message,
+                            shouldCollectMessage);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+            return superImpl.apply(token, code, uid, packageName, attributionTag,
+                    startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+        }
+
+        @Override
         public SyncNotedAppOp startProxyOperation(IBinder token, int code,
                 @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
                 boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 2a0beb8..7eaf18f 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3509,9 +3509,19 @@
     }
 
     @Override
-    public SyncNotedAppOp startOperation(IBinder clientId, int code, int uid, String packageName,
-            String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
+    public SyncNotedAppOp startOperation(IBinder token, int code, int uid,
+            @Nullable String packageName, @Nullable String attributionTag,
+            boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
             String message, boolean shouldCollectMessage) {
+        return mCheckOpsDelegateDispatcher.startOperation(token, code, uid, packageName,
+                attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message,
+                shouldCollectMessage);
+    }
+
+    private SyncNotedAppOp startOperationImpl(@NonNull IBinder clientId, int code, int uid,
+            @Nullable String packageName, @Nullable String attributionTag,
+            boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @NonNull String message,
+            boolean shouldCollectMessage) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
         verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
@@ -3535,7 +3545,6 @@
         return startOperationUnchecked(clientId, code, uid, packageName, attributionTag,
                 Process.INVALID_UID, null, null, OP_FLAG_SELF, startIfModeDefault,
                 shouldCollectAsyncNotedOp, message, shouldCollectMessage, false);
-
     }
 
     @Override
@@ -6973,8 +6982,8 @@
         }
 
         public SyncNotedAppOp noteProxyOperation(int code, AttributionSource attributionSource,
-                boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
-                boolean skipProxyOperation) {
+                boolean shouldCollectAsyncNotedOp, @Nullable String message,
+                boolean shouldCollectMessage, boolean skipProxyOperation) {
             if (mPolicy != null) {
                 if (mCheckOpsDelegate != null) {
                     return mPolicy.noteProxyOperation(code, attributionSource,
@@ -7003,6 +7012,38 @@
                     AppOpsService.this::noteProxyOperationImpl);
         }
 
+        public SyncNotedAppOp startOperation(IBinder token, int code, int uid,
+                @Nullable String packageName, @NonNull String attributionTag,
+                boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
+                @Nullable String message, boolean shouldCollectMessage) {
+            if (mPolicy != null) {
+                if (mCheckOpsDelegate != null) {
+                    return mPolicy.startOperation(token, code, uid, packageName,
+                            attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message,
+                            shouldCollectMessage, this::startDelegateOperationImpl);
+                } else {
+                    return mPolicy.startOperation(token, code, uid, packageName, attributionTag,
+                            startIfModeDefault, shouldCollectAsyncNotedOp, message,
+                            shouldCollectMessage, AppOpsService.this::startOperationImpl);
+                }
+            } else if (mCheckOpsDelegate != null) {
+                return startDelegateOperationImpl(token, code, uid, packageName, attributionTag,
+                        startIfModeDefault, shouldCollectAsyncNotedOp, message,
+                        shouldCollectMessage);
+            }
+            return startOperationImpl(token, code, uid, packageName, attributionTag,
+                    startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+        }
+
+        private SyncNotedAppOp startDelegateOperationImpl(IBinder token, int code, int uid,
+                @Nullable String packageName, @Nullable String attributionTag,
+                boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message,
+                boolean shouldCollectMessage) {
+            return mCheckOpsDelegate.startOperation(token, code, uid, packageName, attributionTag,
+                    startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+                    AppOpsService.this::startOperationImpl);
+        }
+
         public SyncNotedAppOp startProxyOperation(IBinder clientId, int code,
                 @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
                 boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index ca7406b..622b758 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -37,11 +37,11 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
-import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.function.HeptFunction;
 import com.android.internal.util.function.HexFunction;
+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.TriFunction;
@@ -166,7 +166,7 @@
             boolean shouldCollectAsyncNotedOp, @Nullable String message,
             boolean shouldCollectMessage, boolean skipProxyOperation, @NonNull HexFunction<Integer,
                     AttributionSource, Boolean, String, Boolean, Boolean,
-            SyncNotedAppOp> superImpl) {
+                    SyncNotedAppOp> superImpl) {
         return superImpl.apply(resolveDatasourceOp(code, attributionSource.getUid(),
                 attributionSource.getPackageName(), attributionSource.getAttributionTag()),
                 attributionSource, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
@@ -174,6 +174,17 @@
     }
 
     @Override
+    public SyncNotedAppOp startOperation(IBinder token, int code, int uid,
+            @Nullable String packageName, @Nullable String attributionTag,
+            boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message,
+            boolean shouldCollectMessage, @NonNull NonaFunction<IBinder, Integer, Integer, String,
+                    String, Boolean, Boolean, String, Boolean, SyncNotedAppOp> superImpl) {
+        return superImpl.apply(token, resolveDatasourceOp(code, uid, packageName, attributionTag),
+                uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp,
+                message, shouldCollectMessage);
+    }
+
+    @Override
     public SyncNotedAppOp startProxyOperation(IBinder token, int code,
             @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,