Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8afd1531 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Avoid requesting stop for finishing activity

The problem is that removeTask is called on a task with an activity
which is finishing and stopping. Because it is already finishing,
the steps of removeTask are skipped. If the activity is removed
from mStoppingActivities, then the activity won't proceed to destroy.

Bug: 309136273
Test: atest ActivityTaskSupervisorTests#testRemoveTask
Test: CtsWindowManagerDeviceActivity:ActivityLifecycleTests \
      #testRelaunchConfigurationChangedWhileBecomingVisible
      There should have wm_on_destroy_called for SecondActivity.

Change-Id: If13d893ae7eb4cc4105f5554a6e3ed6aae728df7
parent cf01f294
Loading
Loading
Loading
Loading
+14 −12
Original line number Diff line number Diff line
@@ -6434,10 +6434,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A

    void stopIfPossible() {
        if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + this);
        final Task rootTask = getRootTask();
        if (finishing) {
            Slog.e(TAG, "Request to stop a finishing activity: " + this);
            destroyIfPossible("stopIfPossible-finishing");
            return;
        }
        if (isNoHistory()) {
            if (!finishing) {
                if (!rootTask.shouldSleepActivities()) {
            if (!task.shouldSleepActivities()) {
                ProtoLog.d(WM_DEBUG_STATES, "no-history finish of %s", this);
                if (finishIfPossible("stop-no-history", false /* oomAdj */)
                        != FINISH_RESULT_CANCELLED) {
@@ -6449,7 +6452,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                        + "because we're just sleeping", this);
            }
        }
        }

        if (!attachedToProcess()) {
            return;
+2 −1
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.wm.ActivityRecord.State.PAUSED;
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.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
@@ -1681,7 +1682,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
            ArrayList<ActivityRecord> activities = null;
            for (int i = mStoppingActivities.size() - 1; i >= 0; i--) {
                final ActivityRecord r = mStoppingActivities.get(i);
                if (r.getTask() == task) {
                if (!r.finishing && r.isState(RESUMED) && r.getTask() == task) {
                    if (activities == null) {
                        activities = new ArrayList<>();
                    }
+27 −0
Original line number Diff line number Diff line
@@ -201,6 +201,33 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase {
        verify(taskChangeNotifier, never()).notifyActivityDismissingDockedRootTask();
    }

    /** Verifies that the activity can be destroying after removing task. */
    @Test
    public void testRemoveTask() {
        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
        activity1.setVisible(false);
        activity1.finishing = true;
        activity1.setState(ActivityRecord.State.STOPPING, "test");
        activity1.addToStopping(false /* scheduleIdle */, false /* idleDelayed */, "test");
        final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
        activity2.setState(ActivityRecord.State.RESUMED, "test");
        // The state can happen from ActivityRecord#makeInvisible.
        activity2.addToStopping(false /* scheduleIdle */, false /* idleDelayed */, "test");
        mSupervisor.removeTask(activity1.getTask(), true /* killProcess */,
                true /* removeFromRecents */, "testRemoveTask");
        mSupervisor.removeTask(activity2.getTask(), true /* killProcess */,
                true /* removeFromRecents */, "testRemoveTask");

        assertEquals(ActivityRecord.State.DESTROYING, activity2.getState());
        assertEquals(ActivityRecord.State.STOPPING, activity1.getState());
        assertTrue(mSupervisor.mStoppingActivities.contains(activity1));
        // Assume that it is called by scheduleIdle from addToStopping. And because
        // mStoppingActivities remembers the finishing activity, it can continue to destroy.
        mSupervisor.processStoppingAndFinishingActivities(null /* launchedActivity */,
                false /* processPausingActivities */, "test");
        assertEquals(ActivityRecord.State.DESTROYING, activity1.getState());
    }

    /** Ensures that the calling package name passed to client complies with package visibility. */
    @Test
    public void testFilteredReferred() {