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

Commit b2c45110 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Wait for all destroying activities to kill task process

For example:
Task of package A
 - top translucent activity of package B
 - bottom activity of package A
The activities are in different processes, so B may complete
destroyed earlier than A. If the kill is triggered when receiving
the destroyed of A, B may be died before it completes onStop and
onDestroy. So now wait for both A and B.

Also move cancel-kill from cleanup to handleAppDied to avoid the
pending state getting cleared too early when waiting for multiple
activities to destroy.

Fix: 290938781
Test: atest RecentTasksTest#testRemovePackageByName
Change-Id: Ia0928ebddc6ffa56acc065c0833d660bd275e3f6
parent 7b193950
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -4225,6 +4225,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                Slog.v(TAG_APP, "Keeping entry during removeHistory for activity " + this);
            }
        }
        if (task != null && task.mKillProcessesOnDestroyed) {
            mTaskSupervisor.removeTimeoutOfKillProcessesOnProcessDied(this, task);
        }
        // upgrade transition trigger to task if this is the last activity since it means we are
        // closing the task.
        final WindowContainer trigger = remove && task != null && task.getChildCount() == 1
+17 −10
Original line number Diff line number Diff line
@@ -621,13 +621,6 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
        mFinishingActivities.remove(r);

        stopWaitingForActivityVisible(r);

        final Task task = r.getTask();
        if (task != null && task.mKillProcessesOnDestroyed && task.getTopMostActivity() == r) {
            // The activity is destroyed or its process is died, so cancel the pending kill.
            task.mKillProcessesOnDestroyed = false;
            removeTimeoutOfKillProcessesOnDestroyed(task);
        }
    }

    /** There is no valid launch time, just stop waiting. */
@@ -1910,13 +1903,27 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
        killTaskProcessesIfPossible(task);
    }

    private void removeTimeoutOfKillProcessesOnDestroyed(Task task) {
    void removeTimeoutOfKillProcessesOnProcessDied(@NonNull ActivityRecord r, @NonNull Task task) {
        if (r.packageName.equals(task.getBasePackageName())) {
            task.mKillProcessesOnDestroyed = false;
            mHandler.removeMessages(KILL_TASK_PROCESSES_TIMEOUT_MSG, task);
        }
    }

    void killTaskProcessesOnDestroyedIfNeeded(Task task) {
        if (task == null || !task.mKillProcessesOnDestroyed) return;
        removeTimeoutOfKillProcessesOnDestroyed(task);
        final int[] numDestroyingActivities = new int[1];
        task.forAllActivities(r ->  {
            if (r.finishing && r.lastVisibleTime > 0 && r.attachedToProcess()) {
                numDestroyingActivities[0]++;
            }
        });
        if (numDestroyingActivities[0] > 1) {
            // Skip if there are still destroying activities. When the last activity reports
            // destroyed, the number will be 1 to proceed the kill.
            return;
        }
        mHandler.removeMessages(KILL_TASK_PROCESSES_TIMEOUT_MSG, task);
        killTaskProcessesIfPossible(task);
    }

+6 −2
Original line number Diff line number Diff line
@@ -1030,17 +1030,21 @@ public class RecentTasksTest extends WindowTestsBase {

        // If the task has a non-stopped activity, the removal will wait for its onDestroy.
        final Task task = tasks.get(0);
        final ActivityRecord bottom = new ActivityBuilder(mAtm).setTask(task).build();
        final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).build();
        top.lastVisibleTime = 123;
        bottom.lastVisibleTime = top.lastVisibleTime = 123;
        top.setState(ActivityRecord.State.RESUMED, "test");
        mRecentTasks.removeTasksByPackageName(task.getBasePackageName(), TEST_USER_0_ID);
        assertTrue(task.mKillProcessesOnDestroyed);
        top.setState(ActivityRecord.State.DESTROYING, "test");
        bottom.destroyed("test");
        assertTrue("Wait for all destroyed", task.mKillProcessesOnDestroyed);
        top.destroyed("test");
        assertFalse(task.mKillProcessesOnDestroyed);
        assertFalse("Consume kill", task.mKillProcessesOnDestroyed);

        // If the process is died, the state should be cleared.
        final Task lastTask = tasks.get(0);
        lastTask.intent.setComponent(top.mActivityComponent);
        lastTask.addChild(top);
        lastTask.mKillProcessesOnDestroyed = true;
        top.handleAppDied();