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

Commit dcb1fcf2 authored by Yunfan Chen's avatar Yunfan Chen
Browse files

Fix flaky AppWindowTokenTests

The only one failure test is marked with corresponding bug ID. Other
flakiness are fixed.

We need to push a guard task when waiting for handler empty to ensure
all the posted tasks is finished after calling the waitHandlerIdle.
Otherwise, it is possible that the assertion happens before the posted
runnable method finished, which will cause fail, and flakiness.

There was a change by default skip onParentChange call for
TestAppWindowToken which breaks the tests. Set the flag correctly in
setUp fixed it.

Bug: 69229402
Bug: 68267650
Test: atest AppWindowTokenTests. All tests other than flaky one should
get a stable pass.

Change-Id: If485232d676604ec4a5b8d2c9e097fd9794d916e
parent 6a41c383
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -1657,10 +1657,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
            final ActivityManager.TaskSnapshot snapshot = snapshotCtrl.getSnapshot(
                    getTask().mTaskId, getTask().mUserId, false /* restoreFromDisk */,
                    false /* reducedResolution */);
            if (snapshot != null) {
                mThumbnail = new AppWindowThumbnail(t, this, snapshot.getSnapshot(),
                        true /* relative */);
            }
        }
    }

    boolean isInChangeTransition() {
        return mTransitChangeLeash != null || isChangeTransition(mTransit);
+3 −1
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ import org.junit.Test;
 * Build/Install/Run:
 *  atest FrameworksServicesTests:AppWindowTokenTests
 */
@FlakyTest(bugId = 68267650)
@SmallTest
@Presubmit
public class AppWindowTokenTests extends WindowTestsBase {
@@ -79,6 +78,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
        mTask = createTaskInStack(mStack, 0 /* userId */);
        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);

        mToken.mSkipOnParentChanged = false;
        mTask.addChild(mToken, 0);
    }

@@ -303,6 +303,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
        assertNoStartingWindow(mToken);
    }

    @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
    @Test
    public void testAddRemoveRace() {
        // There was once a race condition between adding and removing starting windows
@@ -387,6 +388,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
        // bottom one.
        tokenTop.setVisibility(false, false);
        tokenBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded();
        waitUntilHandlersIdle();

        // Assert that the bottom window now has the starting window.
        assertNoStartingWindow(tokenTop);
+19 −15
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ import com.android.server.policy.WindowManagerPolicy;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.quality.Strictness;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * A Test utility class to create a mock {@link WindowManagerService} instance for tests.
@@ -71,6 +71,8 @@ class TestSystemServices {
    private static WindowManagerService sService;
    private static TestWindowManagerPolicy sPolicy;

    static AtomicBoolean sCurrentMessagesProcessed = new AtomicBoolean(false);

    static void setUpWindowManagerService() {
        sMockitoSession = mockitoSession()
                .spyStatic(LockGuard.class)
@@ -195,21 +197,23 @@ class TestSystemServices {
    }

    private static void waitHandlerIdle(Handler handler) {
        if (!handler.hasMessagesOrCallbacks()) {
            return;
        }
        final CountDownLatch latch = new CountDownLatch(1);
        // Wait for delayed messages are processed.
        handler.getLooper().getQueue().addIdleHandler(() -> {
            if (handler.hasMessagesOrCallbacks()) {
                return true; // keep idle handler.
        synchronized (sCurrentMessagesProcessed) {
            // Add a message to the handler queue and make sure it is fully processed before we move
            // on. This makes sure all previous messages in the handler are fully processed vs. just
            // popping them from the message queue.
            sCurrentMessagesProcessed.set(false);
            handler.post(() -> {
                synchronized (sCurrentMessagesProcessed) {
                    sCurrentMessagesProcessed.set(true);
                    sCurrentMessagesProcessed.notifyAll();
                }
            latch.countDown();
            return false; // remove idle handler.
            });
            while (!sCurrentMessagesProcessed.get()) {
                try {
            latch.await();
                    sCurrentMessagesProcessed.wait();
                } catch (InterruptedException e) {
                }
            }
        }
    }
}