From 7673f3f876ce7566fc552fe28174812676203bf7 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Mon, 17 Apr 2023 19:00:38 +0800 Subject: Check null before getting task bounds The task bounds was used to decide whether multiple launches can be combined into one event for tracking launch time. With below sample: startActivities(new Intent[] { new Intent(c, Activity1.class), new Intent(c, Activity2.class).setFlags( Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK) }); When launching Activity2, because Activity1 hasn't real started, Activity1 will be removed from task directly. Then its task will be null, that causes mLastLaunchedActivity.getTask() to be null. If the task is not available, check if the launched activity has the same uid as the caller uid. Fix: 276513946 Test: atest ActivityMetricsLaunchObserverTests#testConsecutiveLaunch Change-Id: I731f0446b62b666b22ba1a6b37364d95efd0a32c --- .../com/android/server/wm/ActivityMetricsLogger.java | 18 +++++++++++++++--- .../server/wm/ActivityMetricsLaunchObserverTests.java | 7 +++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index a757d90b75ba..f71f3b128557 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -397,9 +397,21 @@ class ActivityMetricsLogger { /** Returns {@code true} if the incoming activity can belong to this transition. */ boolean canCoalesce(ActivityRecord r) { - return mLastLaunchedActivity.mDisplayContent == r.mDisplayContent - && mLastLaunchedActivity.getTask().getBounds().equals(r.getTask().getBounds()) - && mLastLaunchedActivity.getWindowingMode() == r.getWindowingMode(); + if (mLastLaunchedActivity.mDisplayContent != r.mDisplayContent + || mLastLaunchedActivity.getWindowingMode() != r.getWindowingMode()) { + return false; + } + // The current task should be non-null because it is just launched. While the + // last task can be cleared when starting activity with FLAG_ACTIVITY_CLEAR_TASK. + final Task lastTask = mLastLaunchedActivity.getTask(); + final Task currentTask = r.getTask(); + if (lastTask != null && currentTask != null) { + if (lastTask == currentTask) { + return true; + } + return lastTask.getBounds().equals(currentTask.getBounds()); + } + return mLastLaunchedActivity.isUid(r.launchedFromUid); } /** @return {@code true} if the activity matches a launched activity in this transition. */ 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 4e001fe06fb8..37c4b3787835 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -28,6 +28,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMor import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; @@ -501,6 +502,12 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase { onActivityLaunched(mTrampolineActivity); mActivityMetricsLogger.notifyActivityLaunching(mTopActivity.intent, mTrampolineActivity /* caller */, mTrampolineActivity.getUid()); + + // Simulate a corner case that the trampoline activity is removed by CLEAR_TASK. + // The 2 launch events can still be coalesced to one by matching the uid. + mTrampolineActivity.takeFromHistory(); + assertNull(mTrampolineActivity.getTask()); + notifyActivityLaunched(START_SUCCESS, mTopActivity); transitToDrawnAndVerifyOnLaunchFinished(mTopActivity); } -- cgit v1.2.3-59-g8ed1b