From 9c62ef63fdafcb806c0ca8486429fc44bd9454ea Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Mon, 10 Aug 2020 16:21:16 +0800 Subject: [PATCH] Resume next activity if pausing app died If the top activity is crashed before showing any window, when its process reported dead, it will be regarded as no visible activity and no need to resume next activity. That may lead to the next top activity remains in paused state and may be unresponsive. Bug: 159951007 Test: atest ActivityTaskManagerServiceTests# \ testResumeNextActivityOnCrashedAppDied Change-Id: I635fceb9cf7b782f6ffbb9ebef7cb69053f64a0b Merged-In: I635fceb9cf7b782f6ffbb9ebef7cb69053f64a0b (cherry picked from commit f2e7da7a641ae6bf2b49fa487cc56e6fe20b3336) --- .../com/android/server/wm/ActivityStack.java | 7 ++++-- .../wm/ActivityTaskManagerServiceTests.java | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index e9768a26f571a..e7e08f3f68d85 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -2726,13 +2726,15 @@ class ActivityStack extends Task { /** * Reset local parameters because an app's activity died. * @param app The app of the activity that died. - * @return result from removeHistoryRecordsForAppLocked. + * @return {@code true} if the process has any visible activity. */ boolean handleAppDied(WindowProcessController app) { + boolean isPausingDied = false; if (mPausingActivity != null && mPausingActivity.app == app) { if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE, "App died while pausing: " + mPausingActivity); mPausingActivity = null; + isPausingDied = true; } if (mLastPausedActivity != null && mLastPausedActivity.app == app) { mLastPausedActivity = null; @@ -2740,7 +2742,8 @@ class ActivityStack extends Task { } mStackSupervisor.removeHistoryRecords(app); - return mRemoveHistoryRecordsForApp.process(app); + final boolean hadVisibleActivities = mRemoveHistoryRecordsForApp.process(app); + return hadVisibleActivities || isPausingDied; } boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index f65d6e0c82af5..48be58f422539 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -225,5 +225,27 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase { mockSession.finishMocking(); } + + @Test + public void testResumeNextActivityOnCrashedAppDied() { + mSupervisor.beginDeferResume(); + final ActivityRecord homeActivity = new ActivityBuilder(mService) + .setTask(mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()) + .build(); + final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true).build(); + mSupervisor.endDeferResume(); + // Assume the activity is finishing and hidden because it was crashed. + activity.finishing = true; + activity.mVisibleRequested = false; + activity.setVisible(false); + activity.getRootTask().mPausingActivity = activity; + homeActivity.setState(ActivityStack.ActivityState.PAUSED, "test"); + + // Even the visibility states are invisible, the next activity should be resumed because + // the crashed activity was pausing. + mService.mInternal.handleAppDied(activity.app, false /* restarting */, + null /* finishInstrumentationCallback */); + assertEquals(ActivityStack.ActivityState.RESUMED, homeActivity.getState()); + } }