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/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 29937ab..5bf6892 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3658,7 +3658,7 @@
             }
 
             app = r.app;
-            if (app != null && app.debugging) {
+            if (app != null && app.isDebugging()) {
                 // The app's being debugged; let it ride
                 return;
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 594b391..8b25605 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -463,12 +463,6 @@
     static final int BROADCAST_FG_TIMEOUT = 10*1000;
     static final int BROADCAST_BG_TIMEOUT = 60*1000;
 
-    // How long we wait until we timeout on key dispatching.
-    static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
-
-    // How long we wait until we timeout on key dispatching during instrumentation.
-    static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
-
     // Disable hidden API checks for the newly started instrumentation.
     // Must be kept in sync with Am.
     private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0;
@@ -695,10 +689,42 @@
      * All of the processes we currently have running organized by pid.
      * The keys are the pid running the application.
      *
-     * <p>NOTE: This object is protected by its own lock, NOT the global
-     * activity manager lock!
+     * <p>NOTE: This object is protected by its own lock, NOT the global activity manager lock!
      */
-    final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();
+    final PidMap mPidsSelfLocked = new PidMap();
+    final class PidMap {
+        private final SparseArray<ProcessRecord> mPidMap = new SparseArray<>();
+
+        void put(int key, ProcessRecord value) {
+            mPidMap.put(key, value);
+            mAtmInternal.onProcessMapped(key, value.getWindowProcessController());
+        }
+
+        void remove(int pid) {
+            mPidMap.remove(pid);
+            mAtmInternal.onProcessUnMapped(pid);
+        }
+
+        ProcessRecord get(int pid) {
+            return mPidMap.get(pid);
+        }
+
+        int size() {
+            return mPidMap.size();
+        }
+
+        ProcessRecord valueAt(int index) {
+            return mPidMap.valueAt(index);
+        }
+
+        int keyAt(int index) {
+            return mPidMap.keyAt(index);
+        }
+
+        int indexOfKey(int key) {
+            return mPidMap.indexOfKey(key);
+        }
+    }
 
     /**
      * All of the processes that have been forced to be important.  The key
@@ -3635,8 +3661,8 @@
                             app.pendingStart = false;
                             return;
                         }
-                        app.usingWrapper = invokeWith != null
-                                || SystemProperties.get("wrap." + app.processName) != null;
+                        app.setUsingWrapper(invokeWith != null
+                                || SystemProperties.get("wrap." + app.processName) != null);
                         mPendingStarts.put(startSeq, app);
                     }
                     final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
@@ -3732,7 +3758,7 @@
         // Indicates that this process start has been taken care of.
         if (mPendingStarts.get(expectedStartSeq) == null) {
             if (pending.pid == startResult.pid) {
-                pending.usingWrapper = startResult.usingWrapper;
+                pending.setUsingWrapper(startResult.usingWrapper);
                 // TODO: Update already existing clients of usingWrapper
             }
             return false;
@@ -3795,7 +3821,7 @@
         }
         reportUidInfoMessageLocked(TAG, buf.toString(), app.startUid);
         app.setPid(pid);
-        app.usingWrapper = usingWrapper;
+        app.setUsingWrapper(usingWrapper);
         app.pendingStart = false;
         checkTime(app.startTime, "startProcess: starting to update pids map");
         ProcessRecord oldApp;
@@ -3880,7 +3906,7 @@
             aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
             ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                     aInfo.applicationInfo.uid, true);
-            if (app == null || app.instr == null) {
+            if (app == null || app.getActiveInstrumentation() == null) {
                 intent.setFlags(intent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
                 final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
                 // For ANR debugging to verify if the user activity is the one that actually
@@ -4400,9 +4426,9 @@
         app.clearRecentTasks();
         app.clearActivities();
 
-        if (app.instr != null) {
+        if (app.getActiveInstrumentation() != null) {
             Slog.w(TAG, "Crash of app " + app.processName
-                  + " running instrumentation " + app.instr.mClass);
+                  + " running instrumentation " + app.getActiveInstrumentation().mClass);
             Bundle info = new Bundle();
             info.putString("shortMsg", "Process crashed.");
             finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
@@ -4556,7 +4582,7 @@
         // Clean up already done if the process has been re-started.
         if (app.pid == pid && app.thread != null &&
                 app.thread.asBinder() == thread.asBinder()) {
-            boolean doLowMem = app.instr == null;
+            boolean doLowMem = app.getActiveInstrumentation() == null;
             boolean doOomAdj = doLowMem;
             if (!app.killedByAm) {
                 reportUidInfoMessageLocked(TAG,
@@ -5885,7 +5911,7 @@
         if (app == null && startSeq > 0) {
             final ProcessRecord pending = mPendingStarts.get(startSeq);
             if (pending != null && pending.startUid == callingUid
-                    && handleProcessStartedLocked(pending, pid, pending.usingWrapper,
+                    && handleProcessStartedLocked(pending, pid, pending.isUsingWrapper(),
                             startSeq, true)) {
                 app = pending;
             }
@@ -5939,7 +5965,7 @@
         app.forcingToImportant = null;
         updateProcessForegroundLocked(app, false, false);
         app.hasShownUi = false;
-        app.debugging = false;
+        app.setDebugging(false);
         app.cached = false;
         app.killedByAm = false;
         app.killed = false;
@@ -5976,7 +6002,7 @@
                 testMode = mWaitForDebugger
                     ? ApplicationThreadConstants.DEBUG_WAIT
                     : ApplicationThreadConstants.DEBUG_ON;
-                app.debugging = true;
+                app.setDebugging(true);
                 if (mDebugTransient) {
                     mDebugApp = mOrigDebugApp;
                     mWaitForDebugger = mOrigWaitForDebugger;
@@ -5998,13 +6024,15 @@
                                 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
             }
 
-            if (app.instr != null) {
-                notifyPackageUse(app.instr.mClass.getPackageName(),
+            final ActiveInstrumentation instr = app.getActiveInstrumentation();
+
+            if (instr != null) {
+                notifyPackageUse(instr.mClass.getPackageName(),
                                  PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
             }
             if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
                     + processName + " with config " + getGlobalConfiguration());
-            ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
+            ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
             app.compat = compatibilityInfoForPackageLocked(appInfo);
 
             ProfilerInfo profilerInfo = null;
@@ -6021,8 +6049,8 @@
                         preBindAgent = mProfilerInfo.agent;
                     }
                 }
-            } else if (app.instr != null && app.instr.mProfileFile != null) {
-                profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false,
+            } else if (instr != null && instr.mProfileFile != null) {
+                profilerInfo = new ProfilerInfo(instr.mProfileFile, null, 0, false, false,
                         null, false);
             }
             if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) {
@@ -6059,21 +6087,22 @@
             // currently active instrumentation.  (Note we do this AFTER all of the profiling
             // stuff above because profiling can currently happen only in the primary
             // instrumentation process.)
-            if (mActiveInstrumentation.size() > 0 && app.instr == null) {
-                for (int i = mActiveInstrumentation.size() - 1; i >= 0 && app.instr == null; i--) {
+            if (mActiveInstrumentation.size() > 0 && instr == null) {
+                for (int i = mActiveInstrumentation.size() - 1;
+                        i >= 0 && app.getActiveInstrumentation() == null; i--) {
                     ActiveInstrumentation aInstr = mActiveInstrumentation.get(i);
                     if (!aInstr.mFinished && aInstr.mTargetInfo.uid == app.uid) {
                         if (aInstr.mTargetProcesses.length == 0) {
                             // This is the wildcard mode, where every process brought up for
                             // the target instrumentation should be included.
                             if (aInstr.mTargetInfo.packageName.equals(app.info.packageName)) {
-                                app.instr = aInstr;
+                                app.setActiveInstrumentation(aInstr);
                                 aInstr.mRunningProcesses.add(app);
                             }
                         } else {
                             for (String proc : aInstr.mTargetProcesses) {
                                 if (proc.equals(app.processName)) {
-                                    app.instr = aInstr;
+                                    app.setActiveInstrumentation(aInstr);
                                     aInstr.mRunningProcesses.add(app);
                                     break;
                                 }
@@ -6103,16 +6132,17 @@
 
             checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
             mStackSupervisor.getActivityMetricsLogger().notifyBindApplication(app);
+            final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
             if (app.isolatedEntryPoint != null) {
                 // This is an isolated process which should just call an entry point instead of
                 // being bound to an application.
                 thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
-            } else if (app.instr != null) {
+            } else if (instr2 != null) {
                 thread.bindApplication(processName, appInfo, providers,
-                        app.instr.mClass,
-                        profilerInfo, app.instr.mArguments,
-                        app.instr.mWatcher,
-                        app.instr.mUiAutomationConnection, testMode,
+                        instr2.mClass,
+                        profilerInfo, instr2.mArguments,
+                        instr2.mWatcher,
+                        instr2.mUiAutomationConnection, testMode,
                         mBinderTransactionTrackingEnabled, enableTrackAllocation,
                         isRestrictedBackupMode || !normalMode, app.isPersistent(),
                         new Configuration(getGlobalConfiguration()), app.compat,
@@ -9257,7 +9287,8 @@
                 if (proc == null) {
                     throw new SecurityException("Unknown process: " + callingPid);
                 }
-                if (proc.instr == null || proc.instr.mUiAutomationConnection == null) {
+                if (proc.getActiveInstrumentation() == null
+                        || proc.getActiveInstrumentation().mUiAutomationConnection == null) {
                     throw new SecurityException("Only an instrumentation process "
                             + "with a UiAutomation can call setUserIsMonkey");
                 }
@@ -9380,89 +9411,6 @@
                 ActivityManager.BUGREPORT_OPTION_WIFI);
     }
 
-
-    public static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
-        if (r == null || !r.hasProcess()) {
-            return KEY_DISPATCHING_TIMEOUT;
-        }
-        return getInputDispatchingTimeoutLocked((ProcessRecord) r.app.mOwner);
-    }
-
-    public static long getInputDispatchingTimeoutLocked(ProcessRecord r) {
-        if (r != null && (r.instr != null || r.usingWrapper)) {
-            return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
-        }
-        return KEY_DISPATCHING_TIMEOUT;
-    }
-
-    @Override
-    public long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
-        if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires permission "
-                    + android.Manifest.permission.FILTER_EVENTS);
-        }
-        ProcessRecord proc;
-        long timeout;
-        synchronized (this) {
-            synchronized (mPidsSelfLocked) {
-                proc = mPidsSelfLocked.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.
-     */
-    public boolean inputDispatchingTimedOut(final ProcessRecord proc,
-            final ActivityRecord activity, final ActivityRecord parent,
-            final boolean aboveSystem, String reason) {
-        if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires permission "
-                    + android.Manifest.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 (this) {
-                if (proc.debugging) {
-                    return false;
-                }
-
-                if (proc.instr != null) {
-                    Bundle info = new Bundle();
-                    info.putString("shortMsg", "keyDispatchingTimedOut");
-                    info.putString("longMsg", annotation);
-                    finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
-                    return true;
-                }
-            }
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mAppErrors.appNotResponding(proc, activity, parent, aboveSystem, annotation);
-                }
-            });
-        }
-
-        return true;
-    }
-
     public void registerProcessObserver(IProcessObserver observer) {
         enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
                 "registerProcessObserver()");
@@ -17137,7 +17085,7 @@
 
             ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks,
                     abiOverride);
-            app.instr = activeInstr;
+            app.setActiveInstrumentation(activeInstr);
             activeInstr.mFinished = false;
             activeInstr.mRunningProcesses.add(app);
             if (!mActiveInstrumentation.contains(activeInstr)) {
@@ -17170,16 +17118,17 @@
     }
 
     void addInstrumentationResultsLocked(ProcessRecord app, Bundle results) {
-        if (app.instr == null) {
+        final ActiveInstrumentation instr = app.getActiveInstrumentation();
+        if (instr == null) {
             Slog.w(TAG, "finishInstrumentation called on non-instrumented: " + app);
             return;
         }
 
-        if (!app.instr.mFinished && results != null) {
-            if (app.instr.mCurResults == null) {
-                app.instr.mCurResults = new Bundle(results);
+        if (!instr.mFinished && results != null) {
+            if (instr.mCurResults == null) {
+                instr.mCurResults = new Bundle(results);
             } else {
-                app.instr.mCurResults.putAll(results);
+                instr.mCurResults.putAll(results);
             }
         }
     }
@@ -17205,37 +17154,38 @@
 
     @GuardedBy("this")
     void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
-        if (app.instr == null) {
+        final ActiveInstrumentation instr = app.getActiveInstrumentation();
+        if (instr == null) {
             Slog.w(TAG, "finishInstrumentation called on non-instrumented: " + app);
             return;
         }
 
-        if (!app.instr.mFinished) {
-            if (app.instr.mWatcher != null) {
-                Bundle finalResults = app.instr.mCurResults;
+        if (!instr.mFinished) {
+            if (instr.mWatcher != null) {
+                Bundle finalResults = instr.mCurResults;
                 if (finalResults != null) {
-                    if (app.instr.mCurResults != null && results != null) {
+                    if (instr.mCurResults != null && results != null) {
                         finalResults.putAll(results);
                     }
                 } else {
                     finalResults = results;
                 }
-                mInstrumentationReporter.reportFinished(app.instr.mWatcher,
-                        app.instr.mClass, resultCode, finalResults);
+                mInstrumentationReporter.reportFinished(instr.mWatcher,
+                        instr.mClass, resultCode, finalResults);
             }
 
             // Can't call out of the system process with a lock held, so post a message.
-            if (app.instr.mUiAutomationConnection != null) {
+            if (instr.mUiAutomationConnection != null) {
                 mAppOpsService.setAppOpsServiceDelegate(null);
                 getPackageManagerInternalLocked().setCheckPermissionDelegate(null);
                 mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
-                        app.instr.mUiAutomationConnection).sendToTarget();
+                        instr.mUiAutomationConnection).sendToTarget();
             }
-            app.instr.mFinished = true;
+            instr.mFinished = true;
         }
 
-        app.instr.removeProcess(app);
-        app.instr = null;
+        instr.removeProcess(app);
+        app.setActiveInstrumentation(null);
 
         forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId,
                 "finished inst");
@@ -17709,7 +17659,7 @@
             if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making running remote anim: " + app);
             }
-        } else if (app.instr != null) {
+        } else if (app.getActiveInstrumentation() != null) {
             // Don't want to kill running instrumentation.
             adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
@@ -21208,6 +21158,13 @@
                 return ActivityManagerService.this.getHomeIntent();
             }
         }
+
+        @Override
+        public void scheduleAppGcs() {
+            synchronized (ActivityManagerService.this) {
+                ActivityManagerService.this.scheduleAppGcsLocked();
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 19ea955..c9f239e 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1036,7 +1036,7 @@
                 (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges,
                 task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
                 appInfo.targetSdkVersion, mRotationAnimationHint,
-                ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);
+                ActivityTaskManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);
 
         task.addActivityToTop(this);
 
@@ -2134,7 +2134,7 @@
                     mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */,
                             false /* remove */, true /* processPausingActivities */);
                 }
-                service.mAm.scheduleAppGcsLocked();
+                service.scheduleAppGcsLocked();
             }
         }
     }
@@ -2159,13 +2159,11 @@
                     !hasProcess() || app.getPid() == windowPid || windowPid == -1;
         }
         if (windowFromSameProcessAsActivity) {
-            return service.mAm.inputDispatchingTimedOut(
-                    (ProcessRecord) anrApp.mOwner, anrActivity, this, false, reason);
+            return service.inputDispatchingTimedOut(anrApp, anrActivity, this, false, reason);
         } else {
             // In this case another process added windows using this activity token. So, we call the
             // generic service input dispatch timed out method so that the right process is blamed.
-            return service.mAm.inputDispatchingTimedOut(
-                    windowPid, false /* aboveSystem */, reason) < 0;
+            return service.inputDispatchingTimedOut(windowPid, false /* aboveSystem */, reason) < 0;
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a732575..70ac197 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1400,7 +1400,7 @@
                 // (e.g. AMS.startActivityAsUser).
                 final long token = Binder.clearCallingIdentity();
                 try {
-                    return mService.mAm.getPackageManagerInternalLocked().resolveIntent(
+                    return mService.getPackageManagerInternalLocked().resolveIntent(
                             intent, resolvedType, modifiedFlags, userId, true, filterCallingUid);
                 } finally {
                     Binder.restoreCallingIdentity(token);
@@ -2109,7 +2109,7 @@
 
         if (allResumedActivitiesIdle()) {
             if (r != null) {
-                mService.mAm.scheduleAppGcsLocked();
+                mService.scheduleAppGcsLocked();
             }
 
             if (mLaunchingActivity.isHeld()) {
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index ca12716..177e2f5 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -237,7 +237,7 @@
                 (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
             return false;
         }
-        final PackageManagerInternal pmi = mService.mAm.getPackageManagerInternalLocked();
+        final PackageManagerInternal pmi = mService.getPackageManagerInternalLocked();
         if (pmi == null) {
             return false;
         }
@@ -318,7 +318,7 @@
     private boolean interceptHarmfulAppIfNeeded() {
         CharSequence harmfulAppWarning;
         try {
-            harmfulAppWarning = mService.mAm.getPackageManager()
+            harmfulAppWarning = mService.getPackageManager()
                     .getHarmfulAppWarning(mAInfo.packageName, mUserId);
         } catch (RemoteException ex) {
             return false;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 8be5ada..0a1b26c 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -672,7 +672,7 @@
                     && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
                 try {
                     intent.addCategory(Intent.CATEGORY_VOICE);
-                    if (!mService.mAm.getPackageManager().activitySupportsIntent(
+                    if (!mService.getPackageManager().activitySupportsIntent(
                             intent.getComponent(), intent, resolvedType)) {
                         Slog.w(TAG,
                                 "Activity being started in current voice task does not support voice: "
@@ -690,7 +690,7 @@
             // If the caller is starting a new voice session, just make sure the target
             // is actually allowing it to run this way.
             try {
-                if (!mService.mAm.getPackageManager().activitySupportsIntent(intent.getComponent(),
+                if (!mService.getPackageManager().activitySupportsIntent(intent.getComponent(),
                         intent, resolvedType)) {
                     Slog.w(TAG,
                             "Activity being started in new voice task does not support: "
@@ -772,7 +772,7 @@
         // launch the review activity and pass a pending intent to start the activity
         // we are to launching now after the review is completed.
         if (aInfo != null) {
-            if (mService.mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+            if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
                     aInfo.packageName, userId)) {
                 IIntentSender target = mService.mAm.getIntentSenderLocked(
                         ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
@@ -870,7 +870,7 @@
             String resolvedType, int userId) {
         if (auxiliaryResponse != null && auxiliaryResponse.needsPhaseTwo) {
             // request phase two resolution
-            mService.mAm.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo(
+            mService.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo(
                     auxiliaryResponse, originalIntent, resolvedType, callingPackage,
                     verificationBundle, userId);
         }
@@ -970,7 +970,7 @@
                 && !(Intent.ACTION_VIEW.equals(intent.getAction()) && intent.getData() == null)
                 && !Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE.equals(intent.getAction())
                 && !Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE.equals(intent.getAction())
-                && mService.mAm.getPackageManagerInternalLocked()
+                && mService.getPackageManagerInternalLocked()
                         .isInstantAppInstallerComponent(intent.getComponent())) {
             // intercept intents targeted directly to the ephemeral installer the
             // ephemeral installer should never be started with a raw Intent; instead
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);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 7652dd4..2c58094 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -436,7 +436,7 @@
              * If this process was running instrumentation, finish now - it will be handled in
              * {@link ActivityManagerService#handleAppDiedLocked}.
              */
-            if (r != null && r.instr != null) {
+            if (r != null && r.getActiveInstrumentation() != null) {
                 return;
             }
 
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 046cfc7..b36b5d3 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1462,7 +1462,7 @@
         // If the receiver app is being debugged we quietly ignore unresponsiveness, just
         // tidying up and moving on to the next broadcast without crashing or ANRing this
         // app just because it's stopped at a breakpoint.
-        final boolean debugging = (r.curApp != null && r.curApp.debugging);
+        final boolean debugging = (r.curApp != null && r.curApp.isDebugging());
 
         Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
                 + ", started " + (now - r.receiverTime) + "ms ago");
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b33ce2b..8c552b9 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -187,8 +187,9 @@
     int lruSeq;                 // Sequence id for identifying LRU update cycles
     CompatibilityInfo compat;   // last used compatibility mode
     IBinder.DeathRecipient deathRecipient; // Who is watching for the death.
-    ActiveInstrumentation instr;// Set to currently active instrumentation running in process
-    boolean usingWrapper;       // Set to true when process was launched with a wrapper attached
+    private ActiveInstrumentation mInstr; // Set to currently active instrumentation running in
+                                          // process.
+    private boolean mUsingWrapper; // Set to true when process was launched with a wrapper attached
     final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
     long whenUnimportant;       // When (uptime) the process last became unimportant
     long lastCpuTime;           // How long proc has run CPU at last check
@@ -232,7 +233,7 @@
     private boolean mNotResponding; // does the app have a not responding dialog?
     Dialog anrDialog;           // dialog being displayed due to app not resp.
     boolean removed;            // has app package been removed from device?
-    boolean debugging;          // was app launched for debugging?
+    private boolean mDebugging; // was app launched for debugging?
     boolean waitedForDebugger;  // has process show wait for debugger dialog?
     Dialog waitDialog;          // current wait for debugger dialog
 
@@ -317,8 +318,8 @@
             pw.println("}");
         }
         pw.print(prefix); pw.print("compat="); pw.println(compat);
-        if (instr != null) {
-            pw.print(prefix); pw.print("instr="); pw.println(instr);
+        if (mInstr != null) {
+            pw.print(prefix); pw.print("mInstr="); pw.println(mInstr);
         }
         pw.print(prefix); pw.print("thread="); pw.println(thread);
         pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting=");
@@ -435,9 +436,9 @@
                     pw.print(" killedByAm="); pw.print(killedByAm);
                     pw.print(" waitingToKill="); pw.println(waitingToKill);
         }
-        if (debugging || mCrashing || crashDialog != null || mNotResponding
+        if (mDebugging || mCrashing || crashDialog != null || mNotResponding
                 || anrDialog != null || bad) {
-            pw.print(prefix); pw.print("debugging="); pw.print(debugging);
+            pw.print(prefix); pw.print("mDebugging="); pw.print(mDebugging);
                     pw.print(" mCrashing="); pw.print(mCrashing);
                     pw.print(" "); pw.print(crashDialog);
                     pw.print(" mNotResponding="); pw.print(mNotResponding);
@@ -975,6 +976,33 @@
         return mHasForegroundServices;
     }
 
+    void setDebugging(boolean debugging) {
+        mDebugging = debugging;
+        mWindowProcessController.setDebugging(debugging);
+    }
+
+    boolean isDebugging() {
+        return mDebugging;
+    }
+
+    void setUsingWrapper(boolean usingWrapper) {
+        mUsingWrapper = usingWrapper;
+        mWindowProcessController.setUsingWrapper(usingWrapper);
+    }
+
+    boolean isUsingWrapper() {
+        return mUsingWrapper;
+    }
+
+    void setActiveInstrumentation(ActiveInstrumentation instr) {
+        mInstr = instr;
+        mWindowProcessController.setInstrumenting(instr != null);
+    }
+
+    ActiveInstrumentation getActiveInstrumentation() {
+        return mInstr;
+    }
+
     @Override
     public void clearProfilerIfNeeded() {
         synchronized (mService) {
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 230810b..fb6b5c1 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -288,7 +288,7 @@
      * @return whether the home app is also the active handler of recent tasks.
      */
     boolean isRecentsComponentHomeActivity(int userId) {
-        final ComponentName defaultHomeActivity = mService.mAm.getPackageManagerInternalLocked()
+        final ComponentName defaultHomeActivity = mService.getPackageManagerInternalLocked()
                 .getDefaultHomeActivity(userId);
         return defaultHomeActivity != null && mRecentsComponent != null &&
                 defaultHomeActivity.getPackageName().equals(mRecentsComponent.getPackageName());
diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java
index d4c9bcb..e5551b5 100644
--- a/services/core/java/com/android/server/am/WindowProcessController.java
+++ b/services/core/java/com/android/server/am/WindowProcessController.java
@@ -93,6 +93,12 @@
     private volatile String mRequiredAbi;
     // Running any services that are foreground?
     private volatile boolean mHasForegroundServices;
+    // was app launched for debugging?
+    private volatile boolean mDebugging;
+    // Active instrumentation running in process?
+    private volatile boolean mInstrumenting;
+    // Set to true when process was launched with a wrapper attached
+    private volatile boolean mUsingWrapper;
 
     // Thread currently set for VR scheduling
     int mVrThreadTid;
@@ -189,6 +195,30 @@
         return mRequiredAbi;
     }
 
+    public void setDebugging(boolean debugging) {
+        mDebugging = debugging;
+    }
+
+    boolean isDebugging() {
+        return mDebugging;
+    }
+
+    public void setUsingWrapper(boolean usingWrapper) {
+        mUsingWrapper = usingWrapper;
+    }
+
+    boolean isUsingWrapper() {
+        return mUsingWrapper;
+    }
+
+    public void setInstrumenting(boolean instrumenting) {
+        mInstrumenting = instrumenting;
+    }
+
+    boolean isInstrumenting() {
+        return mInstrumenting;
+    }
+
     public void addPackage(String packageName) {
         synchronized (mAtm.mGlobalLock) {
             mPkgList.add(packageName);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index bfecd9d..7dd2dda 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -274,4 +274,8 @@
     public abstract void enableScreenAfterBoot(boolean booted);
     public abstract boolean showStrictModeViolationDialog();
     public abstract void showSystemReadyErrorDialogsIfNeeded();
+
+    public abstract long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason);
+    public abstract void onProcessMapped(int pid, WindowProcessController proc);
+    public abstract void onProcessUnMapped(int pid);
 }
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 016921d..b5e2f01 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -123,17 +123,14 @@
                 return appWindowToken.mInputDispatchingTimeoutNanos;
             }
         } else if (windowState != null) {
-            try {
-                // Notify the activity manager about the timeout and let it decide whether
-                // to abort dispatching or keep waiting.
-                long timeout = ActivityManager.getService().inputDispatchingTimedOut(
-                        windowState.mSession.mPid, aboveSystem, reason);
-                if (timeout >= 0) {
-                    // The activity manager declined to abort dispatching.
-                    // Wait a bit longer and timeout again later.
-                    return timeout * 1000000L; // nanoseconds
-                }
-            } catch (RemoteException ex) {
+            // Notify the activity manager about the timeout and let it decide whether
+            // to abort dispatching or keep waiting.
+            long timeout = mService.mAtmInternal.inputDispatchingTimedOut(
+                    windowState.mSession.mPid, aboveSystem, reason);
+            if (timeout >= 0) {
+                // The activity manager declined to abort dispatching.
+                // Wait a bit longer and timeout again later.
+                return timeout * 1000000L; // nanoseconds
             }
         }
         return 0; // abort dispatching