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

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

Avoid killing task process after its activity was died

Some tests may have the order:
1. removeTask in tearDown
   Schedule KILL_TASK_PROCESSES_TIMEOUT_MSG to wait for the
   activity to be destroyed.
2. forceStopPackage in tearDown
   The process is forced killed, but the scheduled timeout is
   not cleared.
3. Launch the app again in a short time
   If the timeout reaches before the activity attached to
   the new process, the process will be killed so the test
   is failed due to target activity not detected.

Originally the pending-kill state is consumed (clear flag and kill
task processes) only when the activity is destroyed. So this change
ensures it is done by the general cleanup that is also called when
the process died.

Bug: 293280011
Test: atest RecentTasksTest#testRemovePackageByName
Merged-In: I8cf8d67cc7cd39b6cc8db91498dc901f494ae85e
Change-Id: I8cf8d67cc7cd39b6cc8db91498dc901f494ae85e
parent 55722bf5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -4214,6 +4214,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
+20 −2
Original line number Diff line number Diff line
@@ -1891,7 +1891,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
        // DestroyActivityItem may be called first.
        final ActivityRecord top = task.getTopMostActivity();
        if (top != null && top.finishing && !top.mAppStopped && top.lastVisibleTime > 0
                && !task.mKillProcessesOnDestroyed) {
                && !task.mKillProcessesOnDestroyed && top.hasProcess()) {
            task.mKillProcessesOnDestroyed = true;
            mHandler.sendMessageDelayed(
                    mHandler.obtainMessage(KILL_TASK_PROCESSES_TIMEOUT_MSG, task),
@@ -1901,8 +1901,26 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
        killTaskProcessesIfPossible(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;
        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);
    }
@@ -2763,7 +2781,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
                } break;
                case KILL_TASK_PROCESSES_TIMEOUT_MSG: {
                    final Task task = (Task) msg.obj;
                    if (task.mKillProcessesOnDestroyed) {
                    if (task.mKillProcessesOnDestroyed && task.hasActivity()) {
                        Slog.i(TAG, "Destroy timeout of remove-task, attempt to kill " + task);
                        killTaskProcessesIfPossible(task);
                    }
+13 −2
Original line number Diff line number Diff line
@@ -1040,14 +1040,25 @@ 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();
        assertFalse(lastTask.mKillProcessesOnDestroyed);
    }

    @Test