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
This commit is contained in:
Riddle Hsu
2023-01-11 11:58:20 +00:00
parent b0f1e19c1a
commit 8ef7d3fa62
3 changed files with 24 additions and 0 deletions

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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