Correct activity's lifecycle when the process was killed in background.

The lifecycle of an invisible activity would stay in pause stage if
it's process was died and restore from attachApplication. The incorrect
status can affect transition since it won't be removed from
UnknownAppVisibilityController. Stopping the invisible activity so it
won't stay in paused.

Bug: 327596503
Test: atest RecentsAnimationTest
Test: launch a translucent app, entering keyguard, kill home process.
Verify the activity of home process would be stopped after attach the
process back.

Change-Id: I80756609fe643877971408934b19ad97aa0ae746
Merged-In: I80756609fe643877971408934b19ad97aa0ae746
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 2cda1f5..81fb78a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -57,6 +57,7 @@
 import static com.android.server.wm.ActivityRecord.State.PAUSING;
 import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
@@ -104,6 +105,7 @@
 import android.app.servertransaction.LaunchActivityItem;
 import android.app.servertransaction.PauseActivityItem;
 import android.app.servertransaction.ResumeActivityItem;
+import android.app.servertransaction.StopActivityItem;
 import android.companion.virtual.VirtualDeviceManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -944,8 +946,10 @@
                 if (andResume) {
                     lifecycleItem = ResumeActivityItem.obtain(r.token, isTransitionForward,
                             r.shouldSendCompatFakeFocus());
-                } else {
+                } else if (r.isVisibleRequested()) {
                     lifecycleItem = PauseActivityItem.obtain(r.token);
+                } else {
+                    lifecycleItem = StopActivityItem.obtain(r.token);
                 }
 
                 // Schedule transaction.
@@ -1012,7 +1016,7 @@
             // As part of the process of launching, ActivityThread also performs
             // a resume.
             rootTask.minimalResumeActivityLocked(r);
-        } else {
+        } else if (r.isVisibleRequested()) {
             // This activity is not starting in the resumed state... which should look like we asked
             // it to pause+stop (but remain visible), and it has done so and reported back the
             // current icicle and other state.
@@ -1020,6 +1024,9 @@
                     + "(starting in paused state)", r);
             r.setState(PAUSED, "realStartActivityLocked");
             mRootWindowContainer.executeAppTransitionForAllDisplay();
+        } else {
+            // This activity is starting while invisible, so it should be stopped.
+            r.setState(STOPPING, "realStartActivityLocked");
         }
         // Perform OOM scoring after the activity state is set, so the process can be updated with
         // the latest state.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 32b3558..da437c4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -33,6 +33,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityRecord.State.PAUSED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
@@ -164,13 +165,12 @@
         ActivityRecord recentsActivity = recentsStack.getTopNonFinishingActivity();
         // The activity is started in background so it should be invisible and will be stopped.
         assertThat(recentsActivity).isNotNull();
-        assertThat(mSupervisor.mStoppingActivities).contains(recentsActivity);
+        assertThat(recentsActivity.getState()).isEqualTo(STOPPING);
         assertFalse(recentsActivity.isVisibleRequested());
 
         // Assume it is stopped to test next use case.
         recentsActivity.activityStopped(null /* newIcicle */, null /* newPersistentState */,
                 null /* description */);
-        mSupervisor.mStoppingActivities.remove(recentsActivity);
 
         spyOn(recentsActivity);
         // Start when the recents activity exists. It should ensure the configuration.
@@ -178,7 +178,6 @@
                 null /* recentsAnimationRunner */);
 
         verify(recentsActivity).ensureActivityConfiguration(eq(true) /* ignoreVisibility */);
-        assertThat(mSupervisor.mStoppingActivities).contains(recentsActivity);
     }
 
     @Test