Distinguish warm/hot launch by whether the activity has attached process

If the process of an activity was died in background, its activity and
task record will still be in history stack. If the process is started
again in background such as receiving broadcast. Then the launch of the
same activity will have the conditions: process exists and the result
code is START_TASK_TO_FRONT. But the activity still need to create so
it should be warm launch.

Fixes: 171549711
Test: ActivityMetricsLaunchObserverTests#testOnActivityLaunchFinished
Change-Id: Iaf53ab8a35192249c20a73d9cb0de2a5e8effc64
Merged-In: Iaf53ab8a35192249c20a73d9cb0de2a5e8effc64
(cherry picked from commit 2e039cd3bc020a4d0c5831f945d42e162b9ad5e4)
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 189b21f..5570c01 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -129,7 +129,6 @@
      */
     private static final int IGNORE_CALLER = -1;
     private static final int INVALID_DELAY = -1;
-    private static final int INVALID_TRANSITION_TYPE = -1;
 
     // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
     // time we log.
@@ -224,22 +223,19 @@
         static TransitionInfo create(@NonNull ActivityRecord r,
                 @NonNull LaunchingState launchingState, boolean processRunning,
                 boolean processSwitch, int startResult) {
-            int transitionType = INVALID_TRANSITION_TYPE;
+            if (startResult != START_SUCCESS && startResult != START_TASK_TO_FRONT) {
+                return null;
+            }
+            final int transitionType;
             if (processRunning) {
-                if (startResult == START_SUCCESS) {
-                    transitionType = TYPE_TRANSITION_WARM_LAUNCH;
-                } else if (startResult == START_TASK_TO_FRONT) {
-                    transitionType = TYPE_TRANSITION_HOT_LAUNCH;
-                }
-            } else if (startResult == START_SUCCESS || startResult == START_TASK_TO_FRONT) {
+                transitionType = r.attachedToProcess()
+                        ? TYPE_TRANSITION_HOT_LAUNCH
+                        : TYPE_TRANSITION_WARM_LAUNCH;
+            } else {
                 // Task may still exist when cold launching an activity and the start result will be
                 // set to START_TASK_TO_FRONT. Treat this as a COLD launch.
                 transitionType = TYPE_TRANSITION_COLD_LAUNCH;
             }
-            if (transitionType == INVALID_TRANSITION_TYPE) {
-                // That means the startResult is neither START_SUCCESS nor START_TASK_TO_FRONT.
-                return null;
-            }
             return new TransitionInfo(r, launchingState, transitionType, processRunning,
                     processSwitch);
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index e1ce431f..565351a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -32,6 +32,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.timeout;
 
+import android.app.WaitResult;
 import android.content.Intent;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
@@ -163,10 +164,15 @@
 
     @Test
     public void testOnActivityLaunchFinished() {
+        // Assume that the process is started (ActivityBuilder has mocked the returned value of
+        // ATMS#getProcessController) but the activity has not attached process.
+        mTopActivity.app = null;
         onActivityLaunched(mTopActivity);
 
         notifyTransitionStarting(mTopActivity);
-        notifyWindowsDrawn(mTopActivity);
+        final ActivityMetricsLogger.TransitionInfoSnapshot info = notifyWindowsDrawn(mTopActivity);
+        assertWithMessage("Warm launch").that(info.getLaunchState())
+                .isEqualTo(WaitResult.LAUNCH_STATE_WARM);
 
         verifyOnActivityLaunchFinished(mTopActivity);
         verifyNoMoreInteractions(mLaunchObserver);
@@ -201,7 +207,7 @@
         notifyActivityLaunching(noDrawnActivity.intent);
         notifyActivityLaunched(START_SUCCESS, noDrawnActivity);
 
-        noDrawnActivity.destroyIfPossible("test");
+        noDrawnActivity.mVisibleRequested = false;
         mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity);
 
         verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(noDrawnActivity));
@@ -217,6 +223,9 @@
         notifyTransitionStarting(mTopActivity);
         // The pending fully drawn event should send when the actual windows drawn event occurs.
         notifyWindowsDrawn(mTopActivity);
+        final ActivityMetricsLogger.TransitionInfoSnapshot info = notifyWindowsDrawn(mTopActivity);
+        assertWithMessage("Hot launch").that(info.getLaunchState())
+                .isEqualTo(WaitResult.LAUNCH_STATE_HOT);
 
         verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong());
         verifyOnActivityLaunchFinished(mTopActivity);
@@ -260,8 +269,8 @@
         mActivityMetricsLogger.notifyTransitionStarting(reasons);
     }
 
-    private void notifyWindowsDrawn(ActivityRecord r) {
-        mActivityMetricsLogger.notifyWindowsDrawn(r, SystemClock.elapsedRealtimeNanos());
+    private ActivityMetricsLogger.TransitionInfoSnapshot notifyWindowsDrawn(ActivityRecord r) {
+        return mActivityMetricsLogger.notifyWindowsDrawn(r, SystemClock.elapsedRealtimeNanos());
     }
 
     @Test