Moved more stuff from ActivityManagerService to ActivityTaskManagerService (9/n)

Moved more stuff related to activities out of the current service to the new one.

Test: Existing tests pass
Test: go/wm-smoke-auto
Bug: 80414790
Change-Id: I16863dd977bf09136cc23b0ab3aa197c613879ea
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index ca715b5..652bc6a 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -24,7 +24,6 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -32,6 +31,7 @@
 import java.util.Set;
 import java.util.function.Predicate;
 
+import android.app.ActivityManagerInternal;
 import android.app.ActivityThread;
 import android.app.AppOpsManager;
 import android.app.NotificationManager;
@@ -59,7 +59,6 @@
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.TransferPipe;
-import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.server.AppStateTracker;
@@ -1869,7 +1868,7 @@
                 + " type=" + resolvedType + " callingUid=" + callingUid);
 
         userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
-                ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
+                ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE, "service", null);
 
         ServiceMap smap = getServiceMapLocked(userId);
         final ComponentName comp = service.getComponent();
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index ee93fc8..5608f97 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -300,7 +300,7 @@
             }
         }
 
-        final ActivityManagerService service = mSupervisor.mService.mAm;
+        final ActivityTaskManagerService service = mSupervisor.mService;
         if (!isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow,
                 service.mSupportsSplitScreenMultiWindow, service.mSupportsFreeformWindowManagement,
                 service.mSupportsPictureInPicture, activityType)) {
@@ -536,7 +536,7 @@
         }
 
         // Make sure the windowing mode we are trying to use makes sense for what is supported.
-        final ActivityManagerService service = mSupervisor.mService.mAm;
+        final ActivityTaskManagerService service = mSupervisor.mService;
         boolean supportsMultiWindow = service.mSupportsMultiWindow;
         boolean supportsSplitScreen = service.mSupportsSplitScreenMultiWindow;
         boolean supportsFreeform = service.mSupportsFreeformWindowManagement;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 37253ec..1c61f30 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22,11 +22,10 @@
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.REMOVE_TASKS;
-import static android.Manifest.permission.STOP_APP_SWITCHES;
+import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
 import static android.app.AppOpsManager.OP_NONE;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
@@ -120,7 +119,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-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_LRU;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
@@ -134,9 +132,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
-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;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_URI_PERMISSION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
@@ -169,10 +165,6 @@
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
 import static com.android.server.am.MemoryStatUtil.hasMemcg;
-import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_NONE;
-import static android.view.WindowManager.TRANSIT_TASK_OPEN;
-import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
@@ -187,6 +179,7 @@
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityTaskManagerInternal;
 import android.app.ActivityTaskManagerInternal.ScreenObserver;
 import android.app.ActivityTaskManagerInternal.SleepToken;
 import android.app.ActivityManagerProto;
@@ -307,7 +300,6 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.TransactionTooLargeException;
-import android.os.UpdateLock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.WorkSource;
@@ -471,8 +463,6 @@
     private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
     private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
-    private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
-    private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
     private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
     private static final String TAG_LRU = TAG + POSTFIX_LRU;
     private static final String TAG_MU = TAG + POSTFIX_MU;
@@ -483,13 +473,10 @@
     private static final String TAG_PROCESSES = TAG + POSTFIX_PROCESSES;
     private static final String TAG_PROVIDER = TAG + POSTFIX_PROVIDER;
     private static final String TAG_PSS = TAG + POSTFIX_PSS;
-    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
     private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
-    private static final String TAG_STACK = TAG + POSTFIX_STACK;
     private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
     private static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS;
     private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION;
-    private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
 
     // Mock "pretend we're idle now" broadcast action to the job scheduler; declared
     // here so that while the job scheduler can depend on AMS, the other way around
@@ -514,10 +501,6 @@
     // Maximum number of receivers an app can register.
     private static final int MAX_RECEIVERS_ALLOWED_PER_APP = 1000;
 
-    // Amount of time after a call to stopAppSwitches() during which we will
-    // prevent further untrusted switches from happening.
-    static final long APP_SWITCH_DELAY_TIME = 5*1000;
-
     // How long we wait for a launched process to attach to the activity manager
     // before we decide it's never going to come up for real.
     static final int PROC_START_TIMEOUT = 10*1000;
@@ -561,11 +544,6 @@
     /** If a UID observer takes more than this long, send a WTF. */
     private static final int SLOW_UID_OBSERVER_THRESHOLD_MS = 20;
 
-    // Access modes for handleIncomingUser.
-    static final int ALLOW_NON_FULL = 0;
-    static final int ALLOW_NON_FULL_IN_PROFILE = 1;
-    static final int ALLOW_FULL_ONLY = 2;
-
     // Necessary ApplicationInfo flags to mark an app as persistent
     private static final int PERSISTENT_MASK =
             ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
@@ -577,9 +555,6 @@
     // Used to indicate that an app transition should be animated.
     static final boolean ANIMATE = true;
 
-    // Determines whether to take full screen screenshots
-    static final boolean TAKE_FULLSCREEN_SCREENSHOTS = true;
-
     /**
      * Default value for {@link Settings.Global#NETWORK_ACCESS_TIMEOUT_MS}.
      */
@@ -628,9 +603,6 @@
     // devices.
     private boolean mShowDialogs = true;
 
-    // VR Vr2d Display Id.
-    int mVr2dDisplayId = INVALID_DISPLAY;
-
     // Whether we should use SCHED_FIFO for UI and RenderThreads.
     private boolean mUseFifoUiScheduling = false;
 
@@ -679,12 +651,6 @@
 
     final UserController mUserController;
 
-    /**
-     * Packages that are being allowed to perform unrestricted app switches.  Mapping is
-     * User -> Type -> uid.
-     */
-    final SparseArray<ArrayMap<String, Integer>> mAllowAppSwitchUids = new SparseArray<>();
-
     final AppErrors mAppErrors;
 
     final AppWarnings mAppWarnings;
@@ -1329,18 +1295,6 @@
     final Context mUiContext;
 
     /**
-     * The time at which we will allow normal application switches again,
-     * after a call to {@link #stopAppSwitches()}.
-     */
-    long mAppSwitchesAllowedTime;
-
-    /**
-     * This is set to true after the first switch after mAppSwitchesAllowedTime
-     * is set; any switches after that will clear the time.
-     */
-    boolean mDidAppSwitch;
-
-    /**
      * Last time (in uptime) at which we checked for power usage.
      */
     long mLastPowerCheckUptime;
@@ -1491,29 +1445,7 @@
     String mOrigDebugApp = null;
     boolean mOrigWaitForDebugger = false;
     boolean mAlwaysFinishActivities = false;
-    boolean mForceResizableActivities;
-    /**
-     * Flag that indicates if multi-window is enabled.
-     *
-     * For any particular form of multi-window to be enabled, generic multi-window must be enabled
-     * in {@link com.android.internal.R.bool#config_supportsMultiWindow} config or
-     * {@link Settings.Global#DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES} development option set.
-     * At least one of the forms of multi-window must be enabled in order for this flag to be
-     * initialized to 'true'.
-     *
-     * @see #mSupportsSplitScreenMultiWindow
-     * @see #mSupportsFreeformWindowManagement
-     * @see #mSupportsPictureInPicture
-     * @see #mSupportsMultiDisplay
-     */
-    boolean mSupportsMultiWindow;
-    boolean mSupportsSplitScreenMultiWindow;
-    boolean mSupportsFreeformWindowManagement;
-    boolean mSupportsPictureInPicture;
-    boolean mSupportsMultiDisplay;
-    boolean mSupportsLeanbackOnly;
-    IActivityController mController = null;
-    boolean mControllerIsAMonkey = false;
+
     String mProfileApp = null;
     ProcessRecord mProfileProc = null;
     ProfilerInfo mProfilerInfo = null;
@@ -1637,8 +1569,6 @@
         }
     }
 
-    final List<ScreenObserver> mScreenObservers = new ArrayList<>();
-
     final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>();
     ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5];
 
@@ -1680,12 +1610,6 @@
     long mLastWriteTime = 0;
 
     /**
-     * Used to retain an update lock when the foreground activity is in
-     * immersive mode.
-     */
-    final UpdateLock mUpdateLock = new UpdateLock("immersive");
-
-    /**
      * Set to true after the system has finished booting.
      */
     boolean mBooted = false;
@@ -1697,6 +1621,7 @@
 
     WindowManagerService mWindowManager;
     ActivityTaskManagerService mActivityTaskManager;
+    ActivityTaskManagerInternal mAtmInternal;
     final ActivityThread mSystemThread;
 
     private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -1748,7 +1673,6 @@
     static final int DISPATCH_PROCESSES_CHANGED_UI_MSG = 31;
     static final int DISPATCH_PROCESS_DIED_UI_MSG = 32;
     static final int REPORT_MEM_USAGE_MSG = 33;
-    static final int IMMERSIVE_MODE_LOCK_MSG = 37;
     static final int PERSIST_URI_GRANTS_MSG = 38;
     static final int UPDATE_TIME_PREFERENCE_MSG = 41;
     static final int FINISH_BOOTING_MSG = 45;
@@ -1763,8 +1687,6 @@
     static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 57;
     static final int IDLE_UIDS_MSG = 58;
     static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 63;
-    static final int DISPATCH_SCREEN_AWAKE_MSG = 64;
-    static final int DISPATCH_SCREEN_KEYGUARD_MSG = 65;
     static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66;
     static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67;
     static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
@@ -1790,11 +1712,6 @@
      */
     private boolean mUserIsMonkey;
 
-    /** The dimensions of the thumbnails in the Recents UI. */
-    int mThumbnailWidth;
-    int mThumbnailHeight;
-    float mFullscreenThumbnailScale;
-
     final ServiceThread mHandlerThread;
     final MainHandler mHandler;
     final Handler mUiHandler;
@@ -2201,20 +2118,6 @@
                 thread.start();
                 break;
             }
-            case IMMERSIVE_MODE_LOCK_MSG: {
-                final boolean nextState = (msg.arg1 != 0);
-                if (mUpdateLock.isHeld() != nextState) {
-                    if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE,
-                            "Applying new update lock state '" + nextState
-                            + "' for " + (ActivityRecord)msg.obj);
-                    if (nextState) {
-                        mUpdateLock.acquire();
-                    } else {
-                        mUpdateLock.release();
-                    }
-                }
-                break;
-            }
             case PERSIST_URI_GRANTS_MSG: {
                 writeGrantedUriPermissions();
                 break;
@@ -2382,18 +2285,6 @@
             case IDLE_UIDS_MSG: {
                 idleUids();
             } break;
-            case DISPATCH_SCREEN_AWAKE_MSG: {
-                final boolean isAwake = msg.arg1 != 0;
-                for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
-                    mScreenObservers.get(i).onAwakeStateChanged(isAwake);
-                }
-            } break;
-            case DISPATCH_SCREEN_KEYGUARD_MSG: {
-                final boolean isShowing = msg.arg1 != 0;
-                for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
-                    mScreenObservers.get(i).onKeyguardStateChanged(isShowing);
-                }
-            } break;
             case HANDLE_TRUST_STORAGE_UPDATE_MSG: {
                 synchronized (ActivityManagerService.this) {
                     for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
@@ -2588,6 +2479,7 @@
         synchronized (this) {
             mActivityTaskManager = atm;
             mActivityTaskManager.setActivityManagerService(this);
+            mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
             mStackSupervisor = mActivityTaskManager.mStackSupervisor;
         }
     }
@@ -3011,11 +2903,6 @@
         }
     }
 
-    void onUserStoppedLocked(int userId) {
-        mActivityTaskManager.getRecentTasks().unloadUserDataFromMemoryLocked(userId);
-        mAllowAppSwitchUids.remove(userId);
-    }
-
     public void initPowerManagement() {
         mStackSupervisor.initPowerManagement();
         mBatteryStatsService.initPowerManagement();
@@ -3338,7 +3225,7 @@
 
         mWindowManager.setFocusedApp(r.appToken, true);
 
-        applyUpdateLockStateLocked(r);
+        mActivityTaskManager.applyUpdateLockStateLocked(r);
         mActivityTaskManager.applyUpdateVrModeLocked(r);
 
         EventLogTags.writeAmSetResumedActivity(
@@ -3382,16 +3269,6 @@
         mActivityTaskManager.unregisterTaskStackListener(listener);
     }
 
-    final void applyUpdateLockStateLocked(ActivityRecord r) {
-        // Modifications to the UpdateLock state are done on our handler, outside
-        // the activity manager's locks.  The new state is determined based on the
-        // state *now* of the relevant activity record.  The object is passed to
-        // the handler solely for logging detail, not to be consulted/modified.
-        final boolean nextState = r != null && r.immersive;
-        mHandler.sendMessage(
-                mHandler.obtainMessage(IMMERSIVE_MODE_LOCK_MSG, (nextState) ? 1 : 0, 0, r));
-    }
-
     final void showAskCompatModeDialogLocked(ActivityRecord r) {
         Message msg = Message.obtain();
         msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG;
@@ -4416,7 +4293,7 @@
         return mCompatModePackages.compatibilityInfoForPackageLocked(ai);
     }
 
-    void enforceNotIsolatedCaller(String caller) {
+    private void enforceNotIsolatedCaller(String caller) {
         if (UserHandle.isIsolated(Binder.getCallingUid())) {
             throw new SecurityException("Isolated process not allowed to call " + caller);
         }
@@ -5651,7 +5528,7 @@
      * @param maxProcState the process state at or below which to preserve
      *                     processes, or {@code -1} to ignore the process state
      */
-    private void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState) {
+    void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState) {
         if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
                 != PackageManager.PERMISSION_GRANTED) {
             final String msg = "Permission Denial: killAllBackgroundProcessesExcept() from pid="
@@ -7612,7 +7489,7 @@
         }
     }
 
-    int checkComponentPermission(String permission, int pid, int uid,
+    static int checkComponentPermission(String permission, int pid, int uid,
             int owningUid, boolean exported) {
         if (pid == MY_PID) {
             return PackageManager.PERMISSION_GRANTED;
@@ -7700,15 +7577,6 @@
     }
 
     /**
-     * This can be called with or without the global lock held.
-     */
-    void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
-        if (!mActivityTaskManager.getRecentTasks().isCallerRecents(Binder.getCallingUid())) {
-            enforceCallingPermission(permission, func);
-        }
-    }
-
-    /**
      * Determine if UID is holding permissions required to access {@link Uri} in
      * the given {@link ProviderInfo}. Final permission checking is always done
      * in {@link ContentProvider}.
@@ -9165,38 +9033,6 @@
         mActivityTaskManager.cancelTaskWindowTransition(taskId);
     }
 
-    boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
-        if (mActivityTaskManager.getRecentTasks().isCallerRecents(callingUid)) {
-            // Always allow the recents component to get tasks
-            return true;
-        }
-
-        boolean allowed = checkPermission(android.Manifest.permission.REAL_GET_TASKS,
-                callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
-        if (!allowed) {
-            if (checkPermission(android.Manifest.permission.GET_TASKS,
-                    callingPid, callingUid) == PackageManager.PERMISSION_GRANTED) {
-                // Temporary compatibility: some existing apps on the system image may
-                // still be requesting the old permission and not switched to the new
-                // one; if so, we'll still allow them full access.  This means we need
-                // to see if they are holding the old permission and are a system app.
-                try {
-                    if (AppGlobals.getPackageManager().isUidPrivileged(callingUid)) {
-                        allowed = true;
-                        if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
-                                + " is using old GET_TASKS but privileged; allowing");
-                    }
-                } catch (RemoteException e) {
-                }
-            }
-        }
-        if (!allowed) {
-            if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
-                    + " does not hold REAL_GET_TASKS; limiting output");
-        }
-        return allowed;
-    }
-
     @Override
     public void setTaskResizeable(int taskId, int resizeableMode) {
         mActivityTaskManager.setTaskResizeable(taskId, resizeableMode);
@@ -10813,8 +10649,7 @@
                 // Also update state in a special way for running foreground services UI.
                 mServices.updateScreenStateLocked(isAwake);
                 reportCurWakefulnessUsageEventLocked();
-                mHandler.obtainMessage(DISPATCH_SCREEN_AWAKE_MSG, isAwake ? 1 : 0, 0)
-                        .sendToTarget();
+                mActivityTaskManager.onScreenAwakeChanged(isAwake);
             }
             updateOomAdjLocked();
         }
@@ -10978,69 +10813,12 @@
 
     @Override
     public void stopAppSwitches() {
-        enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "stopAppSwitches");
-        synchronized(this) {
-            mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
-                    + APP_SWITCH_DELAY_TIME;
-            mDidAppSwitch = false;
-            mActivityTaskManager.getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME);
-        }
+        mActivityTaskManager.stopAppSwitches();
     }
 
+    @Override
     public void resumeAppSwitches() {
-        enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "resumeAppSwitches");
-        synchronized(this) {
-            // Note that we don't execute any pending app switches... we will
-            // let those wait until either the timeout, or the next start
-            // activity request.
-            mAppSwitchesAllowedTime = 0;
-        }
-    }
-
-    boolean checkAllowAppSwitchUid(int uid) {
-        ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(UserHandle.getUserId(uid));
-        if (types != null) {
-            for (int i = types.size() - 1; i >= 0; i--) {
-                if (types.valueAt(i).intValue() == uid) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
-            int callingPid, int callingUid, String name) {
-        if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
-            return true;
-        }
-
-        if (mActivityTaskManager.getRecentTasks().isCallerRecents(sourceUid)) {
-            return true;
-        }
-
-        int perm = checkComponentPermission(STOP_APP_SWITCHES, sourcePid, sourceUid, -1, true);
-        if (perm == PackageManager.PERMISSION_GRANTED) {
-            return true;
-        }
-        if (checkAllowAppSwitchUid(sourceUid)) {
-            return true;
-        }
-
-        // If the actual IPC caller is different from the logical source, then
-        // also see if they are allowed to control app switches.
-        if (callingUid != -1 && callingUid != sourceUid) {
-            perm = checkComponentPermission(STOP_APP_SWITCHES, callingPid, callingUid, -1, true);
-            if (perm == PackageManager.PERMISSION_GRANTED) {
-                return true;
-            }
-            if (checkAllowAppSwitchUid(callingUid)) {
-                return true;
-            }
-        }
-
-        Slog.w(TAG, name + " request from " + sourceUid + " stopped");
-        return false;
+        mActivityTaskManager.resumeAppSwitches();
     }
 
     public void setDebugApp(String packageName, boolean waitForDebugger,
@@ -11194,13 +10972,7 @@
 
     @Override
     public void setActivityController(IActivityController controller, boolean imAMonkey) {
-        enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
-                "setActivityController()");
-        synchronized (this) {
-            mController = controller;
-            mControllerIsAMonkey = imAMonkey;
-            Watchdog.getInstance().setActivityController(controller);
-        }
+        mActivityTaskManager.setActivityController(controller, imAMonkey);
     }
 
     @Override
@@ -11225,7 +10997,7 @@
     public boolean isUserAMonkey() {
         synchronized (this) {
             // If there is a controller also implies the user is a monkey.
-            return (mUserIsMonkey || (mController != null && mControllerIsAMonkey));
+            return mUserIsMonkey || mActivityTaskManager.isControllerAMonkey();
         }
     }
 
@@ -11532,17 +11304,6 @@
         return false;
     }
 
-    /**
-     * Check that we have the features required for VR-related API calls, and throw an exception if
-     * not.
-     */
-    void enforceSystemHasVrFeature() {
-        if (!mContext.getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
-            throw new UnsupportedOperationException("VR mode not supported on this device!");
-        }
-    }
-
     @Override
     public void setRenderThread(int tid) {
         synchronized (this) {
@@ -11597,7 +11358,7 @@
 
     @Override
     public boolean isVrModePackageEnabled(ComponentName packageName) {
-        enforceSystemHasVrFeature();
+        mActivityTaskManager.enforceSystemHasVrFeature();
 
         final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
 
@@ -12070,78 +11831,22 @@
 
     private void retrieveSettings() {
         final ContentResolver resolver = mContext.getContentResolver();
-        final boolean freeformWindowManagement =
-                mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
-                        || Settings.Global.getInt(
-                                resolver, DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
+        mActivityTaskManager.retrieveSettings(resolver);
 
-        final boolean supportsMultiWindow = ActivityTaskManager.supportsMultiWindow(mContext);
-        final boolean supportsPictureInPicture = supportsMultiWindow &&
-                mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
-        final boolean supportsSplitScreenMultiWindow =
-                ActivityTaskManager.supportsSplitScreenMultiWindow(mContext);
-        final boolean supportsMultiDisplay = mContext.getPackageManager()
-                .hasSystemFeature(FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS);
         final String debugApp = Settings.Global.getString(resolver, DEBUG_APP);
         final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
         final boolean alwaysFinishActivities =
                 Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
-        final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
-        final boolean forceResizable = Settings.Global.getInt(
-                resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
         final long waitForNetworkTimeoutMs = Settings.Global.getLong(resolver,
                 NETWORK_ACCESS_TIMEOUT_MS, NETWORK_ACCESS_TIMEOUT_DEFAULT_MS);
-        final boolean supportsLeanbackOnly =
-                mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK_ONLY);
         mHiddenApiBlacklist.registerObserver();
 
-        // Transfer any global setting for forcing RTL layout, into a System Property
-        SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
-
-        final Configuration configuration = new Configuration();
-        Settings.System.getConfiguration(resolver, configuration);
-        if (forceRtl) {
-            // This will take care of setting the correct layout direction flags
-            configuration.setLayoutDirection(configuration.locale);
-        }
-
         synchronized (this) {
             mDebugApp = mOrigDebugApp = debugApp;
             mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
             mAlwaysFinishActivities = alwaysFinishActivities;
-            mSupportsLeanbackOnly = supportsLeanbackOnly;
-            mForceResizableActivities = forceResizable;
-            final boolean multiWindowFormEnabled = freeformWindowManagement
-                    || supportsSplitScreenMultiWindow
-                    || supportsPictureInPicture
-                    || supportsMultiDisplay;
-            if ((supportsMultiWindow || forceResizable) && multiWindowFormEnabled) {
-                mSupportsMultiWindow = true;
-                mSupportsFreeformWindowManagement = freeformWindowManagement;
-                mSupportsSplitScreenMultiWindow = supportsSplitScreenMultiWindow;
-                mSupportsPictureInPicture = supportsPictureInPicture;
-                mSupportsMultiDisplay = supportsMultiDisplay;
-            } else {
-                mSupportsMultiWindow = false;
-                mSupportsFreeformWindowManagement = false;
-                mSupportsSplitScreenMultiWindow = false;
-                mSupportsPictureInPicture = false;
-                mSupportsMultiDisplay = false;
-            }
-            mWindowManager.setForceResizableTasks(mForceResizableActivities);
-            mWindowManager.setSupportsPictureInPicture(mSupportsPictureInPicture);
-            // This happens before any activities are started, so we can change global configuration
-            // in-place.
-            updateConfigurationLocked(configuration, null, true);
-            final Configuration globalConfig = getGlobalConfiguration();
-            if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Initial config: " + globalConfig);
-
             // Load resources only after the current configuration has been set.
             final Resources res = mContext.getResources();
-            mThumbnailWidth = res.getDimensionPixelSize(
-                    com.android.internal.R.dimen.thumbnail_width);
-            mThumbnailHeight = res.getDimensionPixelSize(
-                    com.android.internal.R.dimen.thumbnail_height);
             mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString(
                     com.android.internal.R.string.config_appsNotReportingCrashes));
             mUserController.mUserSwitchUiEnabled = !res.getBoolean(
@@ -12149,14 +11854,6 @@
             mUserController.mMaxRunningUsers = res.getInteger(
                     com.android.internal.R.integer.config_multiuserMaxRunningUsers);
 
-            if ((globalConfig.uiMode & UI_MODE_TYPE_TELEVISION) == UI_MODE_TYPE_TELEVISION) {
-                mFullscreenThumbnailScale = (float) res
-                    .getInteger(com.android.internal.R.integer.thumbnail_width_tv) /
-                    (float) globalConfig.screenWidthDp;
-            } else {
-                mFullscreenThumbnailScale = res.getFraction(
-                    com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
-            }
             mWaitForNetworkTimeoutMs = waitForNetworkTimeoutMs;
         }
     }
@@ -12937,7 +12634,7 @@
         final boolean allUsers = ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL,
                 callingUid) == PackageManager.PERMISSION_GRANTED;
         final int userId = UserHandle.getUserId(callingUid);
-        final boolean allUids = isGetTasksAllowed(
+        final boolean allUids = mAtmInternal.isGetTasksAllowed(
                 "getRunningAppProcesses", Binder.getCallingPid(), callingUid);
 
         synchronized (this) {
@@ -13965,7 +13662,7 @@
         }
         if (dumpAll) {
             if (dumpPackage == null) {
-                pw.println("  mConfigWillChange: " + getFocusedStack().mConfigWillChange);
+                pw.println("  mConfigWillChange: " + mActivityTaskManager.getFocusedStack().mConfigWillChange);
             }
             if (mCompatModePackages.getPackages().size() > 0) {
                 boolean printed = false;
@@ -14130,10 +13827,10 @@
                 pw.println("  mNativeDebuggingApp=" + mNativeDebuggingApp);
             }
         }
-        if (mAllowAppSwitchUids.size() > 0) {
+        if (mActivityTaskManager.mAllowAppSwitchUids.size() > 0) {
             boolean printed = false;
-            for (int i = 0; i < mAllowAppSwitchUids.size(); i++) {
-                ArrayMap<String, Integer> types = mAllowAppSwitchUids.valueAt(i);
+            for (int i = 0; i < mActivityTaskManager.mAllowAppSwitchUids.size(); i++) {
+                ArrayMap<String, Integer> types = mActivityTaskManager.mAllowAppSwitchUids.valueAt(i);
                 for (int j = 0; j < types.size(); j++) {
                     if (dumpPackage == null ||
                             UserHandle.getAppId(types.valueAt(j).intValue()) == dumpAppId) {
@@ -14146,7 +13843,7 @@
                             printed = true;
                         }
                         pw.print("    User ");
-                        pw.print(mAllowAppSwitchUids.keyAt(i));
+                        pw.print(mActivityTaskManager.mAllowAppSwitchUids.keyAt(i));
                         pw.print(": Type ");
                         pw.print(types.keyAt(j));
                         pw.print(" = ");
@@ -14160,9 +13857,9 @@
             if (mAlwaysFinishActivities) {
                 pw.println("  mAlwaysFinishActivities=" + mAlwaysFinishActivities);
             }
-            if (mController != null) {
-                pw.println("  mController=" + mController
-                        + " mControllerIsAMonkey=" + mControllerIsAMonkey);
+            if (mActivityTaskManager.mController != null) {
+                pw.println("  mController=" + mActivityTaskManager.mController
+                        + " mControllerIsAMonkey=" + mActivityTaskManager.mControllerIsAMonkey);
             }
             if (dumpAll) {
                 pw.println("  Total persistent processes: " + numPers);
@@ -14343,7 +14040,7 @@
         if (dumpPackage == null) {
             mUserController.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.USER_CONTROLLER);
             getGlobalConfiguration().writeToProto(proto, ActivityManagerServiceDumpProcessesProto.GLOBAL_CONFIGURATION);
-            proto.write(ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE, getFocusedStack().mConfigWillChange);
+            proto.write(ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE, mActivityTaskManager.getFocusedStack().mConfigWillChange);
         }
 
         if (mHomeProcess != null && (dumpPackage == null
@@ -14493,10 +14190,10 @@
 
         if (dumpPackage == null) {
             proto.write(ActivityManagerServiceDumpProcessesProto.ALWAYS_FINISH_ACTIVITIES, mAlwaysFinishActivities);
-            if (mController != null) {
+            if (mActivityTaskManager.mController != null) {
                 final long token = proto.start(ActivityManagerServiceDumpProcessesProto.CONTROLLER);
-                proto.write(ActivityManagerServiceDumpProcessesProto.Controller.CONTROLLER, mController.toString());
-                proto.write(ActivityManagerServiceDumpProcessesProto.Controller.IS_A_MONKEY, mControllerIsAMonkey);
+                proto.write(ActivityManagerServiceDumpProcessesProto.Controller.CONTROLLER, mActivityTaskManager.mController.toString());
+                proto.write(ActivityManagerServiceDumpProcessesProto.Controller.IS_A_MONKEY, mActivityTaskManager.mControllerIsAMonkey);
                 proto.end(token);
             }
             proto.write(ActivityManagerServiceDumpProcessesProto.TOTAL_PERSISTENT_PROCS, numPers);
@@ -17363,8 +17060,8 @@
         final int callingUid = Binder.getCallingUid();
         final boolean canInteractAcrossUsers = (ActivityManager.checkUidPermission(
             INTERACT_ACROSS_USERS_FULL, callingUid) == PERMISSION_GRANTED);
-        final boolean allowed = isGetTasksAllowed("getServices", Binder.getCallingPid(),
-            callingUid);
+        final boolean allowed = mAtmInternal.isGetTasksAllowed("getServices",
+                Binder.getCallingPid(), callingUid);
         synchronized (this) {
             return mServices.getRunningServiceInfoLocked(maxNum, flags, callingUid,
                 allowed, canInteractAcrossUsers);
@@ -19336,10 +19033,6 @@
         return config;
     }
 
-    ActivityStack getFocusedStack() {
-        return mStackSupervisor.getFocusedStack();
-    }
-
     @Override
     public StackInfo getFocusedStackInfo() throws RemoteException {
         return mActivityTaskManager.getFocusedStackInfo();
@@ -19369,18 +19062,7 @@
 
         int userId = UserHandle.getCallingUserId();
 
-        synchronized(this) {
-            updatePersistentConfigurationLocked(values, userId);
-        }
-    }
-
-    private void updatePersistentConfigurationLocked(Configuration values, @UserIdInt int userId) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            updateConfigurationLocked(values, null, false, true, userId, false /* deferResume */);
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
+        mActivityTaskManager.updatePersistentConfiguration(values, userId);
     }
 
     private void updateFontScaleIfNeeded(@UserIdInt int userId) {
@@ -19395,7 +19077,7 @@
             final Configuration configuration
                     = mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY);
             configuration.fontScale = scaleFactor;
-            updatePersistentConfigurationLocked(configuration, userId);
+            mActivityTaskManager.updatePersistentConfiguration(configuration, userId);
         }
     }
 
@@ -19423,356 +19105,6 @@
         return mActivityTaskManager.updateConfiguration(values);
     }
 
-    void updateUserConfigurationLocked() {
-        final Configuration configuration = new Configuration(getGlobalConfiguration());
-        final int currentUserId = mUserController.getCurrentUserId();
-        Settings.System.adjustConfigurationForUser(mContext.getContentResolver(), configuration,
-                currentUserId, Settings.System.canWrite(mContext));
-        updateConfigurationLocked(configuration, null /* starting */, false /* initLocale */,
-                false /* persistent */, currentUserId, false /* deferResume */);
-    }
-
-    boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
-            boolean initLocale) {
-        return updateConfigurationLocked(values, starting, initLocale, false /* deferResume */);
-    }
-
-    boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
-            boolean initLocale, boolean deferResume) {
-        // pass UserHandle.USER_NULL as userId because we don't persist configuration for any user
-        return updateConfigurationLocked(values, starting, initLocale, false /* persistent */,
-                UserHandle.USER_NULL, deferResume);
-    }
-
-    // To cache the list of supported system locales
-    private String[] mSupportedSystemLocales = null;
-
-    private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
-            boolean initLocale, boolean persistent, int userId, boolean deferResume) {
-        return updateConfigurationLocked(values, starting, initLocale, persistent, userId,
-                deferResume, null /* result */);
-    }
-
-    /**
-     * Do either or both things: (1) change the current configuration, and (2)
-     * make sure the given activity is running with the (now) current
-     * configuration.  Returns true if the activity has been left running, or
-     * false if <var>starting</var> is being destroyed to match the new
-     * configuration.
-     *
-     * @param userId is only used when persistent parameter is set to true to persist configuration
-     *               for that particular user
-     */
-    boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
-            boolean initLocale, boolean persistent, int userId, boolean deferResume,
-            ActivityTaskManagerService.UpdateConfigurationResult result) {
-        int changes = 0;
-        boolean kept = true;
-
-        if (mWindowManager != null) {
-            mWindowManager.deferSurfaceLayout();
-        }
-        try {
-            if (values != null) {
-                changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId,
-                        deferResume);
-            }
-
-            kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
-        } finally {
-            if (mWindowManager != null) {
-                mWindowManager.continueSurfaceLayout();
-            }
-        }
-
-        if (result != null) {
-            result.changes = changes;
-            result.activityRelaunched = !kept;
-        }
-        return kept;
-    }
-
-    /**
-     * Returns true if this configuration change is interesting enough to send an
-     * {@link Intent#ACTION_SPLIT_CONFIGURATION_CHANGED} broadcast.
-     */
-    private static boolean isSplitConfigurationChange(int configDiff) {
-        return (configDiff & (ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_DENSITY)) != 0;
-    }
-
-    /** Update default (global) configuration and notify listeners about changes. */
-    private int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
-            boolean persistent, int userId, boolean deferResume) {
-        mActivityTaskManager.mTempConfig.setTo(getGlobalConfiguration());
-        final int changes = mActivityTaskManager.mTempConfig.updateFrom(values);
-        if (changes == 0) {
-            // Since calling to Activity.setRequestedOrientation leads to freezing the window with
-            // setting WindowManagerService.mWaitingForConfig to true, it is important that we call
-            // performDisplayOverrideConfigUpdate in order to send the new display configuration
-            // (even if there are no actual changes) to unfreeze the window.
-            performDisplayOverrideConfigUpdate(values, deferResume, DEFAULT_DISPLAY);
-            return 0;
-        }
-
-        if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
-                "Updating global configuration to: " + values);
-
-        EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
-        StatsLog.write(StatsLog.RESOURCE_CONFIGURATION_CHANGED,
-                values.colorMode,
-                values.densityDpi,
-                values.fontScale,
-                values.hardKeyboardHidden,
-                values.keyboard,
-                values.keyboardHidden,
-                values.mcc,
-                values.mnc,
-                values.navigation,
-                values.navigationHidden,
-                values.orientation,
-                values.screenHeightDp,
-                values.screenLayout,
-                values.screenWidthDp,
-                values.smallestScreenWidthDp,
-                values.touchscreen,
-                values.uiMode);
-
-
-        if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
-            final LocaleList locales = values.getLocales();
-            int bestLocaleIndex = 0;
-            if (locales.size() > 1) {
-                if (mSupportedSystemLocales == null) {
-                    mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
-                }
-                bestLocaleIndex = Math.max(0, locales.getFirstMatchIndex(mSupportedSystemLocales));
-            }
-            SystemProperties.set("persist.sys.locale",
-                    locales.get(bestLocaleIndex).toLanguageTag());
-            LocaleList.setDefault(locales, bestLocaleIndex);
-            mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
-                    locales.get(bestLocaleIndex)));
-        }
-
-        mActivityTaskManager.mConfigurationSeq = Math.max(++mActivityTaskManager.mConfigurationSeq, 1);
-        mActivityTaskManager.mTempConfig.seq = mActivityTaskManager.mConfigurationSeq;
-
-        // Update stored global config and notify everyone about the change.
-        mStackSupervisor.onConfigurationChanged(mActivityTaskManager.mTempConfig);
-
-        Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mActivityTaskManager.mTempConfig);
-        // TODO(multi-display): Update UsageEvents#Event to include displayId.
-        mUsageStatsService.reportConfigurationChange(mActivityTaskManager.mTempConfig,
-                mUserController.getCurrentUserId());
-
-        // TODO: If our config changes, should we auto dismiss any currently showing dialogs?
-        updateShouldShowDialogsLocked(mActivityTaskManager.mTempConfig);
-
-        AttributeCache ac = AttributeCache.instance();
-        if (ac != null) {
-            ac.updateConfiguration(mActivityTaskManager.mTempConfig);
-        }
-
-        // Make sure all resources in our process are updated right now, so that anyone who is going
-        // to retrieve resource values after we return will be sure to get the new ones. This is
-        // especially important during boot, where the first config change needs to guarantee all
-        // resources have that config before following boot code is executed.
-        mSystemThread.applyConfigurationToResources(mActivityTaskManager.mTempConfig);
-
-        // We need another copy of global config because we're scheduling some calls instead of
-        // running them in place. We need to be sure that object we send will be handled unchanged.
-        final Configuration configCopy = new Configuration(mActivityTaskManager.mTempConfig);
-        if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
-            Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
-            msg.obj = configCopy;
-            msg.arg1 = userId;
-            mHandler.sendMessage(msg);
-        }
-
-        for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
-            ProcessRecord app = mLruProcesses.get(i);
-            try {
-                if (app.thread != null) {
-                    if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
-                            + app.processName + " new config " + configCopy);
-                    mActivityTaskManager.getLifecycleManager().scheduleTransaction(app.thread,
-                            ConfigurationChangeItem.obtain(configCopy));
-                }
-            } catch (Exception e) {
-                Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);
-            }
-        }
-
-        Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_REPLACE_PENDING
-                | Intent.FLAG_RECEIVER_FOREGROUND
-                | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
-        broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
-                OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
-                UserHandle.USER_ALL);
-        if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
-            intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
-            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
-                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
-                    | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
-            if (initLocale || !mProcessesReady) {
-                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-            }
-            broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
-                    OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
-                    UserHandle.USER_ALL);
-        }
-
-        // Send a broadcast to PackageInstallers if the configuration change is interesting
-        // for the purposes of installing additional splits.
-        if (!initLocale && isSplitConfigurationChange(changes)) {
-            intent = new Intent(Intent.ACTION_SPLIT_CONFIGURATION_CHANGED);
-            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
-                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-
-            // Typically only app stores will have this permission.
-            String[] permissions = new String[] { android.Manifest.permission.INSTALL_PACKAGES };
-            broadcastIntentLocked(null, null, intent, null, null, 0, null, null, permissions,
-                    OP_NONE, null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
-        }
-
-        // Override configuration of the default display duplicates global config, so we need to
-        // update it also. This will also notify WindowManager about changes.
-        performDisplayOverrideConfigUpdate(mStackSupervisor.getConfiguration(), deferResume,
-                DEFAULT_DISPLAY);
-
-        return changes;
-    }
-
-    boolean updateDisplayOverrideConfigurationLocked(Configuration values, ActivityRecord starting,
-            boolean deferResume, int displayId) {
-        return updateDisplayOverrideConfigurationLocked(values, starting, deferResume /* deferResume */,
-                displayId, null /* result */);
-    }
-
-    /**
-     * Updates override configuration specific for the selected display. If no config is provided,
-     * new one will be computed in WM based on current display info.
-     */
-    boolean updateDisplayOverrideConfigurationLocked(Configuration values,
-            ActivityRecord starting, boolean deferResume, int displayId,
-            ActivityTaskManagerService.UpdateConfigurationResult result) {
-        int changes = 0;
-        boolean kept = true;
-
-        if (mWindowManager != null) {
-            mWindowManager.deferSurfaceLayout();
-        }
-        try {
-            if (values != null) {
-                if (displayId == DEFAULT_DISPLAY) {
-                    // Override configuration of the default display duplicates global config, so
-                    // we're calling global config update instead for default display. It will also
-                    // apply the correct override config.
-                    changes = updateGlobalConfigurationLocked(values, false /* initLocale */,
-                            false /* persistent */, UserHandle.USER_NULL /* userId */, deferResume);
-                } else {
-                    changes = performDisplayOverrideConfigUpdate(values, deferResume, displayId);
-                }
-            }
-
-            kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
-        } finally {
-            if (mWindowManager != null) {
-                mWindowManager.continueSurfaceLayout();
-            }
-        }
-
-        if (result != null) {
-            result.changes = changes;
-            result.activityRelaunched = !kept;
-        }
-        return kept;
-    }
-
-    private int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume,
-            int displayId) {
-        mActivityTaskManager.mTempConfig.setTo(mStackSupervisor.getDisplayOverrideConfiguration(displayId));
-        final int changes = mActivityTaskManager.mTempConfig.updateFrom(values);
-        if (changes != 0) {
-            Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
-                    + mActivityTaskManager.mTempConfig + " for displayId=" + displayId);
-            mStackSupervisor.setDisplayOverrideConfiguration(mActivityTaskManager.mTempConfig, displayId);
-
-            final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
-            if (isDensityChange && displayId == DEFAULT_DISPLAY) {
-                mAppWarnings.onDensityChanged();
-
-                killAllBackgroundProcessesExcept(N,
-                        ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
-            }
-        }
-
-        // Update the configuration with WM first and check if any of the stacks need to be resized
-        // due to the configuration change. If so, resize the stacks now and do any relaunches if
-        // necessary. This way we don't need to relaunch again afterwards in
-        // ensureActivityConfiguration().
-        if (mWindowManager != null) {
-            final int[] resizedStacks =
-                    mWindowManager.setNewDisplayOverrideConfiguration(mActivityTaskManager.mTempConfig, displayId);
-            if (resizedStacks != null) {
-                for (int stackId : resizedStacks) {
-                    resizeStackWithBoundsFromWindowManager(stackId, deferResume);
-                }
-            }
-        }
-
-        return changes;
-    }
-
-    /** Applies latest configuration and/or visibility updates if needed. */
-    private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {
-        boolean kept = true;
-        final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
-        // mainStack is null during startup.
-        if (mainStack != null) {
-            if (changes != 0 && starting == null) {
-                // If the configuration changed, and the caller is not already
-                // in the process of starting an activity, then find the top
-                // activity to check if its configuration needs to change.
-                starting = mainStack.topRunningActivityLocked();
-            }
-
-            if (starting != null) {
-                kept = starting.ensureActivityConfiguration(changes,
-                        false /* preserveWindow */);
-                // And we need to make sure at this point that all other activities
-                // are made visible with the correct configuration.
-                mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes,
-                        !PRESERVE_WINDOWS);
-            }
-        }
-
-        return kept;
-    }
-
-    /** Helper method that requests bounds from WM and applies them to stack. */
-    private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) {
-        final Rect newStackBounds = new Rect();
-        final ActivityStack stack = mStackSupervisor.getStack(stackId);
-
-        // TODO(b/71548119): Revert CL introducing below once cause of mismatch is found.
-        if (stack == null) {
-            final StringWriter writer = new StringWriter();
-            final PrintWriter printWriter = new PrintWriter(writer);
-            mStackSupervisor.dumpDisplays(printWriter);
-            printWriter.flush();
-
-            Log.wtf(TAG, "stack not found:" + stackId + " displays:" + writer);
-        }
-
-        stack.getBoundsForNewConfiguration(newStackBounds);
-        mStackSupervisor.resizeStackLocked(
-                stack, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */,
-                null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
-                false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume);
-    }
-
     /**
      * Decide based on the configuration whether we should show the ANR,
      * crash, etc dialogs.  The idea is that if there is no affordance to
@@ -19782,7 +19114,7 @@
      * A thought: SystemUI might also want to get told about this, the Power
      * dialog / global actions also might want different behaviors.
      */
-    private void updateShouldShowDialogsLocked(Configuration config) {
+    void updateShouldShowDialogsLocked(Configuration config) {
         final boolean inputMethodExists = !(config.keyboard == Configuration.KEYBOARD_NOKEYS
                                    && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH
                                    && config.navigation == Configuration.NAVIGATION_NONAV);
@@ -23233,15 +22565,6 @@
         }
 
         @Override
-        public void onUserRemoved(int userId) {
-            synchronized (ActivityManagerService.this) {
-                ActivityManagerService.this.onUserStoppedLocked(userId);
-            }
-            mBatteryStatsService.onUserRemoved(userId);
-            mUserController.onUserRemoved(userId);
-        }
-
-        @Override
         public void killForegroundAppsForUser(int userHandle) {
             synchronized (ActivityManagerService.this) {
                 final ArrayList<ProcessRecord> procs = new ArrayList<>();
@@ -23300,17 +22623,6 @@
         }
 
         @Override
-        public void updatePersistentConfigurationForUser(@NonNull Configuration values,
-                int userId) {
-            Preconditions.checkNotNull(values, "Configuration must not be null");
-            Preconditions.checkArgumentNonnegative(userId, "userId " + userId + " not supported");
-            synchronized (ActivityManagerService.this) {
-                updateConfigurationLocked(values, null, false, true, userId,
-                        false /* deferResume */);
-            }
-        }
-
-        @Override
         public int getUidProcessState(int uid) {
             return getUidState(uid);
         }
@@ -23428,27 +22740,6 @@
         }
 
         @Override
-        public void setAllowAppSwitches(@NonNull String type, int uid, int userId) {
-            synchronized (ActivityManagerService.this) {
-                if (mUserController.isUserRunning(userId, ActivityManager.FLAG_OR_STOPPED)) {
-                    ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(userId);
-                    if (types == null) {
-                        if (uid < 0) {
-                            return;
-                        }
-                        types = new ArrayMap<>();
-                        mAllowAppSwitchUids.put(userId, types);
-                    }
-                    if (uid < 0) {
-                        types.remove(type);
-                    } else {
-                        types.put(type, uid);
-                    }
-                }
-            }
-        }
-
-        @Override
         public boolean isRuntimeRestarted() {
             return mSystemServiceManager.isRuntimeRestarted();
         }
@@ -23511,6 +22802,51 @@
             }
             return processMemoryStates;
         }
+
+        @Override
+        public int handleIncomingUser(int callingPid, int callingUid, int userId,
+                boolean allowAll, int allowMode, String name, String callerPackage) {
+            return mUserController.handleIncomingUser(callingPid, callingUid, userId, allowAll,
+                    allowMode, name, callerPackage);
+        }
+
+        @Override
+        public void enforceCallingPermission(String permission, String func) {
+            ActivityManagerService.this.enforceCallingPermission(permission, func);
+        }
+
+        @Override
+        public int getCurrentUserId() {
+            return mUserController.getCurrentUserIdLU();
+        }
+
+        @Override
+        public boolean isUserRunning(int userId, int flags) {
+            synchronized (ActivityManagerService.this) {
+                return mUserController.isUserRunning(userId, flags);
+            }
+        }
+
+        @Override
+        public void trimApplications() {
+            ActivityManagerService.this.trimApplications();
+        }
+
+        public int getPackageScreenCompatMode(ApplicationInfo ai) {
+            synchronized (ActivityManagerService.this) {
+                return mCompatModePackages.computeCompatModeLocked(ai);
+            }
+        }
+
+        public void setPackageScreenCompatMode(ApplicationInfo ai, int mode) {
+            synchronized (ActivityManagerService.this) {
+                mCompatModePackages.setPackageScreenCompatModeLocked(ai, mode);
+            }
+        }
+
+        public void closeSystemDialogs(String reason) {
+            ActivityManagerService.this.closeSystemDialogs(reason);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 0e427d6..7f3f8f3 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1220,7 +1220,7 @@
      * @return whether this activity supports PiP multi-window and can be put in the pinned stack.
      */
     boolean supportsPictureInPicture() {
-        return service.mAm.mSupportsPictureInPicture && isActivityTypeStandardOrUndefined()
+        return service.mSupportsPictureInPicture && isActivityTypeStandardOrUndefined()
                 && info.supportsPictureInPicture();
     }
 
@@ -1233,7 +1233,7 @@
         // An activity can not be docked even if it is considered resizeable because it only
         // supports picture-in-picture mode but has a non-resizeable resizeMode
         return super.supportsSplitScreenWindowingMode()
-                && service.mAm.mSupportsSplitScreenMultiWindow && supportsResizeableMultiWindow();
+                && service.mSupportsSplitScreenMultiWindow && supportsResizeableMultiWindow();
     }
 
     /**
@@ -1241,16 +1241,16 @@
      *         stack.
      */
     boolean supportsFreeform() {
-        return service.mAm.mSupportsFreeformWindowManagement && supportsResizeableMultiWindow();
+        return service.mSupportsFreeformWindowManagement && supportsResizeableMultiWindow();
     }
 
     /**
      * @return whether this activity supports non-PiP multi-window.
      */
     private boolean supportsResizeableMultiWindow() {
-        return service.mAm.mSupportsMultiWindow && !isActivityTypeHome()
+        return service.mSupportsMultiWindow && !isActivityTypeHome()
                 && (ActivityInfo.isResizeableMode(info.resizeMode)
-                        || service.mAm.mForceResizableActivities);
+                        || service.mForceResizableActivities);
     }
 
     /**
@@ -2347,7 +2347,7 @@
                 displayId, displayConfig, mayFreezeScreenLocked(app));
         if (config != null) {
             frozenBeforeDestroy = true;
-            if (!service.mAm.updateDisplayOverrideConfigurationLocked(config, this,
+            if (!service.updateDisplayOverrideConfigurationLocked(config, this,
                     false /* deferResume */, displayId)) {
                 mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6118131..d177702 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3956,7 +3956,9 @@
             }
         }
 
-        IActivityController controller = mService.mAm.mController;
+        // TODO: There is a dup. of this block of code in ActivityTaskManagerService.finishActivity
+        // We should consolidate.
+        IActivityController controller = mService.mController;
         if (controller != null) {
             ActivityRecord next = topRunningActivityLocked(srec.appToken, 0);
             if (next != null) {
@@ -3965,7 +3967,7 @@
                 try {
                     resumeOK = controller.activityResuming(next.packageName);
                 } catch (RemoteException e) {
-                    mService.mAm.mController = null;
+                    mService.mController = null;
                     Watchdog.getInstance().setActivityController(null);
                 }
 
@@ -4662,7 +4664,7 @@
         // If we have a watcher, preflight the move before committing to it.  First check
         // for *other* available tasks, but if none are available, then try again allowing the
         // current task to be selected.
-        if (isTopStackOnDisplay() && mService.mAm.mController != null) {
+        if (isTopStackOnDisplay() && mService.mController != null) {
             ActivityRecord next = topRunningActivityLocked(null, taskId);
             if (next == null) {
                 next = topRunningActivityLocked(null, 0);
@@ -4671,9 +4673,9 @@
                 // ask watcher if this is allowed
                 boolean moveOK = true;
                 try {
-                    moveOK = mService.mAm.mController.activityResuming(next.packageName);
+                    moveOK = mService.mController.activityResuming(next.packageName);
                 } catch (RemoteException e) {
-                    mService.mAm.mController = null;
+                    mService.mController = null;
                     Watchdog.getInstance().setActivityController(null);
                 }
                 if (!moveOK) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a77d734..10b721e 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -488,7 +488,7 @@
             // No restrictions for the default display.
             return true;
         }
-        if (!mService.mAm.mSupportsMultiDisplay) {
+        if (!mService.mSupportsMultiDisplay) {
             // Can't launch on secondary displays if feature is not supported.
             return false;
         }
@@ -624,7 +624,7 @@
         mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext, mHandler.getLooper());
         mKeyguardController = new KeyguardController(mService.mAm, this);
 
-        mLaunchParamsController = new LaunchParamsController(mService.mAm);
+        mLaunchParamsController = new LaunchParamsController(mService);
         mLaunchParamsController.registerDefaultModifiers(this);
     }
 
@@ -1661,7 +1661,7 @@
         }
 
         // Update the configuration of the activities on the display.
-        return mService.mAm.updateDisplayOverrideConfigurationLocked(config, starting, deferResume,
+        return mService.updateDisplayOverrideConfigurationLocked(config, starting, deferResume,
                 displayId);
     }
 
@@ -2347,9 +2347,9 @@
         if (options == null || options.getLaunchBounds() == null) {
             return false;
         }
-        return (mService.mAm.mSupportsPictureInPicture
+        return (mService.mSupportsPictureInPicture
                 && options.getLaunchWindowingMode() == WINDOWING_MODE_PINNED)
-                || mService.mAm.mSupportsFreeformWindowManagement;
+                || mService.mSupportsFreeformWindowManagement;
     }
 
     LaunchParamsController getLaunchParamsController() {
@@ -3258,21 +3258,21 @@
 
         // Ensure that we aren't trying to move into a multi-window stack without multi-window
         // support
-        if (inMultiWindowMode && !mService.mAm.mSupportsMultiWindow) {
+        if (inMultiWindowMode && !mService.mSupportsMultiWindow) {
             throw new IllegalArgumentException("Device doesn't support multi-window, can not"
                     + " reparent task=" + task + " to stack=" + stack);
         }
 
         // Ensure that we're not moving a task to a dynamic stack if device doesn't support
         // multi-display.
-        if (stack.mDisplayId != DEFAULT_DISPLAY && !mService.mAm.mSupportsMultiDisplay) {
+        if (stack.mDisplayId != DEFAULT_DISPLAY && !mService.mSupportsMultiDisplay) {
             throw new IllegalArgumentException("Device doesn't support multi-display, can not"
                     + " reparent task=" + task + " to stackId=" + stackId);
         }
 
         // Ensure that we aren't trying to move into a freeform stack without freeform support
         if (stack.getWindowingMode() == WINDOWING_MODE_FREEFORM
-                && !mService.mAm.mSupportsFreeformWindowManagement) {
+                && !mService.mSupportsFreeformWindowManagement) {
             throw new IllegalArgumentException("Device doesn't support freeform, can not reparent"
                     + " task=" + task);
         }
@@ -3305,7 +3305,7 @@
             return false;
         }
 
-        if (!mService.mAm.mForceResizableActivities && !r.supportsPictureInPicture()) {
+        if (!mService.mForceResizableActivities && !r.supportsPictureInPicture()) {
             Slog.w(TAG,
                     "moveTopStackActivityToPinnedStackLocked: Picture-In-Picture not supported for "
                             + " r=" + r);
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index fa001df..f7ea4b2 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -21,7 +21,7 @@
 
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.ALLOW_FULL_ONLY;
+import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 
 import android.app.IApplicationThread;
 import android.content.ComponentName;
@@ -237,8 +237,8 @@
     int checkTargetUser(int targetUserId, boolean validateIncomingUser,
             int realCallingPid, int realCallingUid, String reason) {
         if (validateIncomingUser) {
-            return mService.mAm.mUserController.handleIncomingUser(realCallingPid, realCallingUid,
-                    targetUserId, false, ALLOW_FULL_ONLY, reason, null);
+            return mService.handleIncomingUser(
+                    realCallingPid, realCallingUid, targetUserId, reason);
         } else {
             mService.mAm.mUserController.ensureNotSpecialUser(targetUserId);
             return targetUserId;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index f50bb37..6f58aea 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -729,15 +729,15 @@
                     .getPendingRemoteAnimationRegistry()
                     .overrideOptionsIfNeeded(callingPackage, checkedOptions);
         }
-        if (mService.mAm.mController != null) {
+        if (mService.mController != null) {
             try {
                 // The Intent we give to the watcher has the extra data
                 // stripped off, since it can contain private information.
                 Intent watchIntent = intent.cloneFilter();
-                abort |= !mService.mAm.mController.activityStarting(watchIntent,
+                abort |= !mService.mController.activityStarting(watchIntent,
                         aInfo.applicationInfo.packageName);
             } catch (RemoteException e) {
-                mService.mAm.mController = null;
+                mService.mController = null;
             }
         }
 
@@ -844,7 +844,7 @@
         // one, check whether app switches are allowed.
         if (voiceSession == null && (stack.getResumedActivity() == null
                 || stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) {
-            if (!mService.mAm.checkAppSwitchAllowedLocked(callingPid, callingUid,
+            if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
                     realCallingPid, realCallingUid, "Activity start")) {
                 mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
                         sourceRecord, startFlags, stack, callerApp));
@@ -853,17 +853,7 @@
             }
         }
 
-        if (mService.mAm.mDidAppSwitch) {
-            // This is the second allowed switch since we stopped switches,
-            // so now just generally allow switches.  Use case: user presses
-            // home (switches disabled, switch to home, mDidAppSwitch now true);
-            // user taps a home icon (coming from home so allowed, we hit here
-            // and now allow anyone to switch again).
-            mService.mAm.mAppSwitchesAllowedTime = 0;
-        } else {
-            mService.mAm.mDidAppSwitch = true;
-        }
-
+        mService.onStartActivitySetDidAppSwitch();
         mController.doPendingActivityLaunches(false);
 
         return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
@@ -1110,12 +1100,12 @@
                 // do so now.  This allows a clean switch, as we are waiting
                 // for the current activity to pause (so we will not destroy
                 // it), and have not yet started the next activity.
-                mService.mAm.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
+                mService.mAmInternal.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
                         "updateConfiguration()");
                 stack.mConfigWillChange = false;
                 if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                         "Updating to new configuration after starting activity.");
-                mService.mAm.updateConfigurationLocked(globalConfig, null, false);
+                mService.updateConfigurationLocked(globalConfig, null, false);
             }
 
             if (outResult != null) {
@@ -1821,7 +1811,7 @@
         }
 
         // Get the virtual display id from ActivityManagerService.
-        int displayId = mService.mAm.mVr2dDisplayId;
+        int displayId = mService.mVr2dDisplayId;
         if (displayId != INVALID_DISPLAY) {
             if (DEBUG_STACK) {
                 Slog.d(TAG, "getSourceDisplayId :" + displayId);
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 90097fd..d554e0f 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -24,6 +24,7 @@
 import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.Manifest.permission.REMOVE_TASKS;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.STOP_APP_SWITCHES;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
 import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
@@ -32,6 +33,7 @@
 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;
@@ -42,8 +44,19 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
+import static android.os.Build.VERSION_CODES.N;
 import static android.os.Process.SYSTEM_UID;
+import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
+import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS;
 import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
@@ -60,7 +73,9 @@
 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;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
@@ -69,10 +84,13 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.ALLOW_FULL_ONLY;
+import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 import static com.android.server.am.ActivityManagerService.ANIMATE;
-import static com.android.server.am.ActivityManagerService.DISPATCH_SCREEN_KEYGUARD_MSG;
+import static com.android.server.am.ActivityManagerService.MY_PID;
+import static com.android.server.am.ActivityManagerService.SEND_LOCALE_TO_MOUNT_DAEMON_MSG;
 import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
+import static com.android.server.am.ActivityManagerService.UPDATE_CONFIGURATION_MSG;
+import static com.android.server.am.ActivityManagerService.checkComponentPermission;
 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY;
@@ -88,14 +106,17 @@
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.ActivityTaskManagerInternal;
 import android.app.AppGlobals;
+import android.app.IActivityController;
 import android.app.IActivityTaskManager;
 import android.app.IApplicationThread;
 import android.app.IAssistDataReceiver;
@@ -108,17 +129,21 @@
 import android.app.admin.DevicePolicyCache;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
+import android.app.servertransaction.ConfigurationChangeItem;
 import android.app.usage.UsageEvents;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -134,21 +159,29 @@
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.TransactionTooLargeException;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UpdateLock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.EventLog;
+import android.util.Log;
 import android.util.Slog;
 
+import android.util.SparseArray;
 import android.util.SparseIntArray;
+import android.util.StatsLog;
 import android.util.proto.ProtoOutputStream;
 import android.view.IRecentsAnimationRunner;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationDefinition;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.AssistUtils;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.logging.MetricsLogger;
@@ -157,6 +190,7 @@
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.KeyguardDismissCallback;
 import com.android.internal.util.Preconditions;
+import com.android.server.AttributeCache;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.Watchdog;
@@ -166,6 +200,7 @@
 
 import java.io.File;
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -182,10 +217,13 @@
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
     private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
     private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
+    private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
 
     Context mContext;
     H mH;
+    UiHandler mUiHandler;
     ActivityManagerService mAm;
+    ActivityManagerInternal mAmInternal;
     /* Global service lock used by the package the owns this service. */
     Object mGlobalLock;
     ActivityStackSupervisor mStackSupervisor;
@@ -245,14 +283,77 @@
     }
 
     /** Current sequencing integer of the configuration, for skipping old configurations. */
-    int mConfigurationSeq;
+    private int mConfigurationSeq;
+    // To cache the list of supported system locales
+    private String[] mSupportedSystemLocales = null;
 
     /**
      * Temp object used when global and/or display override configuration is updated. It is also
      * sent to outer world instead of {@link #getGlobalConfiguration} because we don't trust
      * anyone...
      */
-    Configuration mTempConfig = new Configuration();
+    private Configuration mTempConfig = new Configuration();
+
+    // Amount of time after a call to stopAppSwitches() during which we will
+    // prevent further untrusted switches from happening.
+    private static final long APP_SWITCH_DELAY_TIME = 5 * 1000;
+
+    /**
+     * The time at which we will allow normal application switches again,
+     * after a call to {@link #stopAppSwitches()}.
+     */
+    long mAppSwitchesAllowedTime;
+    /**
+     * This is set to true after the first switch after mAppSwitchesAllowedTime
+     * is set; any switches after that will clear the time.
+     */
+    boolean mDidAppSwitch;
+
+    IActivityController mController = null;
+    boolean mControllerIsAMonkey = false;
+
+    /**
+     * Used to retain an update lock when the foreground activity is in
+     * immersive mode.
+     */
+    final UpdateLock mUpdateLock = new UpdateLock("immersive");
+
+    /**
+     * Packages that are being allowed to perform unrestricted app switches.  Mapping is
+     * User -> Type -> uid.
+     */
+    final SparseArray<ArrayMap<String, Integer>> mAllowAppSwitchUids = new SparseArray<>();
+
+    /** The dimensions of the thumbnails in the Recents UI. */
+    int mThumbnailWidth;
+    int mThumbnailHeight;
+    float mFullscreenThumbnailScale;
+
+    /**
+     * Flag that indicates if multi-window is enabled.
+     *
+     * For any particular form of multi-window to be enabled, generic multi-window must be enabled
+     * in {@link com.android.internal.R.bool#config_supportsMultiWindow} config or
+     * {@link Settings.Global#DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES} development option set.
+     * At least one of the forms of multi-window must be enabled in order for this flag to be
+     * initialized to 'true'.
+     *
+     * @see #mSupportsSplitScreenMultiWindow
+     * @see #mSupportsFreeformWindowManagement
+     * @see #mSupportsPictureInPicture
+     * @see #mSupportsMultiDisplay
+     */
+    boolean mSupportsMultiWindow;
+    boolean mSupportsSplitScreenMultiWindow;
+    boolean mSupportsFreeformWindowManagement;
+    boolean mSupportsPictureInPicture;
+    boolean mSupportsMultiDisplay;
+    boolean mForceResizableActivities;
+
+    final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>();
+
+    // VR Vr2d Display Id.
+    int mVr2dDisplayId = INVALID_DISPLAY;
 
     ActivityTaskManagerService(Context context) {
         mContext = context;
@@ -265,11 +366,87 @@
         mRecentTasks.onSystemReadyLocked();
     }
 
+    void retrieveSettings(ContentResolver resolver) {
+        final boolean freeformWindowManagement =
+                mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
+                        || Settings.Global.getInt(
+                        resolver, DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
+
+        final boolean supportsMultiWindow = ActivityTaskManager.supportsMultiWindow(mContext);
+        final boolean supportsPictureInPicture = supportsMultiWindow &&
+                mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
+        final boolean supportsSplitScreenMultiWindow =
+                ActivityTaskManager.supportsSplitScreenMultiWindow(mContext);
+        final boolean supportsMultiDisplay = mContext.getPackageManager()
+                .hasSystemFeature(FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS);
+        final boolean alwaysFinishActivities =
+                Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
+        final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
+        final boolean forceResizable = Settings.Global.getInt(
+                resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
+
+        // Transfer any global setting for forcing RTL layout, into a System Property
+        SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
+
+        final Configuration configuration = new Configuration();
+        Settings.System.getConfiguration(resolver, configuration);
+        if (forceRtl) {
+            // This will take care of setting the correct layout direction flags
+            configuration.setLayoutDirection(configuration.locale);
+        }
+
+        synchronized (mGlobalLock) {
+            mForceResizableActivities = forceResizable;
+            final boolean multiWindowFormEnabled = freeformWindowManagement
+                    || supportsSplitScreenMultiWindow
+                    || supportsPictureInPicture
+                    || supportsMultiDisplay;
+            if ((supportsMultiWindow || forceResizable) && multiWindowFormEnabled) {
+                mSupportsMultiWindow = true;
+                mSupportsFreeformWindowManagement = freeformWindowManagement;
+                mSupportsSplitScreenMultiWindow = supportsSplitScreenMultiWindow;
+                mSupportsPictureInPicture = supportsPictureInPicture;
+                mSupportsMultiDisplay = supportsMultiDisplay;
+            } else {
+                mSupportsMultiWindow = false;
+                mSupportsFreeformWindowManagement = false;
+                mSupportsSplitScreenMultiWindow = false;
+                mSupportsPictureInPicture = false;
+                mSupportsMultiDisplay = false;
+            }
+            mWindowManager.setForceResizableTasks(mForceResizableActivities);
+            mWindowManager.setSupportsPictureInPicture(mSupportsPictureInPicture);
+            // This happens before any activities are started, so we can change global configuration
+            // in-place.
+            updateConfigurationLocked(configuration, null, true);
+            final Configuration globalConfig = getGlobalConfiguration();
+            if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Initial config: " + globalConfig);
+
+            // Load resources only after the current configuration has been set.
+            final Resources res = mContext.getResources();
+            mThumbnailWidth = res.getDimensionPixelSize(
+                    com.android.internal.R.dimen.thumbnail_width);
+            mThumbnailHeight = res.getDimensionPixelSize(
+                    com.android.internal.R.dimen.thumbnail_height);
+
+            if ((globalConfig.uiMode & UI_MODE_TYPE_TELEVISION) == UI_MODE_TYPE_TELEVISION) {
+                mFullscreenThumbnailScale = (float) res
+                        .getInteger(com.android.internal.R.integer.thumbnail_width_tv) /
+                        (float) globalConfig.screenWidthDp;
+            } else {
+                mFullscreenThumbnailScale = res.getFraction(
+                        com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
+            }
+        }
+    }
+
     // TODO: Will be converted to WM lock once transition is complete.
     void setActivityManagerService(ActivityManagerService am) {
         mAm = am;
+        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
         mGlobalLock = mAm;
         mH = new H(mAm.mHandlerThread.getLooper());
+        mUiHandler = new UiHandler();
 
         mTempConfig.setToDefaults();
         mTempConfig.setLocales(LocaleList.getDefault());
@@ -278,12 +455,12 @@
         mStackSupervisor.onConfigurationChanged(mTempConfig);
 
         mTaskChangeNotificationController =
-                new TaskChangeNotificationController(mAm, mStackSupervisor, mH);
+                new TaskChangeNotificationController(mGlobalLock, mStackSupervisor, mH);
         mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mH);
         mActivityStartController = new ActivityStartController(this);
         mRecentTasks = createRecentTasks();
         mStackSupervisor.setRecentTasks(mRecentTasks);
-        mVrController = new VrController(mAm);
+        mVrController = new VrController(mGlobalLock);
         mKeyguardController = mStackSupervisor.getKeyguardController();
     }
 
@@ -359,9 +536,8 @@
             Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
             int userId) {
         final String reason = "startActivities";
-        mAm.enforceNotIsolatedCaller(reason);
-        userId = mAm.mUserController.handleIncomingUser(Binder.getCallingPid(),
-                Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, reason, null);
+        enforceNotIsolatedCaller(reason);
+        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, reason);
         // TODO: Switch to user app stacks here.
         return getActivityStartController().startActivities(caller, -1, callingPackage, intents,
                 resolvedTypes, resultTo, SafeActivityOptions.fromBundle(bOptions), userId, reason);
@@ -380,7 +556,7 @@
             Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
             int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
             boolean validateIncomingUser) {
-        mAm.enforceNotIsolatedCaller("startActivityAsUser");
+        enforceNotIsolatedCaller("startActivityAsUser");
 
         userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
                 Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
@@ -404,9 +580,8 @@
     @Override
     public int startActivityIntentSender(IApplicationThread caller, IIntentSender target,
             IBinder whitelistToken, Intent fillInIntent, String resolvedType, IBinder resultTo,
-            String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle bOptions)
-            throws TransactionTooLargeException {
-        mAm.enforceNotIsolatedCaller("startActivityIntentSender");
+            String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle bOptions) {
+        enforceNotIsolatedCaller("startActivityIntentSender");
         // Refuse possible leaked file descriptors
         if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -421,15 +596,14 @@
         synchronized (mGlobalLock) {
             // If this is coming from the currently resumed activity, it is
             // effectively saying that app switches are allowed at this point.
-            final ActivityStack stack = mAm.getFocusedStack();
+            final ActivityStack stack = getFocusedStack();
             if (stack.mResumedActivity != null &&
                     stack.mResumedActivity.info.applicationInfo.uid == Binder.getCallingUid()) {
-                mAm.mAppSwitchesAllowedTime = 0;
+                mAppSwitchesAllowedTime = 0;
             }
         }
-        int ret = pir.sendInner(0, fillInIntent, resolvedType, whitelistToken, null, null,
+        return pir.sendInner(0, fillInIntent, resolvedType, whitelistToken, null, null,
                 resultTo, resultWho, requestCode, flagsMask, flagsValues, bOptions);
-        return ret;
     }
 
     @Override
@@ -556,10 +730,9 @@
             int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
         final WaitResult res = new WaitResult();
         synchronized (mGlobalLock) {
-            mAm.enforceNotIsolatedCaller("startActivityAndWait");
-            userId = mAm.mUserController.handleIncomingUser(Binder.getCallingPid(),
-                    Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY,
-                    "startActivityAndWait", null);
+            enforceNotIsolatedCaller("startActivityAndWait");
+            userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                    userId, "startActivityAndWait");
             // TODO: Switch to user app stacks here.
             getActivityStartController().obtainStarter(intent, "startActivityAndWait")
                     .setCaller(caller)
@@ -583,10 +756,9 @@
             Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
             int startFlags, Configuration config, Bundle bOptions, int userId) {
         synchronized (mGlobalLock) {
-            mAm.enforceNotIsolatedCaller("startActivityWithConfig");
-            userId = mAm.mUserController.handleIncomingUser(Binder.getCallingPid(),
-                    Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY,
-                    "startActivityWithConfig", null);
+            enforceNotIsolatedCaller("startActivityWithConfig");
+            userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
+                    "startActivityWithConfig");
             // TODO: Switch to user app stacks here.
             return getActivityStartController().obtainStarter(intent, "startActivityWithConfig")
                     .setCaller(caller)
@@ -692,17 +864,21 @@
         }
     }
 
+    int handleIncomingUser(int callingPid, int callingUid, int userId, String name) {
+        return mAmInternal.handleIncomingUser(callingPid, callingUid, userId, false /* allowAll */,
+                ALLOW_FULL_ONLY, name, null /* callerPackage */);
+    }
+
     @Override
     public int startVoiceActivity(String callingPackage, int callingPid, int callingUid,
             Intent intent, String resolvedType, IVoiceInteractionSession session,
             IVoiceInteractor interactor, int startFlags, ProfilerInfo profilerInfo,
             Bundle bOptions, int userId) {
-        mAm.enforceCallingPermission(BIND_VOICE_INTERACTION, "startVoiceActivity()");
+        mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startVoiceActivity()");
         if (session == null || interactor == null) {
             throw new NullPointerException("null session or interactor");
         }
-        userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
-                ALLOW_FULL_ONLY, "startVoiceActivity", null);
+        userId = handleIncomingUser(callingPid, callingUid, userId, "startVoiceActivity");
         // TODO: Switch to user app stacks here.
         return getActivityStartController().obtainStarter(intent, "startVoiceActivity")
                 .setCallingUid(callingUid)
@@ -720,9 +896,8 @@
     @Override
     public int startAssistantActivity(String callingPackage, int callingPid, int callingUid,
             Intent intent, String resolvedType, Bundle bOptions, int userId) {
-        mAm.enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()");
-        userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
-                ALLOW_FULL_ONLY, "startAssistantActivity", null);
+        mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()");
+        userId = handleIncomingUser(callingPid, callingUid, userId, "startAssistantActivity");
 
         return getActivityStartController().obtainStarter(intent, "startAssistantActivity")
                 .setCallingUid(callingUid)
@@ -736,7 +911,7 @@
     @Override
     public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver,
             IRecentsAnimationRunner recentsAnimationRunner) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
         final int callingPid = Binder.getCallingPid();
         final long origId = Binder.clearCallingIdentity();
         try {
@@ -745,9 +920,8 @@
                 final int recentsUid = mRecentTasks.getRecentsComponentUid();
 
                 // Start a new recents animation
-                final RecentsAnimation anim = new RecentsAnimation(mAm, mStackSupervisor,
-                        getActivityStartController(), mAm.mWindowManager, mAm.mUserController,
-                        callingPid);
+                final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor,
+                        getActivityStartController(), mWindowManager, callingPid);
                 anim.startRecentsActivity(intent, recentsAnimationRunner, recentsComponent,
                         recentsUid, assistDataReceiver);
             }
@@ -758,7 +932,7 @@
 
     @Override
     public final int startActivityFromRecents(int taskId, Bundle bOptions) {
-        mAm.enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
+        enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
                 "startActivityFromRecents()");
 
         final int callingPid = Binder.getCallingPid();
@@ -810,16 +984,18 @@
                 return false;
             }
 
-            if (mAm.mController != null) {
+            // TODO: There is a dup. of this block of code in ActivityStack.navigateUpToLocked
+            // We should consolidate.
+            if (mController != null) {
                 // Find the first activity that is not finishing.
                 ActivityRecord next = r.getStack().topRunningActivityLocked(token, 0);
                 if (next != null) {
                     // ask watcher if this is allowed
                     boolean resumeOK = true;
                     try {
-                        resumeOK = mAm.mController.activityResuming(next.packageName);
+                        resumeOK = mController.activityResuming(next.packageName);
                     } catch (RemoteException e) {
-                        mAm.mController = null;
+                        mController = null;
                         Watchdog.getInstance().setActivityController(null);
                     }
 
@@ -907,7 +1083,7 @@
         final long origId = Binder.clearCallingIdentity();
         synchronized (mGlobalLock) {
             ActivityRecord.activityResumedLocked(token);
-            mAm.mWindowManager.notifyAppResumedFinished(token);
+            mWindowManager.notifyAppResumedFinished(token);
         }
         Binder.restoreCallingIdentity(origId);
     }
@@ -943,7 +1119,7 @@
             }
         }
 
-        mAm.trimApplications();
+        mAmInternal.trimApplications();
 
         Binder.restoreCallingIdentity(origId);
     }
@@ -1022,11 +1198,30 @@
             // update associated state if we're frontmost
             if (r == mStackSupervisor.getResumedActivityLocked()) {
                 if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE, "Frontmost changed immersion: "+ r);
-                mAm.applyUpdateLockStateLocked(r);
+                applyUpdateLockStateLocked(r);
             }
         }
     }
 
+    void applyUpdateLockStateLocked(ActivityRecord r) {
+        // Modifications to the UpdateLock state are done on our handler, outside
+        // the activity manager's locks.  The new state is determined based on the
+        // state *now* of the relevant activity record.  The object is passed to
+        // the handler solely for logging detail, not to be consulted/modified.
+        final boolean nextState = r != null && r.immersive;
+        mH.post(() -> {
+            if (mUpdateLock.isHeld() != nextState) {
+                if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE,
+                        "Applying new update lock state '" + nextState + "' for " + r);
+                if (nextState) {
+                    mUpdateLock.acquire();
+                } else {
+                    mUpdateLock.release();
+                }
+            }
+        });
+    }
+
     @Override
     public boolean isImmersive(IBinder token) {
         synchronized (mGlobalLock) {
@@ -1040,9 +1235,9 @@
 
     @Override
     public boolean isTopActivityImmersive() {
-        mAm.enforceNotIsolatedCaller("isTopActivityImmersive");
+        enforceNotIsolatedCaller("isTopActivityImmersive");
         synchronized (mGlobalLock) {
-            final ActivityRecord r = mAm.getFocusedStack().topRunningActivityLocked();
+            final ActivityRecord r = getFocusedStack().topRunningActivityLocked();
             return (r != null) ? r.immersive : false;
         }
     }
@@ -1060,7 +1255,7 @@
 
             if (self.isState(
                     ActivityStack.ActivityState.RESUMED, ActivityStack.ActivityState.PAUSING)) {
-                mAm.mWindowManager.overridePendingAppTransition(packageName,
+                mWindowManager.overridePendingAppTransition(packageName,
                         enterAnim, exitAnim, null);
             }
 
@@ -1070,19 +1265,34 @@
 
     @Override
     public int getFrontActivityScreenCompatMode() {
-        mAm.enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
+        enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
+        ApplicationInfo ai;
         synchronized (mGlobalLock) {
-            return mAm.mCompatModePackages.getFrontActivityScreenCompatModeLocked();
+            final ActivityRecord r = getFocusedStack().topRunningActivityLocked();
+            if (r == null) {
+                return ActivityManager.COMPAT_MODE_UNKNOWN;
+            }
+            ai = r.info.applicationInfo;
         }
+
+        return mAmInternal.getPackageScreenCompatMode(ai);
     }
 
     @Override
     public void setFrontActivityScreenCompatMode(int mode) {
-        mAm.enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+        mAmInternal.enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
                 "setFrontActivityScreenCompatMode");
+        ApplicationInfo ai;
         synchronized (mGlobalLock) {
-            mAm.mCompatModePackages.setFrontActivityScreenCompatModeLocked(mode);
+            final ActivityRecord r = getFocusedStack().topRunningActivityLocked();
+            if (r == null) {
+                Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity");
+                return;
+            }
+            ai = r.info.applicationInfo;
         }
+
+        mAmInternal.setPackageScreenCompatMode(ai, mode);
     }
 
     @Override
@@ -1122,7 +1332,7 @@
                 if (translucentChanged) {
                     mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                 }
-                mAm.mWindowManager.setAppFullscreen(token, true);
+                mWindowManager.setAppFullscreen(token, true);
                 return translucentChanged;
             }
         } finally {
@@ -1151,7 +1361,7 @@
                     r.getStack().convertActivityToTranslucent(r);
                 }
                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-                mAm.mWindowManager.setAppFullscreen(token, false);
+                mWindowManager.setAppFullscreen(token, false);
                 return translucentChanged;
             }
         } finally {
@@ -1194,11 +1404,11 @@
 
     @Override
     public ActivityManager.StackInfo getFocusedStackInfo() throws RemoteException {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                ActivityStack focusedStack = mAm.getFocusedStack();
+                ActivityStack focusedStack = getFocusedStack();
                 if (focusedStack != null) {
                     return mStackSupervisor.getStackInfo(focusedStack.mStackId);
                 }
@@ -1211,7 +1421,7 @@
 
     @Override
     public void setFocusedStack(int stackId) {
-        mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()");
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()");
         if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedStack: stackId=" + stackId);
         final long callingId = Binder.clearCallingIdentity();
         try {
@@ -1234,7 +1444,7 @@
 
     @Override
     public void setFocusedTask(int taskId) {
-        mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedTask()");
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedTask()");
         if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedTask: taskId=" + taskId);
         final long callingId = Binder.clearCallingIdentity();
         try {
@@ -1255,7 +1465,7 @@
 
     @Override
     public boolean removeTask(int taskId) {
-        mAm.enforceCallerIsRecentsOrHasPermission(REMOVE_TASKS, "removeTask()");
+        enforceCallerIsRecentsOrHasPermission(REMOVE_TASKS, "removeTask()");
         synchronized (mGlobalLock) {
             final long ident = Binder.clearCallingIdentity();
             try {
@@ -1312,7 +1522,7 @@
      */
     @Override
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
-        mAm.enforceNotIsolatedCaller("moveActivityTaskToBack");
+        enforceNotIsolatedCaller("moveActivityTaskToBack");
         synchronized (mGlobalLock) {
             final long origId = Binder.clearCallingIdentity();
             try {
@@ -1330,7 +1540,7 @@
 
     @Override
     public Rect getTaskBounds(int taskId) {
-        mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getTaskBounds()");
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getTaskBounds()");
         long ident = Binder.clearCallingIdentity();
         Rect rect = new Rect();
         try {
@@ -1364,7 +1574,7 @@
     @Override
     public ActivityManager.TaskDescription getTaskDescription(int id) {
         synchronized (mGlobalLock) {
-            mAm.enforceCallerIsRecentsOrHasPermission(
+            enforceCallerIsRecentsOrHasPermission(
                     MANAGE_ACTIVITY_STACKS, "getTaskDescription()");
             final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id,
                     MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
@@ -1382,7 +1592,7 @@
                     toTop, ANIMATE, null /* initialBounds */, true /* showRecents */);
             return;
         }
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()");
         synchronized (mGlobalLock) {
             final long ident = Binder.clearCallingIdentity();
             try {
@@ -1414,7 +1624,7 @@
 
     @Override
     public String getCallingPackage(IBinder token) {
-        synchronized (this) {
+        synchronized (mGlobalLock) {
             ActivityRecord r = getCallingRecordLocked(token);
             return r != null ? r.info.packageName : null;
         }
@@ -1422,7 +1632,7 @@
 
     @Override
     public ComponentName getCallingActivity(IBinder token) {
-        synchronized (this) {
+        synchronized (mGlobalLock) {
             ActivityRecord r = getCallingRecordLocked(token);
             return r != null ? r.intent.getComponent() : null;
         }
@@ -1438,12 +1648,12 @@
 
     @Override
     public void unhandledBack() {
-        mAm.enforceCallingPermission(android.Manifest.permission.FORCE_BACK, "unhandledBack()");
+        mAmInternal.enforceCallingPermission(android.Manifest.permission.FORCE_BACK, "unhandledBack()");
 
         synchronized (mGlobalLock) {
             final long origId = Binder.clearCallingIdentity();
             try {
-                mAm.getFocusedStack().unhandledBackLocked();
+                getFocusedStack().unhandledBackLocked();
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
@@ -1455,7 +1665,7 @@
      */
     @Override
     public void moveTaskToFront(int taskId, int flags, Bundle bOptions) {
-        mAm.enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()");
+        mAmInternal.enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()");
 
         if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
         synchronized (mGlobalLock) {
@@ -1467,7 +1677,7 @@
     void moveTaskToFrontLocked(int taskId, int flags, SafeActivityOptions options,
             boolean fromRecents) {
 
-        if (!mAm.checkAppSwitchAllowedLocked(Binder.getCallingPid(),
+        if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
                 Binder.getCallingUid(), -1, -1, "Task to front")) {
             SafeActivityOptions.abort(options);
             return;
@@ -1503,6 +1713,69 @@
         SafeActivityOptions.abort(options);
     }
 
+    boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
+            int callingPid, int callingUid, String name) {
+        if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
+            return true;
+        }
+
+        if (getRecentTasks().isCallerRecents(sourceUid)) {
+            return true;
+        }
+
+        int perm = checkComponentPermission(STOP_APP_SWITCHES, sourcePid, sourceUid, -1, true);
+        if (perm == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+        if (checkAllowAppSwitchUid(sourceUid)) {
+            return true;
+        }
+
+        // If the actual IPC caller is different from the logical source, then
+        // also see if they are allowed to control app switches.
+        if (callingUid != -1 && callingUid != sourceUid) {
+            perm = checkComponentPermission(STOP_APP_SWITCHES, callingPid, callingUid, -1, true);
+            if (perm == PackageManager.PERMISSION_GRANTED) {
+                return true;
+            }
+            if (checkAllowAppSwitchUid(callingUid)) {
+                return true;
+            }
+        }
+
+        Slog.w(TAG, name + " request from " + sourceUid + " stopped");
+        return false;
+    }
+
+    private boolean checkAllowAppSwitchUid(int uid) {
+        ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(UserHandle.getUserId(uid));
+        if (types != null) {
+            for (int i = types.size() - 1; i >= 0; i--) {
+                if (types.valueAt(i).intValue() == uid) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void setActivityController(IActivityController controller, boolean imAMonkey) {
+        mAmInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+                "setActivityController()");
+        synchronized (mGlobalLock) {
+            mController = controller;
+            mControllerIsAMonkey = imAMonkey;
+            Watchdog.getInstance().setActivityController(controller);
+        }
+    }
+
+    boolean isControllerAMonkey() {
+        synchronized (mGlobalLock) {
+            return mController != null && mControllerIsAMonkey;
+        }
+    }
+
     @Override
     public int getTaskForActivity(IBinder token, boolean onlyRoot) {
         synchronized (mGlobalLock) {
@@ -1525,7 +1798,7 @@
         synchronized (mGlobalLock) {
             if (DEBUG_ALL) Slog.v(TAG, "getTasks: max=" + maxNum);
 
-            final boolean allowed = mAm.isGetTasksAllowed("getTasks", Binder.getCallingPid(),
+            final boolean allowed = isGetTasksAllowed("getTasks", Binder.getCallingPid(),
                     callingUid);
             mStackSupervisor.getRunningTasks(maxNum, list, ignoreActivityType,
                     ignoreWindowingMode, callingUid, allowed);
@@ -1548,7 +1821,7 @@
 
     @Override
     public boolean willActivityBeVisible(IBinder token) {
-        synchronized(this) {
+        synchronized (mGlobalLock) {
             ActivityStack stack = ActivityRecord.getStackLocked(token);
             if (stack != null) {
                 return stack.willActivityBeVisibleLocked(token);
@@ -1559,7 +1832,7 @@
 
     @Override
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
         synchronized (mGlobalLock) {
             final long ident = Binder.clearCallingIdentity();
             try {
@@ -1582,7 +1855,7 @@
                             + taskId + " to stack " + stackId);
                 }
                 if (stack.inSplitScreenPrimaryWindowingMode()) {
-                    mAm.mWindowManager.setDockedStackCreateState(
+                    mWindowManager.setDockedStackCreateState(
                             SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
                 }
                 task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
@@ -1596,7 +1869,7 @@
     @Override
     public void resizeStack(int stackId, Rect destBounds, boolean allowResizeInDockedMode,
             boolean preserveWindows, boolean animate, int animationDuration) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
 
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -1648,7 +1921,7 @@
     @Override
     public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
             boolean toTop, boolean animate, Rect initialBounds, boolean showRecents) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
                 "setTaskWindowingModeSplitScreenPrimary()");
         synchronized (mGlobalLock) {
             final long ident = Binder.clearCallingIdentity();
@@ -1666,7 +1939,7 @@
                             + " non-standard task " + taskId + " to split-screen windowing mode");
                 }
 
-                mAm.mWindowManager.setDockedStackCreateState(createMode, initialBounds);
+                mWindowManager.setDockedStackCreateState(createMode, initialBounds);
                 final int windowingMode = task.getWindowingMode();
                 final ActivityStack stack = task.getStack();
                 if (toTop) {
@@ -1687,7 +1960,7 @@
      */
     @Override
     public void removeStacksInWindowingModes(int[] windowingModes) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
                 "removeStacksInWindowingModes()");
 
         synchronized (mGlobalLock) {
@@ -1702,7 +1975,7 @@
 
     @Override
     public void removeStacksWithActivityTypes(int[] activityTypes) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
                 "removeStacksWithActivityTypes()");
 
         synchronized (mGlobalLock) {
@@ -1719,12 +1992,12 @@
     public ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,
             int userId) {
         final int callingUid = Binder.getCallingUid();
-        userId = mAm.mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
-                false, ALLOW_FULL_ONLY, "getRecentTasks", null);
-        final boolean allowed = mAm.isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
+        userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId, "getRecentTasks");
+        final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
                 callingUid);
-        final boolean detailed = mAm.checkCallingPermission(
-                android.Manifest.permission.GET_DETAILED_TASKS)
+        final boolean detailed = checkGetTasksPermission(
+                android.Manifest.permission.GET_DETAILED_TASKS, Binder.getCallingPid(),
+                UserHandle.getAppId(callingUid))
                 == PackageManager.PERMISSION_GRANTED;
 
         synchronized (mGlobalLock) {
@@ -1735,7 +2008,7 @@
 
     @Override
     public List<ActivityManager.StackInfo> getAllStackInfos() {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getAllStackInfos()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getAllStackInfos()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
@@ -1748,7 +2021,7 @@
 
     @Override
     public ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
@@ -1761,13 +2034,13 @@
 
     @Override
     public void cancelRecentsAnimation(boolean restoreHomeStackPosition) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "cancelRecentsAnimation()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "cancelRecentsAnimation()");
         final long callingUid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
                 // Cancel the recents animation synchronously (do not hold the WM lock)
-                mAm.mWindowManager.cancelRecentsAnimationSynchronously(restoreHomeStackPosition
+                mWindowManager.cancelRecentsAnimationSynchronously(restoreHomeStackPosition
                         ? REORDER_MOVE_TO_ORIGINAL_POSITION
                         : REORDER_KEEP_IN_PLACE, "cancelRecentsAnimation/uid=" + callingUid);
             }
@@ -1789,7 +2062,7 @@
 
     @Override
     public void startSystemLockTaskMode(int taskId) throws RemoteException {
-        mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startSystemLockTaskMode");
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startSystemLockTaskMode");
         // This makes inner call to look as if it was initiated by system.
         long ident = Binder.clearCallingIdentity();
         try {
@@ -1822,7 +2095,7 @@
      */
     @Override
     public void stopSystemLockTaskMode() throws RemoteException {
-        mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopSystemLockTaskMode");
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopSystemLockTaskMode");
         stopLockTaskModeInternal(null, true /* isSystemCaller */);
     }
 
@@ -1979,7 +2252,7 @@
     @Override
     public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure,
             AssistContent content, Uri referrer) {
-        PendingAssistExtras pae = (PendingAssistExtras)token;
+        PendingAssistExtras pae = (PendingAssistExtras) token;
         synchronized (pae) {
             pae.result = extras;
             pae.structure = structure;
@@ -2003,13 +2276,13 @@
         synchronized (mGlobalLock) {
             buildAssistBundleLocked(pae, extras);
             boolean exists = mPendingAssistExtras.remove(pae);
-            mAm.mUiHandler.removeCallbacks(pae);
+            mUiHandler.removeCallbacks(pae);
             if (!exists) {
                 // Timed out.
                 return;
             }
 
-            if ((sendReceiver=pae.receiver) != null) {
+            if ((sendReceiver = pae.receiver) != null) {
                 // Caller wants result sent back to them.
                 sendBundle = new Bundle();
                 sendBundle.putBundle(ASSIST_KEY_DATA, pae.extras);
@@ -2037,7 +2310,7 @@
                 pae.intent.setFlags(FLAG_ACTIVITY_NEW_TASK
                         | Intent.FLAG_ACTIVITY_SINGLE_TOP
                         | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                mAm.closeSystemDialogs("assist");
+                mAmInternal.closeSystemDialogs("assist");
 
                 try {
                     mContext.startActivityAsUser(pae.intent, new UserHandle(pae.userHandle));
@@ -2068,11 +2341,11 @@
                     throw new IllegalArgumentException("Intent " + intent
                             + " must specify explicit component");
                 }
-                if (thumbnail.getWidth() != mAm.mThumbnailWidth
-                        || thumbnail.getHeight() != mAm.mThumbnailHeight) {
+                if (thumbnail.getWidth() != mThumbnailWidth
+                        || thumbnail.getHeight() != mThumbnailHeight) {
                     throw new IllegalArgumentException("Bad thumbnail size: got "
                             + thumbnail.getWidth() + "x" + thumbnail.getHeight() + ", require "
-                            + mAm.mThumbnailWidth + "x" + mAm.mThumbnailHeight);
+                            + mThumbnailWidth + "x" + mThumbnailHeight);
                 }
                 if (intent.getSelector() != null) {
                     intent.setSelector(null);
@@ -2118,7 +2391,7 @@
     @Override
     public Point getAppTaskThumbnailSize() {
         synchronized (mGlobalLock) {
-            return new Point(mAm.mThumbnailWidth,  mAm.mThumbnailHeight);
+            return new Point(mThumbnailWidth, mThumbnailHeight);
         }
     }
 
@@ -2137,7 +2410,7 @@
 
     @Override
     public void resizeTask(int taskId, Rect bounds, int resizeMode) {
-        mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeTask()");
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeTask()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
@@ -2215,7 +2488,7 @@
     @Override
     public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing,
             int secondaryDisplayShowing) {
-        if (mAm.checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
+        if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
                     + android.Manifest.permission.DEVICE_POWER);
@@ -2235,14 +2508,25 @@
             }
         }
 
-        mAm.mHandler.obtainMessage(DISPATCH_SCREEN_KEYGUARD_MSG, keyguardShowing ? 1 : 0, 0)
-                .sendToTarget();
+        mH.post(() -> {
+            for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
+                mScreenObservers.get(i).onKeyguardStateChanged(keyguardShowing);
+            }
+        });
+    }
+
+    void onScreenAwakeChanged(boolean isAwake) {
+        mH.post(() -> {
+            for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
+                mScreenObservers.get(i).onAwakeStateChanged(isAwake);
+            }
+        });
     }
 
     @Override
     public Bitmap getTaskDescriptionIcon(String filePath, int userId) {
-        userId = mAm.mUserController.handleIncomingUser(Binder.getCallingPid(),
-                Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "getTaskDescriptionIcon", null);
+        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, "getTaskDescriptionIcon");
 
         final File passedIconFile = new File(filePath);
         final File legitIconFile = new File(TaskPersister.getUserImagesDir(userId),
@@ -2256,8 +2540,7 @@
     }
 
     @Override
-    public void startInPlaceAnimationOnFrontMostApplication(Bundle opts)
-            throws RemoteException {
+    public void startInPlaceAnimationOnFrontMostApplication(Bundle opts) {
         final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(opts);
         final ActivityOptions activityOptions = safeOptions != null
                 ? safeOptions.getOptions(mStackSupervisor)
@@ -2268,15 +2551,15 @@
             throw new IllegalArgumentException("Expected in-place ActivityOption " +
                     "with valid animation");
         }
-        mAm.mWindowManager.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
-        mAm.mWindowManager.overridePendingAppTransitionInPlace(activityOptions.getPackageName(),
+        mWindowManager.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
+        mWindowManager.overridePendingAppTransitionInPlace(activityOptions.getPackageName(),
                 activityOptions.getCustomInPlaceResId());
-        mAm.mWindowManager.executeAppTransition();
+        mWindowManager.executeAppTransition();
     }
 
     @Override
     public void removeStack(int stackId) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "removeStack()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "removeStack()");
         synchronized (mGlobalLock) {
             final long ident = Binder.clearCallingIdentity();
             try {
@@ -2298,7 +2581,7 @@
 
     @Override
     public void moveStackToDisplay(int stackId, int displayId) {
-        mAm.enforceCallingPermission(INTERNAL_SYSTEM_WINDOW, "moveStackToDisplay()");
+        mAmInternal.enforceCallingPermission(INTERNAL_SYSTEM_WINDOW, "moveStackToDisplay()");
 
         synchronized (mGlobalLock) {
             final long ident = Binder.clearCallingIdentity();
@@ -2314,7 +2597,7 @@
 
     @Override
     public int createStackOnDisplay(int displayId) {
-        mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createStackOnDisplay()");
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createStackOnDisplay()");
         synchronized (mGlobalLock) {
             final ActivityDisplay display =
                     mStackSupervisor.getActivityDisplayOrCreateLocked(displayId);
@@ -2356,7 +2639,7 @@
     /** Sets the task stack listener that gets callbacks when a task stack changes. */
     @Override
     public void registerTaskStackListener(ITaskStackListener listener) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
                 "registerTaskStackListener()");
         mTaskChangeNotificationController.registerTaskStackListener(listener);
     }
@@ -2364,7 +2647,7 @@
     /** Unregister a task stack listener so that it stops receiving callbacks. */
     @Override
     public void unregisterTaskStackListener(ITaskStackListener listener) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
                 "unregisterTaskStackListener()");
         mTaskChangeNotificationController.unregisterTaskStackListener(listener);
     }
@@ -2418,20 +2701,78 @@
         synchronized (mGlobalLock) {
             buildAssistBundleLocked(pae, pae.result);
             mPendingAssistExtras.remove(pae);
-            mAm.mUiHandler.removeCallbacks(pae);
+            mUiHandler.removeCallbacks(pae);
         }
         return pae.extras;
     }
 
+    /**
+     * Binder IPC calls go through the public entry point.
+     * This can be called with or without the global lock held.
+     */
+    private static int checkCallingPermission(String permission) {
+        return checkPermission(
+                permission, Binder.getCallingPid(), UserHandle.getAppId(Binder.getCallingUid()));
+    }
+
+    /** This can be called with or without the global lock held. */
+    void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
+        if (!getRecentTasks().isCallerRecents(Binder.getCallingUid())) {
+            mAmInternal.enforceCallingPermission(permission, func);
+        }
+    }
+
+    @VisibleForTesting
+    int checkGetTasksPermission(String permission, int pid, int uid) {
+        return checkPermission(permission, pid, uid);
+    }
+
+    static int checkPermission(String permission, int pid, int uid) {
+        if (permission == null) {
+            return PackageManager.PERMISSION_DENIED;
+        }
+        return checkComponentPermission(permission, pid, uid, -1, true);
+    }
+
+    boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
+        if (getRecentTasks().isCallerRecents(callingUid)) {
+            // Always allow the recents component to get tasks
+            return true;
+        }
+
+        boolean allowed = checkGetTasksPermission(android.Manifest.permission.REAL_GET_TASKS,
+                callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
+        if (!allowed) {
+            if (checkGetTasksPermission(android.Manifest.permission.GET_TASKS,
+                    callingPid, callingUid) == PackageManager.PERMISSION_GRANTED) {
+                // Temporary compatibility: some existing apps on the system image may
+                // still be requesting the old permission and not switched to the new
+                // one; if so, we'll still allow them full access.  This means we need
+                // to see if they are holding the old permission and are a system app.
+                try {
+                    if (AppGlobals.getPackageManager().isUidPrivileged(callingUid)) {
+                        allowed = true;
+                        if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
+                                + " is using old GET_TASKS but privileged; allowing");
+                    }
+                } catch (RemoteException e) {
+                }
+            }
+            if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
+                    + " does not hold REAL_GET_TASKS; limiting output");
+        }
+        return allowed;
+    }
+
     private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
             IAssistDataReceiver receiver, Bundle receiverExtras, IBinder activityToken,
             boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout,
             int flags) {
-        mAm.enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
+        mAmInternal.enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
                 "enqueueAssistContext()");
 
         synchronized (mGlobalLock) {
-            ActivityRecord activity = mAm.getFocusedStack().getTopActivity();
+            ActivityRecord activity = getFocusedStack().getTopActivity();
             if (activity == null) {
                 Slog.w(TAG, "getAssistContextExtras failed: no top activity");
                 return null;
@@ -2482,7 +2823,7 @@
                 activity.app.thread.requestAssistContextExtras(activity.appToken, pae, requestType,
                         mViSessionId, flags);
                 mPendingAssistExtras.add(pae);
-                mAm.mUiHandler.postDelayed(pae, timeout);
+                mUiHandler.postDelayed(pae, timeout);
             } catch (RemoteException e) {
                 Slog.w(TAG, "getAssistContextExtras failed: crash calling " + activity);
                 return null;
@@ -2559,7 +2900,7 @@
     public boolean isAssistDataAllowedOnCurrentActivity() {
         int userId;
         synchronized (mGlobalLock) {
-            final ActivityStack focusedStack = mAm.getFocusedStack();
+            final ActivityStack focusedStack = getFocusedStack();
             if (focusedStack == null || focusedStack.isActivityTypeAssistant()) {
                 return false;
             }
@@ -2579,7 +2920,7 @@
         try {
             synchronized (mGlobalLock) {
                 ActivityRecord caller = ActivityRecord.forTokenLocked(token);
-                ActivityRecord top = mAm.getFocusedStack().getTopActivity();
+                ActivityRecord top = getFocusedStack().getTopActivity();
                 if (top != caller) {
                     Slog.w(TAG, "showAssistFromActivity failed: caller " + caller
                             + " is not current top " + top);
@@ -2644,7 +2985,7 @@
 
     @Override
     public void keyguardGoingAway(int flags) {
-        mAm.enforceNotIsolatedCaller("keyguardGoingAway");
+        enforceNotIsolatedCaller("keyguardGoingAway");
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
@@ -2662,7 +3003,7 @@
      */
     @Override
     public void positionTaskInStack(int taskId, int stackId, int position) {
-        mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
         synchronized (mGlobalLock) {
             long ident = Binder.clearCallingIdentity();
             try {
@@ -2723,7 +3064,7 @@
      */
     @Override
     public void dismissSplitScreenMode(boolean toTop) {
-        mAm.enforceCallerIsRecentsOrHasPermission(
+        enforceCallerIsRecentsOrHasPermission(
                 MANAGE_ACTIVITY_STACKS, "dismissSplitScreenMode()");
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -2765,7 +3106,7 @@
      */
     @Override
     public void dismissPip(boolean animate, int animationDuration) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "dismissPip()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "dismissPip()");
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
@@ -2793,7 +3134,7 @@
 
     @Override
     public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
-        mAm.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "suppressResizeConfigChanges()");
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "suppressResizeConfigChanges()");
         synchronized (mGlobalLock) {
             mSuppressResizeConfigChanges = suppress;
         }
@@ -2807,7 +3148,7 @@
     @Override
     // TODO: API should just be about changing windowing modes...
     public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
                 "moveTasksToFullscreenStack()");
         synchronized (mGlobalLock) {
             final long origId = Binder.clearCallingIdentity();
@@ -2837,10 +3178,10 @@
      */
     @Override
     public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
                 "moveTopActivityToPinnedStack()");
         synchronized (mGlobalLock) {
-            if (!mAm.mSupportsPictureInPicture) {
+            if (!mSupportsPictureInPicture) {
                 throw new IllegalStateException("moveTopActivityToPinnedStack:"
                         + "Device doesn't support picture-in-picture mode");
             }
@@ -2942,8 +3283,8 @@
                     // device is currently locked).
                     dismissKeyguard(token, new KeyguardDismissCallback() {
                         @Override
-                        public void onDismissSucceeded() throws RemoteException {
-                            mAm.mHandler.post(enterPipRunnable);
+                        public void onDismissSucceeded() {
+                            mH.post(enterPipRunnable);
                         }
                     }, null /* message */);
                 } else {
@@ -3012,7 +3353,7 @@
      */
     private ActivityRecord ensureValidPictureInPictureActivityParamsLocked(String caller,
             IBinder token, PictureInPictureParams params) {
-        if (!mAm.mSupportsPictureInPicture) {
+        if (!mSupportsPictureInPicture) {
             throw new IllegalStateException(caller
                     + ": Device doesn't support picture-in-picture mode.");
         }
@@ -3029,7 +3370,7 @@
         }
 
         if (params.hasSetAspectRatio()
-                && !mAm.mWindowManager.isValidPictureInPictureAspectRatio(r.getStack().mDisplayId,
+                && !mWindowManager.isValidPictureInPictureAspectRatio(r.getStack().mDisplayId,
                 params.getAspectRatio())) {
             final float minAspectRatio = mContext.getResources().getFloat(
                     com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
@@ -3048,7 +3389,7 @@
 
     @Override
     public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) {
-        mAm.enforceNotIsolatedCaller("getUriPermissionOwnerForActivity");
+        enforceNotIsolatedCaller("getUriPermissionOwnerForActivity");
         synchronized (mGlobalLock) {
             ActivityRecord r = ActivityRecord.isInStackLocked(activityToken);
             if (r == null) {
@@ -3063,7 +3404,7 @@
     public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
             Rect tempDockedTaskInsetBounds,
             Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizeDockedStack()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizeDockedStack()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
@@ -3078,7 +3419,7 @@
 
     @Override
     public void setSplitScreenResizing(boolean resizing) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setSplitScreenResizing()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setSplitScreenResizing()");
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
@@ -3089,9 +3430,20 @@
         }
     }
 
+    /**
+     * Check that we have the features required for VR-related API calls, and throw an exception if
+     * not.
+     */
+    void enforceSystemHasVrFeature() {
+        if (!mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
+            throw new UnsupportedOperationException("VR mode not supported on this device!");
+        }
+    }
+
     @Override
     public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) {
-        mAm.enforceSystemHasVrFeature();
+        enforceSystemHasVrFeature();
 
         final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
 
@@ -3131,7 +3483,7 @@
     public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) {
         Slog.i(TAG, "Activity tried to startLocalVoiceInteraction");
         synchronized (mGlobalLock) {
-            ActivityRecord activity = mAm.getFocusedStack().getTopActivity();
+            ActivityRecord activity = getFocusedStack().getTopActivity();
             if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
                 throw new SecurityException("Only focused activity can call startVoiceInteraction");
             }
@@ -3176,7 +3528,7 @@
 
     @Override
     public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizePinnedStack()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizePinnedStack()");
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
@@ -3189,7 +3541,7 @@
 
     @Override
     public boolean updateDisplayOverrideConfiguration(Configuration values, int displayId) {
-        mAm.enforceCallingPermission(CHANGE_CONFIGURATION, "updateDisplayOverrideConfiguration()");
+        mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateDisplayOverrideConfiguration()");
 
         synchronized (mGlobalLock) {
             // Check if display is initialized in AM.
@@ -3202,14 +3554,14 @@
                 return false;
             }
 
-            if (values == null && mAm.mWindowManager != null) {
+            if (values == null && mWindowManager != null) {
                 // sentinel: fetch the current configuration from the window manager
-                values = mAm.mWindowManager.computeNewConfiguration(displayId);
+                values = mWindowManager.computeNewConfiguration(displayId);
             }
 
-            if (mAm.mWindowManager != null) {
+            if (mWindowManager != null) {
                 // Update OOM levels based on display size.
-                mAm.mProcessList.applyDisplaySize(mAm.mWindowManager);
+                mAm.mProcessList.applyDisplaySize(mWindowManager);
             }
 
             final long origId = Binder.clearCallingIdentity();
@@ -3217,7 +3569,7 @@
                 if (values != null) {
                     Settings.System.clearConfiguration(values);
                 }
-                mAm.updateDisplayOverrideConfigurationLocked(values, null /* starting */,
+                updateDisplayOverrideConfigurationLocked(values, null /* starting */,
                         false /* deferResume */, displayId, mTmpUpdateConfigurationResult);
                 return mTmpUpdateConfigurationResult.changes != 0;
             } finally {
@@ -3228,17 +3580,17 @@
 
     @Override
     public boolean updateConfiguration(Configuration values) {
-        mAm.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()");
+        mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()");
 
         synchronized (mGlobalLock) {
-            if (values == null && mAm.mWindowManager != null) {
+            if (values == null && mWindowManager != null) {
                 // sentinel: fetch the current configuration from the window manager
-                values = mAm.mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY);
+                values = mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY);
             }
 
-            if (mAm.mWindowManager != null) {
+            if (mWindowManager != null) {
                 // Update OOM levels based on display size.
-                mAm.mProcessList.applyDisplaySize(mAm.mWindowManager);
+                mAm.mProcessList.applyDisplaySize(mWindowManager);
             }
 
             final long origId = Binder.clearCallingIdentity();
@@ -3246,7 +3598,7 @@
                 if (values != null) {
                     Settings.System.clearConfiguration(values);
                 }
-                mAm.updateConfigurationLocked(values, null, false, false /* persistent */,
+                updateConfigurationLocked(values, null, false, false /* persistent */,
                         UserHandle.USER_NULL, false /* deferResume */,
                         mTmpUpdateConfigurationResult);
                 return mTmpUpdateConfigurationResult.changes != 0;
@@ -3260,7 +3612,7 @@
     public void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback,
             CharSequence message) {
         if (message != null) {
-            mAm.enforceCallingPermission(
+            mAmInternal.enforceCallingPermission(
                     Manifest.permission.SHOW_KEYGUARD_MESSAGE, "dismissKeyguard()");
         }
         final long callingId = Binder.clearCallingIdentity();
@@ -3275,7 +3627,7 @@
 
     @Override
     public void cancelTaskWindowTransition(int taskId) {
-        mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
                 "cancelTaskWindowTransition()");
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -3295,7 +3647,7 @@
 
     @Override
     public ActivityManager.TaskSnapshot getTaskSnapshot(int taskId, boolean reducedResolution) {
-        mAm.enforceCallerIsRecentsOrHasPermission(READ_FRAME_BUFFER, "getTaskSnapshot()");
+        enforceCallerIsRecentsOrHasPermission(READ_FRAME_BUFFER, "getTaskSnapshot()");
         final long ident = Binder.clearCallingIdentity();
         try {
             final TaskRecord task;
@@ -3336,11 +3688,11 @@
     @Override
     public @UserIdInt
     int getLastResumedActivityUserId() {
-        mAm.enforceCallingPermission(
+        mAmInternal.enforceCallingPermission(
                 Manifest.permission.INTERACT_ACROSS_USERS_FULL, "getLastResumedActivityUserId()");
         synchronized (mGlobalLock) {
             if (mAm.mLastResumedActivity == null) {
-                return mAm.mUserController.getCurrentUserId();
+                return getCurrentUserId();
             }
             return mAm.mLastResumedActivity.userId;
         }
@@ -3350,7 +3702,7 @@
     public void updateLockTaskFeatures(int userId, int flags) {
         final int callingUid = Binder.getCallingUid();
         if (callingUid != 0 && callingUid != SYSTEM_UID) {
-            mAm.enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
+            mAmInternal.enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
                     "updateLockTaskFeatures()");
         }
         synchronized (mGlobalLock) {
@@ -3394,7 +3746,7 @@
 
     @Override
     public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) {
-        mAm.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+        mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
                 "registerRemoteAnimations");
         definition.setCallingPid(Binder.getCallingPid());
         synchronized (mGlobalLock) {
@@ -3414,7 +3766,7 @@
     @Override
     public void registerRemoteAnimationForNextActivityStart(String packageName,
             RemoteAnimationAdapter adapter) {
-        mAm.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+        mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
                 "registerRemoteAnimationForNextActivityStart");
         adapter.setCallingPid(Binder.getCallingPid());
         synchronized (mGlobalLock) {
@@ -3443,7 +3795,7 @@
 
     @Override
     public void setVrThread(int tid) {
-        mAm.enforceSystemHasVrFeature();
+        enforceSystemHasVrFeature();
         synchronized (mGlobalLock) {
             synchronized (mAm.mPidsSelfLocked) {
                 final int pid = Binder.getCallingPid();
@@ -3455,7 +3807,7 @@
 
     @Override
     public void setPersistentVrThread(int tid) {
-        if (mAm.checkCallingPermission(Manifest.permission.RESTRICTED_VR_ACCESS)
+        if (checkCallingPermission(Manifest.permission.RESTRICTED_VR_ACCESS)
                 != PERMISSION_GRANTED) {
             final String msg = "Permission Denial: setPersistentVrThread() from pid="
                     + Binder.getCallingPid()
@@ -3464,7 +3816,7 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        mAm.enforceSystemHasVrFeature();
+        enforceSystemHasVrFeature();
         synchronized (mGlobalLock) {
             synchronized (mAm.mPidsSelfLocked) {
                 final int pid = Binder.getCallingPid();
@@ -3474,9 +3826,41 @@
         }
     }
 
-    /**
-     * @return whether the system should disable UI modes incompatible with VR mode.
-     */
+    @Override
+    public void stopAppSwitches() {
+        enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "stopAppSwitches");
+        synchronized (mGlobalLock) {
+            mAppSwitchesAllowedTime = SystemClock.uptimeMillis() + APP_SWITCH_DELAY_TIME;
+            mDidAppSwitch = false;
+            getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME);
+        }
+    }
+
+    @Override
+    public void resumeAppSwitches() {
+        enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "resumeAppSwitches");
+        synchronized (mGlobalLock) {
+            // Note that we don't execute any pending app switches... we will
+            // let those wait until either the timeout, or the next start
+            // activity request.
+            mAppSwitchesAllowedTime = 0;
+        }
+    }
+
+    void onStartActivitySetDidAppSwitch() {
+        if (mDidAppSwitch) {
+            // This is the second allowed switch since we stopped switches, so now just generally
+            // allow switches. Use case:
+            // - user presses home (switches disabled, switch to home, mDidAppSwitch now true);
+            // - user taps a home icon (coming from home so allowed, we hit here and now allow
+            // anyone to switch again).
+            mAppSwitchesAllowedTime = 0;
+        } else {
+            mDidAppSwitch = true;
+        }
+    }
+
+    /** @return whether the system should disable UI modes incompatible with VR mode. */
     boolean shouldDisableNonVrUiLocked() {
         return mVrController.shouldDisableNonVrUiLocked();
     }
@@ -3512,6 +3896,10 @@
         });
     }
 
+    ActivityStack getFocusedStack() {
+        return mStackSupervisor.getFocusedStack();
+    }
+
     /** Pokes the task persister. */
     void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
         mRecentTasks.notifyTaskPersisterLocked(task, flush);
@@ -3540,12 +3928,398 @@
         mVrController.writeToProto(proto, fieldId);
     }
 
+    int getCurrentUserId() {
+        return mAmInternal.getCurrentUserId();
+    }
+
+    private void enforceNotIsolatedCaller(String caller) {
+        if (UserHandle.isIsolated(Binder.getCallingUid())) {
+            throw new SecurityException("Isolated process not allowed to call " + caller);
+        }
+    }
+
+    /**
+     * Current global configuration information. Contains general settings for the entire system,
+     * also corresponds to the merged configuration of the default display.
+     */
+    Configuration getGlobalConfiguration() {
+        return mStackSupervisor.getConfiguration();
+    }
+
+    boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+            boolean initLocale) {
+        return updateConfigurationLocked(values, starting, initLocale, false /* deferResume */);
+    }
+
+    boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+            boolean initLocale, boolean deferResume) {
+        // pass UserHandle.USER_NULL as userId because we don't persist configuration for any user
+        return updateConfigurationLocked(values, starting, initLocale, false /* persistent */,
+                UserHandle.USER_NULL, deferResume);
+    }
+
+    void updatePersistentConfiguration(Configuration values, @UserIdInt int userId) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                updateConfigurationLocked(values, null, false, true, userId,
+                        false /* deferResume */);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    void updateUserConfiguration() {
+        synchronized (mGlobalLock) {
+            final Configuration configuration = new Configuration(getGlobalConfiguration());
+            final int currentUserId = mAmInternal.getCurrentUserId();
+            Settings.System.adjustConfigurationForUser(mContext.getContentResolver(), configuration,
+                    currentUserId, Settings.System.canWrite(mContext));
+            updateConfigurationLocked(configuration, null /* starting */, false /* initLocale */,
+                    false /* persistent */, currentUserId, false /* deferResume */);
+        }
+    }
+
+    private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+            boolean initLocale, boolean persistent, int userId, boolean deferResume) {
+        return updateConfigurationLocked(values, starting, initLocale, persistent, userId,
+                deferResume, null /* result */);
+    }
+
+    /**
+     * Do either or both things: (1) change the current configuration, and (2)
+     * make sure the given activity is running with the (now) current
+     * configuration.  Returns true if the activity has been left running, or
+     * false if <var>starting</var> is being destroyed to match the new
+     * configuration.
+     *
+     * @param userId is only used when persistent parameter is set to true to persist configuration
+     *               for that particular user
+     */
+    boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+            boolean initLocale, boolean persistent, int userId, boolean deferResume,
+            ActivityTaskManagerService.UpdateConfigurationResult result) {
+        int changes = 0;
+        boolean kept = true;
+
+        if (mWindowManager != null) {
+            mWindowManager.deferSurfaceLayout();
+        }
+        try {
+            if (values != null) {
+                changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId,
+                        deferResume);
+            }
+
+            kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
+        } finally {
+            if (mWindowManager != null) {
+                mWindowManager.continueSurfaceLayout();
+            }
+        }
+
+        if (result != null) {
+            result.changes = changes;
+            result.activityRelaunched = !kept;
+        }
+        return kept;
+    }
+
+    /**
+     * Returns true if this configuration change is interesting enough to send an
+     * {@link Intent#ACTION_SPLIT_CONFIGURATION_CHANGED} broadcast.
+     */
+    private static boolean isSplitConfigurationChange(int configDiff) {
+        return (configDiff & (ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_DENSITY)) != 0;
+    }
+
+    /** Update default (global) configuration and notify listeners about changes. */
+    private int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
+            boolean persistent, int userId, boolean deferResume) {
+        mTempConfig.setTo(getGlobalConfiguration());
+        final int changes = mTempConfig.updateFrom(values);
+        if (changes == 0) {
+            // Since calling to Activity.setRequestedOrientation leads to freezing the window with
+            // setting WindowManagerService.mWaitingForConfig to true, it is important that we call
+            // performDisplayOverrideConfigUpdate in order to send the new display configuration
+            // (even if there are no actual changes) to unfreeze the window.
+            performDisplayOverrideConfigUpdate(values, deferResume, DEFAULT_DISPLAY);
+            return 0;
+        }
+
+        if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
+                "Updating global configuration to: " + values);
+
+        EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
+        StatsLog.write(StatsLog.RESOURCE_CONFIGURATION_CHANGED,
+                values.colorMode,
+                values.densityDpi,
+                values.fontScale,
+                values.hardKeyboardHidden,
+                values.keyboard,
+                values.keyboardHidden,
+                values.mcc,
+                values.mnc,
+                values.navigation,
+                values.navigationHidden,
+                values.orientation,
+                values.screenHeightDp,
+                values.screenLayout,
+                values.screenWidthDp,
+                values.smallestScreenWidthDp,
+                values.touchscreen,
+                values.uiMode);
+
+
+        if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
+            final LocaleList locales = values.getLocales();
+            int bestLocaleIndex = 0;
+            if (locales.size() > 1) {
+                if (mSupportedSystemLocales == null) {
+                    mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
+                }
+                bestLocaleIndex = Math.max(0, locales.getFirstMatchIndex(mSupportedSystemLocales));
+            }
+            SystemProperties.set("persist.sys.locale",
+                    locales.get(bestLocaleIndex).toLanguageTag());
+            LocaleList.setDefault(locales, bestLocaleIndex);
+            mAm.mHandler.sendMessage(mAm.mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
+                    locales.get(bestLocaleIndex)));
+        }
+
+        mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
+        mTempConfig.seq = mConfigurationSeq;
+
+        // Update stored global config and notify everyone about the change.
+        mStackSupervisor.onConfigurationChanged(mTempConfig);
+
+        Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempConfig);
+        // TODO(multi-display): Update UsageEvents#Event to include displayId.
+        mAm.mUsageStatsService.reportConfigurationChange(
+                mTempConfig, mAmInternal.getCurrentUserId());
+
+        // TODO: If our config changes, should we auto dismiss any currently showing dialogs?
+        mAm.updateShouldShowDialogsLocked(mTempConfig);
+
+        AttributeCache ac = AttributeCache.instance();
+        if (ac != null) {
+            ac.updateConfiguration(mTempConfig);
+        }
+
+        // Make sure all resources in our process are updated right now, so that anyone who is going
+        // to retrieve resource values after we return will be sure to get the new ones. This is
+        // especially important during boot, where the first config change needs to guarantee all
+        // resources have that config before following boot code is executed.
+        mAm.mSystemThread.applyConfigurationToResources(mTempConfig);
+
+        // We need another copy of global config because we're scheduling some calls instead of
+        // running them in place. We need to be sure that object we send will be handled unchanged.
+        final Configuration configCopy = new Configuration(mTempConfig);
+        if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
+            Message msg = mAm.mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
+            msg.obj = configCopy;
+            msg.arg1 = userId;
+            mAm.mHandler.sendMessage(msg);
+        }
+
+        for (int i = mAm.mLruProcesses.size() - 1; i >= 0; i--) {
+            ProcessRecord app = mAm.mLruProcesses.get(i);
+            try {
+                if (app.thread != null) {
+                    if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
+                            + app.processName + " new config " + configCopy);
+                    getLifecycleManager().scheduleTransaction(app.thread,
+                            ConfigurationChangeItem.obtain(configCopy));
+                }
+            } catch (Exception e) {
+                Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);
+            }
+        }
+
+        Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_REPLACE_PENDING
+                | Intent.FLAG_RECEIVER_FOREGROUND
+                | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+        mAm.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+                OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+                UserHandle.USER_ALL);
+        if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
+            intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
+            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
+                    | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+            if (initLocale || !mAm.mProcessesReady) {
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            }
+            mAm.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+                    OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+                    UserHandle.USER_ALL);
+        }
+
+        // Send a broadcast to PackageInstallers if the configuration change is interesting
+        // for the purposes of installing additional splits.
+        if (!initLocale && isSplitConfigurationChange(changes)) {
+            intent = new Intent(Intent.ACTION_SPLIT_CONFIGURATION_CHANGED);
+            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+
+            // Typically only app stores will have this permission.
+            String[] permissions = new String[] { android.Manifest.permission.INSTALL_PACKAGES };
+            mAm.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, permissions,
+                    OP_NONE, null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+        }
+
+        // Override configuration of the default display duplicates global config, so we need to
+        // update it also. This will also notify WindowManager about changes.
+        performDisplayOverrideConfigUpdate(mStackSupervisor.getConfiguration(), deferResume,
+                DEFAULT_DISPLAY);
+
+        return changes;
+    }
+
+    boolean updateDisplayOverrideConfigurationLocked(Configuration values, ActivityRecord starting,
+            boolean deferResume, int displayId) {
+        return updateDisplayOverrideConfigurationLocked(values, starting, deferResume /* deferResume */,
+                displayId, null /* result */);
+    }
+
+    /**
+     * Updates override configuration specific for the selected display. If no config is provided,
+     * new one will be computed in WM based on current display info.
+     */
+    boolean updateDisplayOverrideConfigurationLocked(Configuration values,
+            ActivityRecord starting, boolean deferResume, int displayId,
+            ActivityTaskManagerService.UpdateConfigurationResult result) {
+        int changes = 0;
+        boolean kept = true;
+
+        if (mWindowManager != null) {
+            mWindowManager.deferSurfaceLayout();
+        }
+        try {
+            if (values != null) {
+                if (displayId == DEFAULT_DISPLAY) {
+                    // Override configuration of the default display duplicates global config, so
+                    // we're calling global config update instead for default display. It will also
+                    // apply the correct override config.
+                    changes = updateGlobalConfigurationLocked(values, false /* initLocale */,
+                            false /* persistent */, UserHandle.USER_NULL /* userId */, deferResume);
+                } else {
+                    changes = performDisplayOverrideConfigUpdate(values, deferResume, displayId);
+                }
+            }
+
+            kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
+        } finally {
+            if (mWindowManager != null) {
+                mWindowManager.continueSurfaceLayout();
+            }
+        }
+
+        if (result != null) {
+            result.changes = changes;
+            result.activityRelaunched = !kept;
+        }
+        return kept;
+    }
+
+    private int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume,
+            int displayId) {
+        mTempConfig.setTo(mStackSupervisor.getDisplayOverrideConfiguration(displayId));
+        final int changes = mTempConfig.updateFrom(values);
+        if (changes != 0) {
+            Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
+                    + mTempConfig + " for displayId=" + displayId);
+            mStackSupervisor.setDisplayOverrideConfiguration(mTempConfig, displayId);
+
+            final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
+            if (isDensityChange && displayId == DEFAULT_DISPLAY) {
+                mAm.mAppWarnings.onDensityChanged();
+
+                mAm.killAllBackgroundProcessesExcept(N,
+                        ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
+            }
+        }
+
+        // Update the configuration with WM first and check if any of the stacks need to be resized
+        // due to the configuration change. If so, resize the stacks now and do any relaunches if
+        // necessary. This way we don't need to relaunch again afterwards in
+        // ensureActivityConfiguration().
+        if (mWindowManager != null) {
+            final int[] resizedStacks =
+                    mWindowManager.setNewDisplayOverrideConfiguration(mTempConfig, displayId);
+            if (resizedStacks != null) {
+                for (int stackId : resizedStacks) {
+                    resizeStackWithBoundsFromWindowManager(stackId, deferResume);
+                }
+            }
+        }
+
+        return changes;
+    }
+
+    /** Helper method that requests bounds from WM and applies them to stack. */
+    private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) {
+        final Rect newStackBounds = new Rect();
+        final ActivityStack stack = mStackSupervisor.getStack(stackId);
+
+        // TODO(b/71548119): Revert CL introducing below once cause of mismatch is found.
+        if (stack == null) {
+            final StringWriter writer = new StringWriter();
+            final PrintWriter printWriter = new PrintWriter(writer);
+            mStackSupervisor.dumpDisplays(printWriter);
+            printWriter.flush();
+
+            Log.wtf(TAG, "stack not found:" + stackId + " displays:" + writer);
+        }
+
+        stack.getBoundsForNewConfiguration(newStackBounds);
+        mStackSupervisor.resizeStackLocked(
+                stack, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */,
+                null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+                false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume);
+    }
+
+    /** Applies latest configuration and/or visibility updates if needed. */
+    private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {
+        boolean kept = true;
+        final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
+        // mainStack is null during startup.
+        if (mainStack != null) {
+            if (changes != 0 && starting == null) {
+                // If the configuration changed, and the caller is not already
+                // in the process of starting an activity, then find the top
+                // activity to check if its configuration needs to change.
+                starting = mainStack.topRunningActivityLocked();
+            }
+
+            if (starting != null) {
+                kept = starting.ensureActivityConfiguration(changes,
+                        false /* preserveWindow */);
+                // And we need to make sure at this point that all other activities
+                // are made visible with the correct configuration.
+                mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes,
+                        !PRESERVE_WINDOWS);
+            }
+        }
+
+        return kept;
+    }
+
     final class H extends Handler {
         public H(Looper looper) {
             super(looper, null, true);
         }
     }
 
+    final class UiHandler extends Handler {
+
+        public UiHandler() {
+            super(com.android.server.UiThread.get().getLooper(), null, true);
+        }
+    }
+
     final class LocalService extends ActivityTaskManagerInternal {
         @Override
         public SleepToken acquireSleepToken(String tag, int displayId) {
@@ -3657,9 +4431,9 @@
                 // We might change the visibilities here, so prepare an empty app transition which
                 // might be overridden later if we actually change visibilities.
                 final boolean wasTransitionSet =
-                        mAm.mWindowManager.getPendingAppTransition() != TRANSIT_NONE;
+                        mWindowManager.getPendingAppTransition() != TRANSIT_NONE;
                 if (!wasTransitionSet) {
-                    mAm.mWindowManager.prepareAppTransition(TRANSIT_NONE,
+                    mWindowManager.prepareAppTransition(TRANSIT_NONE,
                             false /* alwaysKeepCurrent */);
                 }
                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
@@ -3667,7 +4441,7 @@
                 // If there was a transition set already we don't want to interfere with it as we
                 // might be starting it too early.
                 if (!wasTransitionSet) {
-                    mAm.mWindowManager.executeAppTransition();
+                    mWindowManager.executeAppTransition();
                 }
             }
             if (callback != null) {
@@ -3693,7 +4467,7 @@
         public void setVr2dDisplayId(int vr2dDisplayId) {
             if (DEBUG_STACK) Slog.d(TAG, "setVr2dDisplayId called for: " + vr2dDisplayId);
             synchronized (mGlobalLock) {
-                mAm.mVr2dDisplayId = vr2dDisplayId;
+                mVr2dDisplayId = vr2dDisplayId;
             }
         }
 
@@ -3734,7 +4508,7 @@
 
         @Override
         public void registerScreenObserver(ScreenObserver observer) {
-            mAm.mScreenObservers.add(observer);
+            mScreenObservers.add(observer);
         }
 
         @Override
@@ -3754,7 +4528,7 @@
 
         @Override
         public void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
-            mAm.enforceCallerIsRecentsOrHasPermission(permission, func);
+            ActivityTaskManagerService.this.enforceCallerIsRecentsOrHasPermission(permission, func);
         }
 
         @Override
@@ -3763,5 +4537,43 @@
                 mActiveVoiceInteractionServiceComponent = component;
             }
         }
+
+        @Override
+        public void setAllowAppSwitches(@NonNull String type, int uid, int userId) {
+            if (!mAmInternal.isUserRunning(userId, ActivityManager.FLAG_OR_STOPPED)) {
+                return;
+            }
+            synchronized (mGlobalLock) {
+                ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(userId);
+                if (types == null) {
+                    if (uid < 0) {
+                        return;
+                    }
+                    types = new ArrayMap<>();
+                    mAllowAppSwitchUids.put(userId, types);
+                }
+                if (uid < 0) {
+                    types.remove(type);
+                } else {
+                    types.put(type, uid);
+                }
+            }
+        }
+
+        @Override
+        public void onUserStopped(int userId) {
+            synchronized (mGlobalLock) {
+                getRecentTasks().unloadUserDataFromMemoryLocked(userId);
+                mAllowAppSwitchUids.remove(userId);
+            }
+        }
+
+        @Override
+        public boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
+            synchronized (mGlobalLock) {
+                return ActivityTaskManagerService.this.isGetTasksAllowed(
+                        caller, callingPid, callingUid);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index eac3501..5719490 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -532,7 +532,7 @@
                                                        String shortMsg, String longMsg,
                                                        String stackTrace, long timeMillis,
                                                        int callingPid, int callingUid) {
-        if (mService.mController == null) {
+        if (mService.mActivityTaskManager.mController == null) {
             return false;
         }
 
@@ -540,7 +540,7 @@
             String name = r != null ? r.processName : null;
             int pid = r != null ? r.pid : callingPid;
             int uid = r != null ? r.info.uid : callingUid;
-            if (!mService.mController.appCrashed(name, pid,
+            if (!mService.mActivityTaskManager.mController.appCrashed(name, pid,
                     shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
                 if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
                         && "Native crash".equals(crashInfo.exceptionClassName)) {
@@ -563,7 +563,7 @@
                 return true;
             }
         } catch (RemoteException e) {
-            mService.mController = null;
+            mService.mActivityTaskManager.mController = null;
             Watchdog.getInstance().setActivityController(null);
         }
         return false;
@@ -887,16 +887,16 @@
         ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
         SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
 
-        if (mService.mController != null) {
+        if (mService.mActivityTaskManager.mController != null) {
             try {
                 // 0 == continue, -1 = kill process immediately
-                int res = mService.mController.appEarlyNotResponding(
+                int res = mService.mActivityTaskManager.mController.appEarlyNotResponding(
                         app.processName, app.pid, annotation);
                 if (res < 0 && app.pid != MY_PID) {
                     app.kill("anr", true);
                 }
             } catch (RemoteException e) {
-                mService.mController = null;
+                mService.mActivityTaskManager.mController = null;
                 Watchdog.getInstance().setActivityController(null);
             }
         }
@@ -1054,10 +1054,10 @@
         mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
                 cpuInfo, tracesFile, null);
 
-        if (mService.mController != null) {
+        if (mService.mActivityTaskManager.mController != null) {
             try {
                 // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
-                int res = mService.mController.appNotResponding(
+                int res = mService.mActivityTaskManager.mController.appNotResponding(
                         app.processName, app.pid, info.toString());
                 if (res != 0) {
                     if (res < 0 && app.pid != MY_PID) {
@@ -1070,7 +1070,7 @@
                     return;
                 }
             } catch (RemoteException e) {
-                mService.mController = null;
+                mService.mActivityTaskManager.mController = null;
                 Watchdog.getInstance().setActivityController(null);
             }
         }
diff --git a/services/core/java/com/android/server/am/AppTaskImpl.java b/services/core/java/com/android/server/am/AppTaskImpl.java
index 953d3b8..c22dedc 100644
--- a/services/core/java/com/android/server/am/AppTaskImpl.java
+++ b/services/core/java/com/android/server/am/AppTaskImpl.java
@@ -20,7 +20,6 @@
 import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
 
 import android.app.ActivityManager;
-import android.app.ActivityOptions;
 import android.app.IAppTask;
 import android.app.IApplicationThread;
 import android.content.Intent;
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index b54441a..037f245 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -49,7 +49,6 @@
     public static final String KEY_RECEIVER_EXTRA_COUNT = "count";
     public static final String KEY_RECEIVER_EXTRA_INDEX = "index";
 
-    private IActivityManager mService;
     private IWindowManager mWindowManager;
     private Context mContext;
     private AppOpsManager mAppOpsManager;
@@ -118,14 +117,13 @@
      *                                This can be {@link AppOpsManager#OP_NONE} to indicate that
      *                                screenshots should never be fetched.
      */
-    public AssistDataRequester(Context context, IActivityManager service,
+    public AssistDataRequester(Context context,
             IWindowManager windowManager, AppOpsManager appOpsManager,
             AssistDataRequesterCallbacks callbacks, Object callbacksLock,
             int requestStructureAppOps, int requestScreenshotAppOps) {
         mCallbacks = callbacks;
         mCallbacksLock = callbacksLock;
         mWindowManager = windowManager;
-        mService = service;
         mContext = context;
         mAppOpsManager = appOpsManager;
         mRequestStructureAppOps = requestStructureAppOps;
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index c6947ab..38254b8 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -219,25 +219,10 @@
                 : ActivityManager.COMPAT_MODE_DISABLED;
     }
 
-    public boolean getFrontActivityAskCompatModeLocked() {
-        ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked();
-        if (r == null) {
-            return false;
-        }
-        return getPackageAskCompatModeLocked(r.packageName);
-    }
-
     public boolean getPackageAskCompatModeLocked(String packageName) {
         return (getPackageFlags(packageName)&COMPAT_FLAG_DONT_ASK) == 0;
     }
 
-    public void setFrontActivityAskCompatModeLocked(boolean ask) {
-        ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked();
-        if (r != null) {
-            setPackageAskCompatModeLocked(r.packageName, ask);
-        }
-    }
-
     public void setPackageAskCompatModeLocked(String packageName, boolean ask) {
         setPackageFlagLocked(packageName, COMPAT_FLAG_DONT_ASK, ask);
     }
@@ -255,23 +240,6 @@
         }
     }
 
-    public int getFrontActivityScreenCompatModeLocked() {
-        ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked();
-        if (r == null) {
-            return ActivityManager.COMPAT_MODE_UNKNOWN;
-        }
-        return computeCompatModeLocked(r.info.applicationInfo);
-    }
-
-    public void setFrontActivityScreenCompatModeLocked(int mode) {
-        ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked();
-        if (r == null) {
-            Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity");
-            return;
-        }
-        setPackageScreenCompatModeLocked(r.info.applicationInfo, mode);
-    }
-
     public int getPackageScreenCompatModeLocked(String packageName) {
         ApplicationInfo ai = null;
         try {
@@ -297,7 +265,7 @@
         setPackageScreenCompatModeLocked(ai, mode);
     }
 
-    private void setPackageScreenCompatModeLocked(ApplicationInfo ai, int mode) {
+    void setPackageScreenCompatModeLocked(ApplicationInfo ai, int mode) {
         final String packageName = ai.packageName;
 
         int curFlags = getPackageFlags(packageName);
@@ -349,7 +317,7 @@
 
             scheduleWrite();
 
-            final ActivityStack stack = mService.getFocusedStack();
+            final ActivityStack stack = mService.mActivityTaskManager.getFocusedStack();
             ActivityRecord starting = stack.restartPackage(packageName);
 
             // Tell all processes that loaded this package about the change.
diff --git a/services/core/java/com/android/server/am/LaunchParamsController.java b/services/core/java/com/android/server/am/LaunchParamsController.java
index 4330d2c..6415c3e 100644
--- a/services/core/java/com/android/server/am/LaunchParamsController.java
+++ b/services/core/java/com/android/server/am/LaunchParamsController.java
@@ -38,7 +38,7 @@
  * registered {@link LaunchParamsModifier}s.
  */
 class LaunchParamsController {
-    private final ActivityManagerService mService;
+    private final ActivityTaskManagerService mService;
     private final List<LaunchParamsModifier> mModifiers = new ArrayList<>();
 
     // Temporary {@link LaunchParams} for internal calculations. This is kept separate from
@@ -48,7 +48,7 @@
     private final LaunchParams mTmpCurrent = new LaunchParams();
     private final LaunchParams mTmpResult = new LaunchParams();
 
-    LaunchParamsController(ActivityManagerService service) {
+    LaunchParamsController(ActivityTaskManagerService service) {
        mService = service;
     }
 
@@ -125,7 +125,7 @@
         try {
             if (mTmpParams.hasPreferredDisplay()
                     && mTmpParams.mPreferredDisplayId != task.getStack().getDisplay().mDisplayId) {
-                mService.mActivityTaskManager.moveStackToDisplay(task.getStackId(), mTmpParams.mPreferredDisplayId);
+                mService.moveStackToDisplay(task.getStackId(), mTmpParams.mPreferredDisplayId);
             }
 
             if (mTmpParams.hasWindowingMode()
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index bd49bd1..1c7ad3f 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -54,11 +54,10 @@
     private static final String TAG = RecentsAnimation.class.getSimpleName();
     private static final boolean DEBUG = false;
 
-    private final ActivityManagerService mService;
+    private final ActivityTaskManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
     private final ActivityStartController mActivityStartController;
     private final WindowManagerService mWindowManager;
-    private final UserController mUserController;
     private final ActivityDisplay mDefaultDisplay;
     private final int mCallingPid;
 
@@ -68,15 +67,14 @@
     // The stack to restore the target stack behind when the animation is finished
     private ActivityStack mRestoreTargetBehindStack;
 
-    RecentsAnimation(ActivityManagerService am, ActivityStackSupervisor stackSupervisor,
+    RecentsAnimation(ActivityTaskManagerService atm, ActivityStackSupervisor stackSupervisor,
             ActivityStartController activityStartController, WindowManagerService wm,
-            UserController userController, int callingPid) {
-        mService = am;
+            int callingPid) {
+        mService = atm;
         mStackSupervisor = stackSupervisor;
         mDefaultDisplay = stackSupervisor.getDefaultDisplay();
         mActivityStartController = activityStartController;
         mWindowManager = wm;
-        mUserController = userController;
         mCallingPid = callingPid;
     }
 
@@ -122,7 +120,7 @@
 
         mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
 
-        mService.setRunningRemoteAnimation(mCallingPid, true);
+        mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true);
 
         mWindowManager.deferSurfaceLayout();
         try {
@@ -132,7 +130,7 @@
                         mService.mContext.getSystemService(Context.APP_OPS_SERVICE);
                 final AssistDataReceiverProxy proxy = new AssistDataReceiverProxy(
                         assistDataReceiver, recentsComponent.getPackageName());
-                mAssistDataRequester = new AssistDataRequester(mService.mContext, mService,
+                mAssistDataRequester = new AssistDataRequester(mService.mContext,
                         mWindowManager, appOpsManager, proxy, this, OP_ASSIST_STRUCTURE, OP_NONE);
                 mAssistDataRequester.requestAssistData(mStackSupervisor.getTopVisibleActivities(),
                         true /* fetchData */, false /* fetchScreenshots */,
@@ -165,7 +163,7 @@
                         .setCallingUid(recentsUid)
                         .setCallingPackage(recentsComponent.getPackageName())
                         .setActivityOptions(SafeActivityOptions.fromBundle(options.toBundle()))
-                        .setMayWait(mUserController.getCurrentUserId())
+                        .setMayWait(mService.getCurrentUserId())
                         .execute();
                 mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
                 mWindowManager.executeAppTransition();
@@ -210,7 +208,7 @@
     }
 
     private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
-        synchronized (mService) {
+        synchronized (mService.mGlobalLock) {
             if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller="
                     + mWindowManager.getRecentsAnimationController()
                     + " reorderMode=" + reorderMode);
@@ -232,7 +230,7 @@
                 mStackSupervisor.sendPowerHintForLaunchEndIfNeeded();
             }
 
-            mService.setRunningRemoteAnimation(mCallingPid, false);
+            mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, false);
 
             mWindowManager.inSurfaceTransaction(() -> {
                 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER,
@@ -317,7 +315,7 @@
         if (runSychronously) {
             finishAnimation(reorderMode);
         } else {
-            mService.mHandler.post(() -> finishAnimation(reorderMode));
+            mService.mH.post(() -> finishAnimation(reorderMode));
         }
     }
 
diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java
index 778990b..b87b948 100644
--- a/services/core/java/com/android/server/am/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/am/SafeActivityOptions.java
@@ -192,7 +192,7 @@
         // component or has the START_TASKS_FROM_RECENTS permission
         if (options.getLaunchTaskId() != INVALID_TASK_ID
                 && !supervisor.mRecentTasks.isCallerRecents(callingUid)) {
-            final int startInTaskPerm = supervisor.mService.mAm.checkPermission(
+            final int startInTaskPerm = ActivityTaskManagerService.checkPermission(
                     START_TASKS_FROM_RECENTS, callingPid, callingUid);
             if (startInTaskPerm == PERMISSION_DENIED) {
                 final String msg = "Permission Denial: starting " + getIntentString(intent)
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 465fa67..481bb2b 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -655,7 +655,7 @@
                     synchronized (mService.mGlobalLock) {
                         if (DEBUG) Slog.d(TAG, "mRecents=" + mRecentTasks);
                         mRecentTasks.getPersistableTaskIds(persistentTaskIds);
-                        mService.mAm.mWindowManager.removeObsoleteTaskFiles(persistentTaskIds,
+                        mService.mWindowManager.removeObsoleteTaskFiles(persistentTaskIds,
                                 mRecentTasks.usersWithRecentsLoadedLocked());
                     }
                     removeObsoleteFiles(persistentTaskIds);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 6eac4bc..ba012ab 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1494,7 +1494,7 @@
     }
 
     private boolean isResizeable(boolean checkSupportsPip) {
-        return (mService.mAm.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
+        return (mService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
                 || (checkSupportsPip && mSupportsPictureInPicture));
     }
 
@@ -1507,8 +1507,8 @@
         // A task can not be docked even if it is considered resizeable because it only supports
         // picture-in-picture mode but has a non-resizeable resizeMode
         return super.supportsSplitScreenWindowingMode()
-                && mService.mAm.mSupportsSplitScreenMultiWindow
-                && (mService.mAm.mForceResizableActivities
+                && mService.mSupportsSplitScreenMultiWindow
+                && (mService.mForceResizableActivities
                         || (isResizeable(false /* checkSupportsPip */)
                                 && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
     }
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index b500bbf..3b47844 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -28,9 +28,9 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.ALLOW_FULL_ONLY;
-import static com.android.server.am.ActivityManagerService.ALLOW_NON_FULL;
-import static com.android.server.am.ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE;
+import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
 import static com.android.server.am.ActivityManagerService.MY_PID;
 import static com.android.server.am.UserState.STATE_BOOTING;
 import static com.android.server.am.UserState.STATE_RUNNING_LOCKED;
@@ -41,6 +41,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.app.ActivityTaskManagerInternal;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.Dialog;
@@ -80,7 +81,6 @@
 import android.text.format.DateUtils;
 import android.util.ArraySet;
 import android.util.IntArray;
-import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -88,7 +88,6 @@
 import android.util.TimingsTraceLog;
 import android.util.proto.ProtoOutputStream;
 
-import android.view.Window;
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -2097,9 +2096,7 @@
             return mService.mWindowManager;
         }
         void activityManagerOnUserStopped(int userId) {
-            synchronized (mService) {
-                mService.onUserStoppedLocked(userId);
-            }
+            LocalServices.getService(ActivityTaskManagerInternal.class).onUserStopped(userId);
         }
 
         void systemServiceManagerCleanupUser(int userId) {
@@ -2174,9 +2171,7 @@
         }
 
         void updateUserConfiguration() {
-            synchronized (mService) {
-                mService.updateUserConfigurationLocked();
-            }
+            mService.mActivityTaskManager.updateUserConfiguration();
         }
 
         void clearBroadcastQueueForUser(int userId) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 407cb93..6e7eae1 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -27,11 +27,11 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
+import android.app.ActivityTaskManagerInternal;
 import android.app.IActivityManager;
 import android.app.IStopUserCallback;
 import android.app.KeyguardManager;
 import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -72,7 +72,6 @@
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.os.storage.StorageManager;
-import android.provider.Settings;
 import android.security.GateKeeper;
 import android.service.gatekeeper.IGateKeeperService;
 import android.util.AtomicFile;
@@ -82,7 +81,6 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
-import android.util.SparseLongArray;
 import android.util.TimeUtils;
 import android.util.Xml;
 
@@ -2968,9 +2966,9 @@
                             new Thread() {
                                 @Override
                                 public void run() {
-                                    // Clean up any ActivityManager state
-                                    LocalServices.getService(ActivityManagerInternal.class)
-                                            .onUserRemoved(userHandle);
+                                    // Clean up any ActivityTaskManager state
+                                    LocalServices.getService(ActivityTaskManagerInternal.class)
+                                            .onUserStopped(userHandle);
                                     removeUserState(userHandle);
                                 }
                             }.start();