Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84be5ace authored by Andrii Kulian's avatar Andrii Kulian Committed by android-build-merger
Browse files

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

am: 756a8860

Change-Id: Ife9d23460a925b466d8f243bd51819d77f2f7e47
parents 899a4c2a 756a8860
Loading
Loading
Loading
Loading
+9 −1
Original line number Original line Diff line number Diff line
@@ -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) {
+11 −4
Original line number Original line Diff line number Diff line
@@ -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;
                }
                }
+2 −2
Original line number Original line Diff line number Diff line
@@ -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;
            }
            }
+22 −0
Original line number Original line Diff line number Diff line
@@ -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());
    }
}
}