AML: Do not merge launch events on different displays
Generally multi-display is visually independent, so the launch
events on different displays should be tracked separately.
Bug: 123355661
Bug: 135197913
Test: atest ActivityMetricsLaunchObserverTests# \
testConsecutiveLaunchOnDifferentDisplay
Change-Id: I84e1e800654a440782ff9a85124449ce6d8078ba
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index c8357e2..1c010c7 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -543,9 +543,10 @@
return;
}
- if (info != null) {
- // If we are already in an existing transition, only update the activity name, but not
- // the other attributes.
+ if (info != null
+ && info.mLastLaunchedActivity.mDisplayContent == launchedActivity.mDisplayContent) {
+ // If we are already in an existing transition on the same display, only update the
+ // activity name, but not the other attributes.
if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched update launched activity");
// Coalesce multiple (trampoline) activities from a single sequence together.
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 12074dc3..3eee031 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -44,6 +44,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import java.util.Arrays;
@@ -57,6 +58,7 @@
*/
@SmallTest
@Presubmit
+@RunWith(WindowTestRunner.class)
public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
private ActivityMetricsLogger mActivityMetricsLogger;
private ActivityMetricsLogger.LaunchingState mLaunchingState;
@@ -116,11 +118,18 @@
return argThat(new ActivityRecordMatcher(record));
}
- static <T> T verifyAsync(T mock) {
+ private <T> T verifyAsync(T mock) {
+ // With WindowTestRunner, all test methods are inside WM lock, so we have to unblock any
+ // messages that are waiting for the lock.
+ waitHandlerIdle(mService.mH);
// AMLO callbacks happen on a separate thread than AML calls, so we need to use a timeout.
return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5)));
}
+ private void verifyOnActivityLaunchFinished(ActivityRecord activity) {
+ verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(activity), anyLong());
+ }
+
private void onIntentStarted(Intent intent) {
notifyActivityLaunching(intent);
@@ -159,7 +168,7 @@
notifyTransitionStarting(mTopActivity);
notifyWindowsDrawn(mTopActivity);
- verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
+ verifyOnActivityLaunchFinished(mTopActivity);
verifyNoMoreInteractions(mLaunchObserver);
}
@@ -210,7 +219,7 @@
notifyWindowsDrawn(mTopActivity);
verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong());
- verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
+ verifyOnActivityLaunchFinished(mTopActivity);
verifyNoMoreInteractions(mLaunchObserver);
}
@@ -267,7 +276,7 @@
notifyWindowsDrawn(mTopActivity);
- verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
+ verifyOnActivityLaunchFinished(mTopActivity);
verifyNoMoreInteractions(mLaunchObserver);
}
@@ -322,16 +331,40 @@
assertWithMessage("Different callers should get 2 indepedent launching states")
.that(previousState).isNotEqualTo(mLaunchingState);
-
- notifyTransitionStarting(otherActivity);
- notifyWindowsDrawn(otherActivity);
-
- verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(otherActivity), anyLong());
+ transitToDrawnAndVerifyOnLaunchFinished(otherActivity);
// The first transition should still be valid.
- notifyTransitionStarting(mTopActivity);
- notifyWindowsDrawn(mTopActivity);
+ transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
+ }
- verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
+ @Test
+ public void testConsecutiveLaunchOnDifferentDisplay() {
+ onActivityLaunched(mTopActivity);
+
+ final ActivityStack stack = new StackBuilder(mRootActivityContainer)
+ .setDisplay(addNewDisplayContentAt(DisplayContent.POSITION_BOTTOM))
+ .setCreateActivity(false)
+ .build();
+ final ActivityRecord activityOnNewDisplay = new ActivityBuilder(mService)
+ .setStack(stack)
+ .setCreateTask(true)
+ .setProcessName("new")
+ .build();
+
+ // Before TopActivity is drawn, it launches another activity on a different display.
+ mActivityMetricsLogger.notifyActivityLaunching(activityOnNewDisplay.intent,
+ mTopActivity /* caller */);
+ notifyActivityLaunched(START_SUCCESS, activityOnNewDisplay);
+
+ // There should be 2 events instead of coalescing as one event.
+ transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
+ transitToDrawnAndVerifyOnLaunchFinished(activityOnNewDisplay);
+ }
+
+ private void transitToDrawnAndVerifyOnLaunchFinished(ActivityRecord activity) {
+ notifyTransitionStarting(activity);
+ notifyWindowsDrawn(activity);
+
+ verifyOnActivityLaunchFinished(activity);
}
}