Start home activities for all displays on boot

We were only starting home activity on default display when
system boot up. After system booted, home activities would be
started when new displays added. But in some cases, there
are more than one displays being ready before boot completed.
So it ended up with no home activities on secondary displays.

Making sure home activities can be launched on all displays
on boot now.

Also checks finishing booting when all resumed activities
on all displays are idle.

Bug: 111363427
Test: Manual
Test: atest ActivityStackSupervisorTests

Change-Id: I2291ce967bc6f2f03ca7f680c3d6a2d8e8f3cd08
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e8c6365..c6fdf15 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -129,7 +129,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
 import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
 import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
@@ -8380,7 +8379,7 @@
                     throw e.rethrowAsRuntimeException();
                 }
             }
-            mAtmInternal.startHomeActivity(currentUserId, "systemReady");
+            mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
 
             mAtmInternal.showSystemReadyErrorDialogsIfNeeded();
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 17454b4..87226bf 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -44,6 +44,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.app.WindowConfiguration.activityTypeToString;
 import static android.app.WindowConfiguration.windowingModeToString;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 import static android.content.pm.PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY;
@@ -115,8 +116,8 @@
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
+import android.app.AppGlobals;
 import android.app.AppOpsManager;
-import android.app.IApplicationThread;
 import android.app.ProfilerInfo;
 import android.app.ResultInfo;
 import android.app.WaitResult;
@@ -146,6 +147,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
+import android.os.FactoryTest;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -786,10 +788,24 @@
             r.moveFocusableActivityToTop(myReason);
             return resumeFocusedStacksTopActivitiesLocked(r.getStack(), prev, null);
         }
-        return mService.startHomeActivityLocked(mCurrentUser, myReason, displayId);
+        return startHomeOnDisplay(mCurrentUser, myReason, displayId);
     }
 
-    boolean canStartHomeOnDisplay(ActivityInfo homeActivity, int displayId) {
+    boolean canStartHomeOnDisplay(ActivityInfo homeInfo, int displayId) {
+        if (mService.mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
+                && mService.mTopAction == null) {
+            // We are running in factory test mode, but unable to find the factory test app, so
+            // just sit around displaying the error message and don't try to start anything.
+            return false;
+        }
+
+        final WindowProcessController app =
+                mService.getProcessController(homeInfo.processName, homeInfo.applicationInfo.uid);
+        if (app != null && app.isInstrumenting()) {
+            // Don't do this if the home app is currently being instrumented.
+            return false;
+        }
+
         if (displayId == DEFAULT_DISPLAY || (displayId != INVALID_DISPLAY
                 && displayId == mService.mVr2dDisplayId)) {
             // No restrictions to default display or vr 2d display.
@@ -802,8 +818,8 @@
             return false;
         }
 
-        final boolean supportMultipleInstance = homeActivity.launchMode != LAUNCH_SINGLE_TASK
-                && homeActivity.launchMode != LAUNCH_SINGLE_INSTANCE;
+        final boolean supportMultipleInstance = homeInfo.launchMode != LAUNCH_SINGLE_TASK
+                && homeInfo.launchMode != LAUNCH_SINGLE_INSTANCE;
         if (!supportMultipleInstance) {
             // Can't launch home on other displays if it requested to be single instance.
             return false;
@@ -1037,12 +1053,14 @@
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
             for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                // We cannot only check the top stack on each display since there might have
+                // always-on-top stacks (e.g. pinned stack).
                 final ActivityStack stack = display.getChildAt(stackNdx);
-                if (!isTopDisplayFocusedStack(stack) || stack.numActivities() == 0) {
+                if (stack.numActivities() == 0) {
                     continue;
                 }
                 final ActivityRecord resumedActivity = stack.getResumedActivity();
-                if (resumedActivity == null || !resumedActivity.idle) {
+                if (resumedActivity != null && !resumedActivity.idle) {
                     if (DEBUG_STATES) Slog.d(TAG_STATES, "allResumedActivitiesIdle: stack="
                              + stack.mStackId + " " + resumedActivity + " not idle");
                     return false;
@@ -1895,7 +1913,7 @@
     }
 
     /**
-     * Called when the frontmost task is idle.
+     * Called when all resumed tasks/stacks are idle.
      * @return the state of mService.mAm.mBooting before this was called.
      */
     @GuardedBy("mService")
@@ -1950,7 +1968,9 @@
             r.idle = true;
 
             //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
-            if (isTopDisplayFocusedStack(r.getStack()) || fromTimeout) {
+
+            // Make sure we can finish booting when all resumed activities are idle.
+            if ((!mService.isBooted() && allResumedActivitiesIdle()) || fromTimeout) {
                 booting = checkFinishBootingLocked();
             }
 
@@ -4107,7 +4127,7 @@
         if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
         synchronized (mService.mGlobalLock) {
             getActivityDisplayOrCreateLocked(displayId);
-            mService.startHomeActivityLocked(mCurrentUser, "displayAdded", displayId);
+            startHomeOnDisplay(mCurrentUser, "displayAdded", displayId);
         }
     }
 
@@ -4185,6 +4205,76 @@
         return activityDisplay;
     }
 
+    boolean startHomeOnAllDisplays(int userId, String reason) {
+        boolean homeStarted = false;
+        for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
+            final int displayId = mActivityDisplays.get(i).mDisplayId;
+            homeStarted |= startHomeOnDisplay(userId, reason, displayId);
+        }
+        return homeStarted;
+    }
+
+    /**
+     * This starts home activity on displays that can have system decorations and only if the
+     * home activity can have multiple instances.
+     */
+    boolean startHomeOnDisplay(int userId, String reason, int displayId) {
+        final Intent homeIntent = mService.getHomeIntent();
+        final ActivityInfo aInfo = resolveHomeActivity(userId, homeIntent);
+        if (aInfo == null) {
+            return false;
+        }
+
+        if (!canStartHomeOnDisplay(aInfo, displayId)) {
+            return false;
+        }
+
+        // Update the reason for ANR debugging to verify if the user activity is the one that
+        // actually launched.
+        final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
+                aInfo.applicationInfo.uid);
+        mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
+                displayId);
+        return true;
+    }
+
+    /**
+     * This resolves the home activity info and updates the home component of the given intent.
+     * @return the home activity info if any.
+     */
+    private ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) {
+        final int flags = ActivityManagerService.STOCK_PM_FLAGS;
+        final ComponentName comp = homeIntent.getComponent();
+        ActivityInfo aInfo = null;
+        try {
+            if (comp != null) {
+                // Factory test.
+                aInfo = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
+            } else {
+                final String resolvedType =
+                        homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver());
+                final ResolveInfo info = AppGlobals.getPackageManager()
+                        .resolveIntent(homeIntent, resolvedType, flags, userId);
+                if (info != null) {
+                    aInfo = info.activityInfo;
+                }
+            }
+        } catch (RemoteException e) {
+            // ignore
+        }
+
+        if (aInfo == null) {
+            Slog.wtf(TAG, "No home screen found for " + homeIntent, new Throwable());
+            return null;
+        }
+
+        homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
+        aInfo = new ActivityInfo(aInfo);
+        aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
+        homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
+        return aInfo;
+    }
+
     @VisibleForTesting
     void addChild(ActivityDisplay activityDisplay, int position) {
         positionChildAt(activityDisplay, position);
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index 20d5ab2..3151ec9 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -20,8 +20,8 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-
 import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL;
+
 import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
@@ -35,7 +35,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Binder;
-import android.os.FactoryTest;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -167,10 +166,6 @@
     }
 
     void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, int displayId) {
-        if (!mSupervisor.canStartHomeOnDisplay(aInfo, displayId)) {
-            return;
-        }
-
         final ActivityOptions options = ActivityOptions.makeBasic();
         options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
         options.setLaunchActivityType(ACTIVITY_TYPE_HOME);
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 5b0a4a9..5e3c1da 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -85,13 +85,10 @@
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.HOME_PROC;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.LAUNCHING_ACTIVITY;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto
-        .PREVIOUS_PROC_VISIBLE_TIME_MS;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
-        .MODE;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
-        .PACKAGE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
 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;
@@ -5353,65 +5350,6 @@
         return intent;
     }
 
-    /**
-     * This starts home activity on displays that can have system decorations and only if the
-     * home activity can have multiple instances.
-     */
-    boolean startHomeActivityLocked(int userId, String reason, int displayId) {
-        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL && mTopAction == null) {
-            // We are running in factory test mode, but unable to find the factory test app, so just
-            // sit around displaying the error message and don't try to start anything.
-            return false;
-        }
-
-        final Intent intent = getHomeIntent();
-        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
-        if (aInfo != null) {
-            intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
-            // Don't do this if the home app is currently being instrumented.
-            aInfo = new ActivityInfo(aInfo);
-            aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
-            WindowProcessController app =
-                    getProcessController(aInfo.processName, aInfo.applicationInfo.uid);
-            if (app == null || !app.isInstrumenting()) {
-                intent.setFlags(intent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
-                final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
-                // For ANR debugging to verify if the user activity is the one that actually
-                // launched.
-                final String myReason = reason + ":" + userId + ":" + resolvedUserId;
-                getActivityStartController().startHomeActivity(intent, aInfo, myReason, displayId);
-            }
-        } else {
-            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
-        }
-
-        return true;
-    }
-
-    private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
-        ActivityInfo ai = null;
-        final ComponentName comp = intent.getComponent();
-        try {
-            if (comp != null) {
-                // Factory test.
-                ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
-            } else {
-                ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
-                        intent,
-                        intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                        flags, userId);
-
-                if (info != null) {
-                    ai = info.activityInfo;
-                }
-            }
-        } catch (RemoteException e) {
-            // ignore
-        }
-
-        return ai;
-    }
-
     ApplicationInfo getAppInfoForUser(ApplicationInfo info, int userId) {
         if (info == null) return null;
         ApplicationInfo newInfo = new ApplicationInfo(info);
@@ -6127,7 +6065,14 @@
         @Override
         public boolean startHomeActivity(int userId, String reason) {
             synchronized (mGlobalLock) {
-                return startHomeActivityLocked(userId, reason, DEFAULT_DISPLAY);
+                return mStackSupervisor.startHomeOnDisplay(userId, reason, DEFAULT_DISPLAY);
+            }
+        }
+
+        @Override
+        public boolean startHomeOnAllDisplays(int userId, String reason) {
+            synchronized (mGlobalLock) {
+                return mStackSupervisor.startHomeOnAllDisplays(userId, reason);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index b011da6..caa2da3 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -33,8 +33,8 @@
 import android.os.SystemClock;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.SparseIntArray;
-
 import android.util.proto.ProtoOutputStream;
+
 import com.android.internal.app.IVoiceInteractor;
 import com.android.server.am.ActivityServiceConnectionsHolder;
 import com.android.server.am.PendingIntentRecord;
@@ -48,7 +48,6 @@
 import java.lang.ref.WeakReference;
 import java.util.List;
 import java.util.Set;
-import java.util.function.Predicate;
 
 /**
  * Activity Task manager local system service interface.
@@ -348,6 +347,8 @@
     /** @return The intent used to launch the home activity. */
     public abstract Intent getHomeIntent();
     public abstract boolean startHomeActivity(int userId, String reason);
+    /** Start home activities on all displays that support system decorations. */
+    public abstract boolean startHomeOnAllDisplays(int userId, String reason);
     /** @return true if the given process is the factory test process. */
     public abstract boolean isFactoryTestProcess(WindowProcessController wpc);
     public abstract void updateTopComponentForFactoryTest();
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index 2c993d3..f5bd0aa 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -26,16 +26,21 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
 
+import static com.android.server.am.ActivityDisplay.POSITION_TOP;
 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.contains;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -430,4 +435,32 @@
         verify(targetStack, times(1)).resumeTopActivityUncheckedLocked(
                 eq(activity), eq(null /* targetOptions */));
     }
+
+
+    /**
+     * Tests that home activities can be started on the displays that supports system decorations.
+     */
+    @Test
+    public void testStartHomeOnAllDisplays() throws Exception {
+        // Create secondary displays.
+        final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay());
+        mSupervisor.addChild(secondDisplay, POSITION_TOP);
+        doReturn(true).when(secondDisplay).supportsSystemDecorations();
+
+        // Create mock tasks and other necessary mocks.
+        TaskBuilder taskBuilder = new TaskBuilder(mService.mStackSupervisor).setCreateStack(false);
+        final TaskRecord.TaskRecordFactory factory = mock(TaskRecord.TaskRecordFactory.class);
+        TaskRecord.setTaskRecordFactory(factory);
+        doAnswer(i -> taskBuilder.build()).when(factory)
+                .create(any(), anyInt(), any(), any(), any(), any());
+        doReturn(true).when(mService.mStackSupervisor)
+                .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean());
+        doReturn(true).when(mSupervisor).canStartHomeOnDisplay(any(), anyInt());
+
+        mSupervisor.startHomeOnAllDisplays(0, "testStartHome");
+
+        assertTrue(mSupervisor.getDefaultDisplay().getTopStack().isActivityTypeHome());
+        assertNotNull(secondDisplay.getTopStack());
+        assertTrue(secondDisplay.getTopStack().isActivityTypeHome());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 094241e..ea5b1aa 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -39,14 +39,6 @@
 
 import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
-import android.content.pm.PackageManagerInternal;
-import com.android.server.uri.UriGrantsManagerInternal;
-import com.android.server.wm.ActivityTaskManagerInternal;
-import com.android.server.wm.DisplayWindowController;
-
-import org.junit.Rule;
-import org.mockito.invocation.InvocationOnMock;
-
 import android.app.IApplicationThread;
 import android.content.ComponentName;
 import android.content.Context;
@@ -54,6 +46,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
@@ -73,7 +66,10 @@
 import com.android.server.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.ServiceThread;
+import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.AppWindowContainerController;
+import com.android.server.wm.DisplayWindowController;
 import com.android.server.wm.PinnedStackWindowController;
 import com.android.server.wm.RootWindowContainerController;
 import com.android.server.wm.StackWindowController;
@@ -83,7 +79,9 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
 
 import java.io.File;
 import java.util.List;
@@ -172,6 +170,7 @@
         // Makes sure the supervisor is using with the spy object.
         atm.mStackSupervisor.setService(atm);
         doReturn(mock(IPackageManager.class)).when(am).getPackageManager();
+        doReturn(mock(IPackageManager.class)).when(atm).getPackageManager();
         PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class);
         doReturn(mockPackageManager).when(am).getPackageManagerInternalLocked();
         doReturn(null).when(mockPackageManager).getDefaultHomeActivity(anyInt());
@@ -419,6 +418,10 @@
         private ActivityTaskManagerInternal mInternal;
         private PackageManagerInternal mPmInternal;
 
+        // ActivityStackSupervisor may be created more than once while setting up AMS and ATMS.
+        // We keep the reference in order to prevent creating it twice.
+        private ActivityStackSupervisor mTestStackSupervisor;
+
         TestActivityTaskManagerService(Context context) {
             super(context);
             mSupportsMultiWindow = true;
@@ -449,24 +452,27 @@
 
         @Override
         final protected ActivityStackSupervisor createStackSupervisor() {
-            final ActivityStackSupervisor supervisor = spy(createTestSupervisor());
-            final KeyguardController keyguardController = mock(KeyguardController.class);
+            if (mTestStackSupervisor == null) {
+                final ActivityStackSupervisor supervisor = spy(createTestSupervisor());
+                final KeyguardController keyguardController = mock(KeyguardController.class);
 
-            // Invoked during {@link ActivityStack} creation.
-            doNothing().when(supervisor).updateUIDsPresentOnDisplay();
-            // Always keep things awake.
-            doReturn(true).when(supervisor).hasAwakeDisplay();
-            // Called when moving activity to pinned stack.
-            doNothing().when(supervisor).ensureActivitiesVisibleLocked(any(), anyInt(), anyBoolean());
-            // Do not schedule idle timeouts
-            doNothing().when(supervisor).scheduleIdleTimeoutLocked(any());
-            // unit test version does not handle launch wake lock
-            doNothing().when(supervisor).acquireLaunchWakelock();
-            doReturn(keyguardController).when(supervisor).getKeyguardController();
+                // Invoked during {@link ActivityStack} creation.
+                doNothing().when(supervisor).updateUIDsPresentOnDisplay();
+                // Always keep things awake.
+                doReturn(true).when(supervisor).hasAwakeDisplay();
+                // Called when moving activity to pinned stack.
+                doNothing().when(supervisor).ensureActivitiesVisibleLocked(any(), anyInt(),
+                        anyBoolean());
+                // Do not schedule idle timeouts
+                doNothing().when(supervisor).scheduleIdleTimeoutLocked(any());
+                // unit test version does not handle launch wake lock
+                doNothing().when(supervisor).acquireLaunchWakelock();
+                doReturn(keyguardController).when(supervisor).getKeyguardController();
 
-            supervisor.initialize();
-
-            return supervisor;
+                supervisor.initialize();
+                mTestStackSupervisor = supervisor;
+            }
+            return mTestStackSupervisor;
         }
 
         protected ActivityStackSupervisor createTestSupervisor() {