Merge "Prevent exception when stack being removed on crash" into pi-dev am: 6acf543681

am: 756a886015

Change-Id: Ife9d23460a925b466d8f243bd51819d77f2f7e47
This commit is contained in:
Andrii Kulian
2018-04-03 20:32:24 -07:00
committed by android-build-merger
4 changed files with 44 additions and 7 deletions

View File

@@ -3544,7 +3544,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
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();
TaskRecord finishedTask = null;
if (r == null || r.app != app) {

View File

@@ -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;
ActivityStack focusedStack = getFocusedStack();
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
final int numStacks = display.getChildCount();
for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
// It is possible that request to finish activity might also remove its task and stack,
// 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);
TaskRecord t = stack.finishTopRunningActivityLocked(app, reason);
final TaskRecord t = stack.finishTopCrashedActivityLocked(app, reason);
if (stack == focusedStack || finishedTask == null) {
finishedTask = t;
}

View File

@@ -742,8 +742,8 @@ class AppErrors {
}
mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
} else {
TaskRecord affectedTask =
mService.mStackSupervisor.finishTopRunningActivityLocked(app, reason);
final TaskRecord affectedTask =
mService.mStackSupervisor.finishTopCrashedActivitiesLocked(app, reason);
if (data != null) {
data.task = affectedTask;
}

View File

@@ -265,4 +265,26 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase {
// Supervisor should skip over the non-existent display.
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());
}
}