From 8ef7d3fa6268f509dd1dabf9b352908db048d033 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Wed, 11 Jan 2023 11:58:20 +0000 Subject: [PATCH] Support of restart process of non-top visible activity Since the method restartTaskActivityProcessIfVisible is added, restartProcessIfVisible may not only be called for the top activity. Then if the current top finishes itself, there may be a timing that the restarting state is changed by resuming next. That will break the restart procedure when receiving onStop completion of the target app. By checking if the activity is scheduled to be restarted, the restarting state can be recovered and continue the procedure. Fix: 259042920 Test: SizeCompatTests#testRestartProcessIfVisible Change-Id: Idb5833480e7f029c9da3c3ea6e4d9df911df5a0c --- .../android/server/wm/ActivityClientController.java | 11 +++++++++++ .../com/android/server/wm/ActivityTaskSupervisor.java | 4 ++++ .../src/com/android/server/wm/SizeCompatTests.java | 9 +++++++++ 3 files changed, 24 insertions(+) diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index a16e659610135..49ac2c1f7d969 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -46,6 +46,7 @@ import static com.android.server.wm.ActivityRecord.State.DESTROYING; 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.ActivityRecord.State.STOPPING; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; @@ -240,11 +241,21 @@ class ActivityClientController extends IActivityClientController.Stub { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityStopped"); r = ActivityRecord.isInRootTaskLocked(token); if (r != null) { + if (!r.isState(STOPPING, RESTARTING_PROCESS) + && mTaskSupervisor.hasScheduledRestartTimeouts(r)) { + // Recover the restarting state which was replaced by other lifecycle changes. + r.setState(RESTARTING_PROCESS, "continue-restart"); + } if (r.attachedToProcess() && r.isState(RESTARTING_PROCESS)) { // The activity was requested to restart from // {@link #restartActivityProcessIfVisible}. restartingName = r.app.mName; restartingUid = r.app.mUid; + // Make EnsureActivitiesVisibleHelper#makeVisibleAndRestartIfNeeded not skip + // restarting non-top activity. + if (r != r.getTask().topRunningActivity()) { + r.setVisibleRequested(false); + } } r.activityStopped(icicle, persistentState, description); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 103b9b29379bf..f14b550e18d8b 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -2243,6 +2243,10 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { mHandler.sendEmptyMessageDelayed(SLEEP_TIMEOUT_MSG, SLEEP_TIMEOUT); } + boolean hasScheduledRestartTimeouts(ActivityRecord r) { + return mHandler.hasMessages(RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG, r); + } + void removeRestartTimeouts(ActivityRecord r) { mHandler.removeMessages(RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG, r); } diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 113f5ecbc9f56..3eb7fe3b0021a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -295,6 +295,15 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(RESTARTING_PROCESS, mActivity.getState()); assertNotEquals(originalOverrideBounds, mActivity.getBounds()); + + // Even if the state is changed (e.g. a floating activity on top is finished and make it + // resume), the restart procedure should recover the state and continue to kill the process. + mActivity.setState(RESUMED, "anyStateChange"); + doReturn(true).when(mSupervisor).hasScheduledRestartTimeouts(mActivity); + mAtm.mActivityClientController.activityStopped(mActivity.token, null /* icicle */, + null /* persistentState */, null /* description */); + assertEquals(RESTARTING_PROCESS, mActivity.getState()); + verify(mSupervisor).removeRestartTimeouts(mActivity); } @Test