From 56ce0fa5c1777ef0a3aec6d9b3495d4bdfe3b29d Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Tue, 15 Mar 2022 15:46:31 +0800 Subject: [PATCH] Preserve task when clearing top activities There is no guarantee that clear-top won't finish all activities in the task, such as the last activity is declared as default launch mode and the intent flags don't have SINGLE_TOP, then it will also be finished. Otherwise when adding the new activity into the detached task, it will cause NPE in onChildPositionChanged because its display content is null. Fixes: 224462770 Test: TaskTests#testPerformClearTop Change-Id: Icfa0390a5881043bc55486347aa2854db100d171 --- services/core/java/com/android/server/wm/Task.java | 4 ++++ .../src/com/android/server/wm/TaskTests.java | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index cd7ebe327c919..00f50ec4975ad 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1623,12 +1623,16 @@ class Task extends TaskFragment { } ActivityRecord performClearTop(ActivityRecord newR, int launchFlags) { + // The task should be preserved for putting new activity in case the last activity is + // finished if it is normal launch mode and not single top ("clear-task-top"). + mReuseTask = true; mTaskSupervisor.beginDeferResume(); final ActivityRecord result; try { result = clearTopActivities(newR, launchFlags); } finally { mTaskSupervisor.endDeferResume(); + mReuseTask = false; } return result; } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 636c6bc77e0a2..9304761fc1c96 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -258,6 +258,20 @@ public class TaskTests extends WindowTestsBase { assertNull(task1.isInTask(activity2)); } + @Test + public void testPerformClearTop() { + final Task task = createTask(mDisplayContent); + final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build(); + final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build(); + // Detach from process so the activities can be removed from hierarchy when finishing. + activity1.detachFromProcess(); + activity2.detachFromProcess(); + assertNull(task.performClearTop(activity1, 0 /* launchFlags */)); + assertFalse(task.hasChild()); + // In real case, the task should be preserved for adding new activity. + assertTrue(task.isAttached()); + } + @Test public void testRemoveChildForOverlayTask() { final Task task = createTask(mDisplayContent);