Moved input time out handling to ActivityTaskManagerService (14/n)

Also:
- Post handling of scheduling GC from WM to AM side.
- Removed access on package manager through mAm reference.

Bug: 80414790
Test: Existing tests pass
Change-Id: Ia76c57411fc332ea099adb6ef7975e012b4d744c
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index ab1ba6c..4a0f692 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.BIND_VOICE_INTERACTION;
 import static android.Manifest.permission.CHANGE_CONFIGURATION;
 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.Manifest.permission.FILTER_EVENTS;
 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.READ_FRAME_BUFFER;
@@ -36,15 +37,12 @@
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
-import static android.app.ActivityTaskManager.INVALID_STACK_ID;
 import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
 import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.AppOpsManager.OP_NONE;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -74,7 +72,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IMMERSIVE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
@@ -122,6 +119,8 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.DialogInterface;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.database.ContentObserver;
 import android.os.IUserManager;
 import android.os.PowerManager;
@@ -131,7 +130,6 @@
 import android.os.WorkSource;
 import android.view.WindowManager;
 import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
 import com.android.server.AppOpsService;
 import com.android.server.pm.UserManagerService;
@@ -181,7 +179,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PersistableBundle;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.StrictMode;
 import android.os.SystemClock;
@@ -250,6 +247,11 @@
     private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
 
+    // How long we wait until we timeout on key dispatching.
+    private static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000;
+    // How long we wait until we timeout on key dispatching during instrumentation.
+    private static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000;
+
     Context mContext;
     /**
      * This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can
@@ -261,6 +263,7 @@
     ActivityManagerService mAm;
     ActivityManagerInternal mAmInternal;
     UriGrantsManagerInternal mUgmInternal;
+    private PackageManagerInternal mPmInternal;
     /* Global service lock used by the package the owns this service. */
     Object mGlobalLock;
     ActivityStackSupervisor mStackSupervisor;
@@ -269,6 +272,8 @@
     private AppOpsService mAppOpsService;
     /** All processes currently running that might have a window organized by name. */
     final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
+    /** All processes we currently have running mapped by pid */
+    final SparseArray<WindowProcessController> mPidMap = new SparseArray<>();
     /** This is the process holding what we currently consider to be the "home" activity. */
     WindowProcessController mHomeProcess;
     /**
@@ -4540,6 +4545,80 @@
                 && mAmInternal.getCurrentUser().isDemo());
     }
 
+    static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
+        if (r == null || !r.hasProcess()) {
+            return KEY_DISPATCHING_TIMEOUT_MS;
+        }
+        return getInputDispatchingTimeoutLocked(r.app);
+    }
+
+    private static long getInputDispatchingTimeoutLocked(WindowProcessController r) {
+        if (r != null && (r.isInstrumenting() || r.isUsingWrapper())) {
+            return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS;
+        }
+        return KEY_DISPATCHING_TIMEOUT_MS;
+    }
+
+    long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
+        if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires permission " + FILTER_EVENTS);
+        }
+        WindowProcessController proc;
+        long timeout;
+        synchronized (mGlobalLock) {
+            proc = mPidMap.get(pid);
+            timeout = getInputDispatchingTimeoutLocked(proc);
+        }
+
+        if (inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
+            return -1;
+        }
+
+        return timeout;
+    }
+
+    /**
+     * Handle input dispatching timeouts.
+     * Returns whether input dispatching should be aborted or not.
+     */
+    boolean inputDispatchingTimedOut(final WindowProcessController proc,
+            final ActivityRecord activity, final ActivityRecord parent,
+            final boolean aboveSystem, String reason) {
+        if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires permission " + FILTER_EVENTS);
+        }
+
+        final String annotation;
+        if (reason == null) {
+            annotation = "Input dispatching timed out";
+        } else {
+            annotation = "Input dispatching timed out (" + reason + ")";
+        }
+
+        if (proc != null) {
+            synchronized (mGlobalLock) {
+                if (proc.isDebugging()) {
+                    return false;
+                }
+
+                if (proc.isInstrumenting()) {
+                    Bundle info = new Bundle();
+                    info.putString("shortMsg", "keyDispatchingTimedOut");
+                    info.putString("longMsg", annotation);
+                    mAm.finishInstrumentationLocked(
+                            (ProcessRecord) proc.mOwner, Activity.RESULT_CANCELED, info);
+                    return true;
+                }
+            }
+            mH.post(() -> {
+                mAm.mAppErrors.appNotResponding(
+                        (ProcessRecord) proc.mOwner, activity, parent, aboveSystem, annotation);
+            });
+        }
+
+        return true;
+    }
+
     /**
      * Decide based on the configuration whether we should show the ANR,
      * crash, etc dialogs.  The idea is that if there is no affordance to
@@ -4784,6 +4863,26 @@
         return kept;
     }
 
+    void scheduleAppGcsLocked() {
+        mH.post(() -> mAmInternal.scheduleAppGcs());
+    }
+
+    /**
+     * Returns the PackageManager. Used by classes hosted by {@link ActivityTaskManagerService}. The
+     * PackageManager could be unavailable at construction time and therefore needs to be accessed
+     * on demand.
+     */
+    IPackageManager getPackageManager() {
+        return AppGlobals.getPackageManager();
+    }
+
+    PackageManagerInternal getPackageManagerInternalLocked() {
+        if (mPmInternal == null) {
+            mPmInternal = LocalServices.getService(PackageManagerInternal.class);
+        }
+        return mPmInternal;
+    }
+
     void logAppTooSlow(WindowProcessController app, long startTime, String msg) {
         if (true || Build.IS_USER) {
             return;
@@ -5232,5 +5331,27 @@
                 }
             }
         }
+
+        @Override
+        public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) {
+            synchronized (mGlobalLock) {
+                return ActivityTaskManagerService.this.inputDispatchingTimedOut(
+                        pid, aboveSystem, reason);
+            }
+        }
+
+        @Override
+        public void onProcessMapped(int pid, WindowProcessController proc) {
+            synchronized (mGlobalLock) {
+                mPidMap.put(pid, proc);
+            }
+        }
+
+        @Override
+        public void onProcessUnMapped(int pid) {
+            synchronized (mGlobalLock) {
+                mPidMap.remove(pid);
+            }
+        }
     }
 }