Loading services/core/java/com/android/server/wm/Task.java +5 −1 Original line number Diff line number Diff line Loading @@ -7056,17 +7056,21 @@ class Task extends WindowContainer<WindowContainer> { /** * Reset local parameters because an app's activity died. * @param app The app of the activity that died. * @return {@code true} if the process of the pausing activity is died. */ void handleAppDied(WindowProcessController app) { 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; mLastNoHistoryActivity = null; } return isPausingDied; } boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, Loading services/core/java/com/android/server/wm/WindowProcessController.java +4 −1 Original line number Diff line number Diff line Loading @@ -1201,7 +1201,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio final Task rootTask = r.getRootTask(); if (rootTask != null) { rootTask.handleAppDied(this); // There may be a pausing activity that hasn't shown any window and was requested // to be hidden. But pausing is also a visible state, it should be regarded as // visible, so the caller can know the next activity should be resumed. hasVisibleActivities |= rootTask.handleAppDied(this); } r.handleAppDied(); } Loading services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +22 −0 Original line number Diff line number Diff line Loading @@ -225,5 +225,27 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { mockSession.finishMocking(); } @Test public void testResumeNextActivityOnCrashedAppDied() { mSupervisor.beginDeferResume(); final ActivityRecord homeActivity = new ActivityBuilder(mAtm) .setTask(mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()) .build(); final ActivityRecord activity = new ActivityBuilder(mAtm).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(Task.ActivityState.PAUSED, "test"); // Even the visibility states are invisible, the next activity should be resumed because // the crashed activity was pausing. mAtm.mInternal.handleAppDied(activity.app, false /* restarting */, null /* finishInstrumentationCallback */); assertEquals(Task.ActivityState.RESUMED, homeActivity.getState()); } } Loading
services/core/java/com/android/server/wm/Task.java +5 −1 Original line number Diff line number Diff line Loading @@ -7056,17 +7056,21 @@ class Task extends WindowContainer<WindowContainer> { /** * Reset local parameters because an app's activity died. * @param app The app of the activity that died. * @return {@code true} if the process of the pausing activity is died. */ void handleAppDied(WindowProcessController app) { 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; mLastNoHistoryActivity = null; } return isPausingDied; } boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, Loading
services/core/java/com/android/server/wm/WindowProcessController.java +4 −1 Original line number Diff line number Diff line Loading @@ -1201,7 +1201,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio final Task rootTask = r.getRootTask(); if (rootTask != null) { rootTask.handleAppDied(this); // There may be a pausing activity that hasn't shown any window and was requested // to be hidden. But pausing is also a visible state, it should be regarded as // visible, so the caller can know the next activity should be resumed. hasVisibleActivities |= rootTask.handleAppDied(this); } r.handleAppDied(); } Loading
services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +22 −0 Original line number Diff line number Diff line Loading @@ -225,5 +225,27 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { mockSession.finishMocking(); } @Test public void testResumeNextActivityOnCrashedAppDied() { mSupervisor.beginDeferResume(); final ActivityRecord homeActivity = new ActivityBuilder(mAtm) .setTask(mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()) .build(); final ActivityRecord activity = new ActivityBuilder(mAtm).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(Task.ActivityState.PAUSED, "test"); // Even the visibility states are invisible, the next activity should be resumed because // the crashed activity was pausing. mAtm.mInternal.handleAppDied(activity.app, false /* restarting */, null /* finishInstrumentationCallback */); assertEquals(Task.ActivityState.RESUMED, homeActivity.getState()); } }