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

Commit c9de96ab authored by wilsonshih's avatar wilsonshih Committed by Wei Sheng Shih
Browse files

Fixes unable remove starting window due to transferStartingWindow

When starting two activities for embedded activity, it's possible for
the starting window to be transferred to the second launched activity
before the starting window is created.
This causes Shell to receive two addStartingWindow requests for
different app tokens, and WindowManager rejects the first request for
the first launched activity because the startingData is transferred to
the second activity.
To prevent the window record from being removed too early, also track
the current app token, and only stop tracking when all creation
requests have failed.

Also fixes the testRemoveStartingInShell, there should wait for the
TransactionCommittedListener to be added to the main execute queue
before flushing.

Bug: 413589384
Bug: 414192230
Flag: com.android.window.flags.remove_starting_in_transition
Test: atest FlickerTestsActivityEmbedding
Test: atest StartingWindowControllerTests
Change-Id: I48ece2a089068e2101c6bf5f755020e1204bf713
parent 6e14ced4
Loading
Loading
Loading
Loading
+35 −11
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.graphics.Color;
import android.os.IBinder;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.SurfaceControl;
@@ -210,14 +211,27 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
            }
        }

        void onAddingWindow(int taskId, IBinder transitionToken) {
            mWindowRecords.put(taskId, new WindowRecord(taskId, transitionToken));
        void onAddingWindow(int taskId, IBinder transitionToken, IBinder appToken) {
            final WindowRecord wr = mWindowRecords.get(taskId);
            if (wr != null) {
                wr.addAppToken(appToken);
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_REMOVE_STARTING_TRACKER,
                        "RSO:Start tracking appToken=%s for task=%d", appToken, taskId);
            } else {
                mWindowRecords.put(taskId, new WindowRecord(taskId, transitionToken, appToken));
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_REMOVE_STARTING_TRACKER,
                        "RSO:Start tracking for task=%d", taskId);
            }
        }

        // Stop tracking because the window is not created.
        void forceRemoveWindow(int taskId) {
        void forceRemoveWindow(int taskId, IBinder appToken) {
            final WindowRecord wr = mWindowRecords.get(taskId);
            if (wr == null || !wr.removeAppToken(appToken)) {
                return;
            }
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_REMOVE_STARTING_TRACKER,
                    "RSO:Window wasn't created, removal record task=%d", taskId);
            mWindowRecords.remove(taskId);
        }

@@ -289,9 +303,21 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
            boolean mTransactionApplied;
            StartingWindowRemovalInfo mStartingWindowRemovalInfo;

            WindowRecord(int taskId, IBinder transition) {
            final ArraySet<IBinder> mAppTokens = new ArraySet<>();

            WindowRecord(int taskId, IBinder transition, IBinder appToken) {
                mTaskId = taskId;
                mTransition = transition;
                addAppToken(appToken);
            }

            void addAppToken(IBinder token) {
                mAppTokens.add(token);
            }

            boolean removeAppToken(IBinder token) {
                mAppTokens.remove(token);
                return mAppTokens.isEmpty();
            }
        }
    }
@@ -326,8 +352,8 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
     */
    public void addStartingWindow(StartingWindowInfo windowInfo) {
        if (Flags.removeStartingInTransition()) {
            mShellMainExecutor.execute(() -> mRemoveStartingObserver
                    .onAddingWindow(windowInfo.taskInfo.taskId, windowInfo.transitionToken));
            mShellMainExecutor.execute(() -> mRemoveStartingObserver.onAddingWindow(
                    windowInfo.taskInfo.taskId, windowInfo.transitionToken, windowInfo.appToken));
        }
        mSplashScreenExecutor.execute(() -> {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addStartingWindow");
@@ -360,10 +386,8 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
            }
            if (Flags.removeStartingInTransition()) {
                if (!mStartingSurfaceDrawer.hasStartingWindow(taskId, isWindowless)) {
                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_REMOVE_STARTING_TRACKER,
                            "RSO:Window wasn't created, removal record task=%d", taskId);
                    mShellMainExecutor.execute(() ->
                            mRemoveStartingObserver.forceRemoveWindow(taskId));
                            mRemoveStartingObserver.forceRemoveWindow(taskId, windowInfo.appToken));
                }
            }
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+10 −13
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.hardware.display.DisplayManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.SystemClock;
import android.os.UserManager;
import android.platform.test.annotations.EnableFlags;
import android.view.Display;
@@ -66,9 +67,6 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * Tests for the starting window controller.
 *
@@ -141,6 +139,7 @@ public class StartingWindowControllerTests extends ShellTestCase {
    public void testRemoveStartingInShell() {
        final int taskId = 1;
        final IBinder token = new Binder();
        final IBinder appToken = new Binder();
        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
                .addChange(TRANSIT_OPEN).build();
        final StartingWindowRemovalInfo removalInfo = new StartingWindowRemovalInfo();
@@ -149,7 +148,7 @@ public class StartingWindowControllerTests extends ShellTestCase {
        final StartingWindowController.RemoveStartingObserver observer =
                mController.mRemoveStartingObserver;

        observer.onAddingWindow(taskId, token);
        observer.onAddingWindow(taskId, token, appToken);
        observer.onTransitionReady(token, info, st, st);
        waitTransactionCommit(st);
        assertTrue(observer.hasPendingRemoval());
@@ -157,7 +156,7 @@ public class StartingWindowControllerTests extends ShellTestCase {
        assertFalse(observer.hasPendingRemoval());

        st.clear();
        observer.onAddingWindow(taskId, token);
        observer.onAddingWindow(taskId, token, appToken);
        observer.requestRemoval(taskId, removalInfo);
        observer.onTransitionReady(token, info, st, st);
        assertTrue(observer.hasPendingRemoval());
@@ -171,7 +170,7 @@ public class StartingWindowControllerTests extends ShellTestCase {
        final TransitionInfo secondInfo = new TransitionInfoBuilder(TRANSIT_OPEN)
                .addChange(TRANSIT_OPEN, FLAG_IS_BEHIND_STARTING_WINDOW,
                        null, null, null).build();
        observer.onAddingWindow(taskId, token);
        observer.onAddingWindow(taskId, token, appToken);
        observer.onTransitionReady(token, info, st, st);
        waitTransactionCommit(st);
        observer.onTransitionReady(secondToken, secondInfo, st, st);
@@ -181,7 +180,7 @@ public class StartingWindowControllerTests extends ShellTestCase {
        assertFalse(observer.hasPendingRemoval());

        st.clear();
        observer.onAddingWindow(taskId, token);
        observer.onAddingWindow(taskId, token, appToken);
        observer.onTransitionReady(token, info, st, st);
        waitTransactionCommit(st);
        observer.onTransitionReady(secondToken, secondInfo, st, st);
@@ -192,13 +191,11 @@ public class StartingWindowControllerTests extends ShellTestCase {
    }

    private void waitTransactionCommit(SurfaceControl.Transaction st) {
        final CountDownLatch waitCommit = new CountDownLatch(1);
        st.addTransactionCommittedListener(Runnable::run, waitCommit::countDown);
        st.apply();
        try {
            waitCommit.await(3L, TimeUnit.SECONDS);
        } catch (InterruptedException ex) {
            throw new AssertionError("Test interrupted", ex);
        final long timeout = SystemClock.currentTimeMicro() + 500L;
        while (mMainExecutor.getCallbacks().isEmpty()
                && SystemClock.currentTimeMicro() < timeout) {
            SystemClock.sleep(50);
        }
        mMainExecutor.flushAll();
    }