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

Commit aa5df3bb authored by Chris Li's avatar Chris Li Committed by Automerger Merge Worker
Browse files

Merge "Fix system crash when ActivityEmbedding process died with pending...

Merge "Fix system crash when ActivityEmbedding process died with pending events" into tm-qpr-dev am: 77f46df3

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20224010



Change-Id: I06dbce4dde92a527669c8659bbe88f8fdd423a8d
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 7f97c651 77f46df3
Loading
Loading
Loading
Loading
+27 −11
Original line number Diff line number Diff line
@@ -184,14 +184,25 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
        }

        void dispose() {
            while (!mOrganizedTaskFragments.isEmpty()) {
                final TaskFragment taskFragment = mOrganizedTaskFragments.get(0);
                // Cleanup before remove to prevent it from sending any additional event, such as
                // #onTaskFragmentVanished, to the removed organizer.
            for (int i = mOrganizedTaskFragments.size() - 1; i >= 0; i--) {
                // Cleanup the TaskFragmentOrganizer from all TaskFragments it organized before
                // removing the windows to prevent it from adding any additional TaskFragment
                // pending event.
                final TaskFragment taskFragment = mOrganizedTaskFragments.get(i);
                taskFragment.onTaskFragmentOrganizerRemoved();
            }

            // Defer to avoid unnecessary layout when there are multiple TaskFragments removal.
            mAtmService.deferWindowLayout();
            try {
                while (!mOrganizedTaskFragments.isEmpty()) {
                    final TaskFragment taskFragment = mOrganizedTaskFragments.remove(0);
                    taskFragment.removeImmediately();
                mOrganizedTaskFragments.remove(taskFragment);
                }
            } finally {
                mAtmService.continueWindowLayout();
            }

            for (int i = mDeferredTransitions.size() - 1; i >= 0; i--) {
                // Cleanup any running transaction to unblock the current transition.
                onTransactionFinished(mDeferredTransitions.keyAt(i));
@@ -426,7 +437,6 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr

    @Override
    public void unregisterOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
        validateAndGetState(organizer);
        final int pid = Binder.getCallingPid();
        final long uid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
@@ -697,11 +707,17 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
    }

    private void removeOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
        final TaskFragmentOrganizerState state = validateAndGetState(organizer);
        final TaskFragmentOrganizerState state = mTaskFragmentOrganizerState.get(
                organizer.asBinder());
        if (state == null) {
            Slog.w(TAG, "The organizer has already been removed.");
            return;
        }
        // Remove any pending event of this organizer first because state.dispose() may trigger
        // event dispatch as result of surface placement.
        mPendingTaskFragmentEvents.remove(organizer.asBinder());
        // remove all of the children of the organized TaskFragment
        state.dispose();
        // Remove any pending event of this organizer.
        mPendingTaskFragmentEvents.remove(organizer.asBinder());
        mTaskFragmentOrganizerState.remove(organizer.asBinder());
    }

+46 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -91,6 +92,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;

import java.util.List;

@@ -761,6 +763,50 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
        assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
    }

    @Test
    public void testOrganizerRemovedWithPendingEvents() {
        final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
                .setCreateParentTask()
                .setOrganizer(mOrganizer)
                .setFragmentToken(mFragmentToken)
                .build();
        final TaskFragment tf1 = new TaskFragmentBuilder(mAtm)
                .setCreateParentTask()
                .setOrganizer(mOrganizer)
                .setFragmentToken(new Binder())
                .build();
        assertTrue(tf0.isOrganizedTaskFragment());
        assertTrue(tf1.isOrganizedTaskFragment());
        assertTrue(tf0.isAttached());
        assertTrue(tf0.isAttached());

        // Mock the behavior that remove TaskFragment can trigger event dispatch.
        final Answer<Void> removeImmediately = invocation -> {
            invocation.callRealMethod();
            mController.dispatchPendingEvents();
            return null;
        };
        doAnswer(removeImmediately).when(tf0).removeImmediately();
        doAnswer(removeImmediately).when(tf1).removeImmediately();

        // Add pending events.
        mController.onTaskFragmentAppeared(mIOrganizer, tf0);
        mController.onTaskFragmentAppeared(mIOrganizer, tf1);

        // Remove organizer.
        mController.unregisterOrganizer(mIOrganizer);
        mController.dispatchPendingEvents();

        // Nothing should happen after the organizer is removed.
        verify(mOrganizer, never()).onTransactionReady(any());

        // TaskFragments should be removed.
        assertFalse(tf0.isOrganizedTaskFragment());
        assertFalse(tf1.isOrganizedTaskFragment());
        assertFalse(tf0.isAttached());
        assertFalse(tf0.isAttached());
    }

    @Test
    public void testTaskFragmentInPip_startActivityInTaskFragment() {
        setupTaskFragmentInPip();