Loading services/core/java/com/android/server/am/ActivityStack.java +9 −1 Original line number Original line Diff line number Diff line Loading @@ -3544,7 +3544,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mService.updateOomAdjLocked(); mService.updateOomAdjLocked(); } } final TaskRecord finishTopRunningActivityLocked(ProcessRecord app, String reason) { /** * Finish the topmost activity that belongs to the crashed app. We may also finish the activity * that requested launch of the crashed one to prevent launch-crash loop. * @param app The app that crashed. * @param reason Reason to perform this action. * @return The task that was finished in this stack, {@code null} if top running activity does * not belong to the crashed app. */ final TaskRecord finishTopCrashedActivityLocked(ProcessRecord app, String reason) { ActivityRecord r = topRunningActivityLocked(); ActivityRecord r = topRunningActivityLocked(); TaskRecord finishedTask = null; TaskRecord finishedTask = null; if (r == null || r.app != app) { if (r == null || r.app != app) { Loading services/core/java/com/android/server/am/ActivityStackSupervisor.java +11 −4 Original line number Original line Diff line number Diff line Loading @@ -2126,15 +2126,22 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } } } TaskRecord finishTopRunningActivityLocked(ProcessRecord app, String reason) { /** * Finish the topmost activities in all stacks that belong to the crashed app. * @param app The app that crashed. * @param reason Reason to perform this action. * @return The task that was finished in this stack, {@code null} if haven't found any. */ TaskRecord finishTopCrashedActivitiesLocked(ProcessRecord app, String reason) { TaskRecord finishedTask = null; TaskRecord finishedTask = null; ActivityStack focusedStack = getFocusedStack(); ActivityStack focusedStack = getFocusedStack(); for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); final int numStacks = display.getChildCount(); // It is possible that request to finish activity might also remove its task and stack, for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { // so we need to be careful with indexes in the loop and check child count every time. for (int stackNdx = 0; stackNdx < display.getChildCount(); ++stackNdx) { final ActivityStack stack = display.getChildAt(stackNdx); final ActivityStack stack = display.getChildAt(stackNdx); TaskRecord t = stack.finishTopRunningActivityLocked(app, reason); final TaskRecord t = stack.finishTopCrashedActivityLocked(app, reason); if (stack == focusedStack || finishedTask == null) { if (stack == focusedStack || finishedTask == null) { finishedTask = t; finishedTask = t; } } Loading services/core/java/com/android/server/am/AppErrors.java +2 −2 Original line number Original line Diff line number Diff line Loading @@ -742,8 +742,8 @@ class AppErrors { } } mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); } else { } else { TaskRecord affectedTask = final TaskRecord affectedTask = mService.mStackSupervisor.finishTopRunningActivityLocked(app, reason); mService.mStackSupervisor.finishTopCrashedActivitiesLocked(app, reason); if (data != null) { if (data != null) { data.task = affectedTask; data.task = affectedTask; } } Loading services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +22 −0 Original line number Original line Diff line number Diff line Loading @@ -265,4 +265,26 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { // Supervisor should skip over the non-existent display. // Supervisor should skip over the non-existent display. assertEquals(null, mSupervisor.topRunningActivityLocked()); assertEquals(null, mSupervisor.topRunningActivityLocked()); } } /** * Verifies that removal of activity with task and stack is done correctly. */ @Test public void testRemovingStackOnAppCrash() throws Exception { final ActivityDisplay defaultDisplay = mService.mStackSupervisor.getDefaultDisplay(); final int originalStackCount = defaultDisplay.getChildCount(); final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) .setStack(stack).build(); assertEquals(originalStackCount + 1, defaultDisplay.getChildCount()); // Let's pretend that the app has crashed. firstActivity.app.thread = null; mService.mStackSupervisor.finishTopCrashedActivitiesLocked(firstActivity.app, "test"); // Verify that the stack was removed. assertEquals(originalStackCount, defaultDisplay.getChildCount()); } } } Loading
services/core/java/com/android/server/am/ActivityStack.java +9 −1 Original line number Original line Diff line number Diff line Loading @@ -3544,7 +3544,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mService.updateOomAdjLocked(); mService.updateOomAdjLocked(); } } final TaskRecord finishTopRunningActivityLocked(ProcessRecord app, String reason) { /** * Finish the topmost activity that belongs to the crashed app. We may also finish the activity * that requested launch of the crashed one to prevent launch-crash loop. * @param app The app that crashed. * @param reason Reason to perform this action. * @return The task that was finished in this stack, {@code null} if top running activity does * not belong to the crashed app. */ final TaskRecord finishTopCrashedActivityLocked(ProcessRecord app, String reason) { ActivityRecord r = topRunningActivityLocked(); ActivityRecord r = topRunningActivityLocked(); TaskRecord finishedTask = null; TaskRecord finishedTask = null; if (r == null || r.app != app) { if (r == null || r.app != app) { Loading
services/core/java/com/android/server/am/ActivityStackSupervisor.java +11 −4 Original line number Original line Diff line number Diff line Loading @@ -2126,15 +2126,22 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } } } TaskRecord finishTopRunningActivityLocked(ProcessRecord app, String reason) { /** * Finish the topmost activities in all stacks that belong to the crashed app. * @param app The app that crashed. * @param reason Reason to perform this action. * @return The task that was finished in this stack, {@code null} if haven't found any. */ TaskRecord finishTopCrashedActivitiesLocked(ProcessRecord app, String reason) { TaskRecord finishedTask = null; TaskRecord finishedTask = null; ActivityStack focusedStack = getFocusedStack(); ActivityStack focusedStack = getFocusedStack(); for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); final int numStacks = display.getChildCount(); // It is possible that request to finish activity might also remove its task and stack, for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { // so we need to be careful with indexes in the loop and check child count every time. for (int stackNdx = 0; stackNdx < display.getChildCount(); ++stackNdx) { final ActivityStack stack = display.getChildAt(stackNdx); final ActivityStack stack = display.getChildAt(stackNdx); TaskRecord t = stack.finishTopRunningActivityLocked(app, reason); final TaskRecord t = stack.finishTopCrashedActivityLocked(app, reason); if (stack == focusedStack || finishedTask == null) { if (stack == focusedStack || finishedTask == null) { finishedTask = t; finishedTask = t; } } Loading
services/core/java/com/android/server/am/AppErrors.java +2 −2 Original line number Original line Diff line number Diff line Loading @@ -742,8 +742,8 @@ class AppErrors { } } mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); } else { } else { TaskRecord affectedTask = final TaskRecord affectedTask = mService.mStackSupervisor.finishTopRunningActivityLocked(app, reason); mService.mStackSupervisor.finishTopCrashedActivitiesLocked(app, reason); if (data != null) { if (data != null) { data.task = affectedTask; data.task = affectedTask; } } Loading
services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +22 −0 Original line number Original line Diff line number Diff line Loading @@ -265,4 +265,26 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { // Supervisor should skip over the non-existent display. // Supervisor should skip over the non-existent display. assertEquals(null, mSupervisor.topRunningActivityLocked()); assertEquals(null, mSupervisor.topRunningActivityLocked()); } } /** * Verifies that removal of activity with task and stack is done correctly. */ @Test public void testRemovingStackOnAppCrash() throws Exception { final ActivityDisplay defaultDisplay = mService.mStackSupervisor.getDefaultDisplay(); final int originalStackCount = defaultDisplay.getChildCount(); final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) .setStack(stack).build(); assertEquals(originalStackCount + 1, defaultDisplay.getChildCount()); // Let's pretend that the app has crashed. firstActivity.app.thread = null; mService.mStackSupervisor.finishTopCrashedActivitiesLocked(firstActivity.app, "test"); // Verify that the stack was removed. assertEquals(originalStackCount, defaultDisplay.getChildCount()); } } }