From f3317557ad3346fc6640136c89e5e4b20abc4670 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Thu, 6 Apr 2023 18:10:09 -0700 Subject: [PATCH] Support test-handler in BLASTSyncEngine and add queue-syncset test Many sync-engine operations post to the main handler which meant we couldn't really test any of these code-paths, so this separates out the handler into a separate member and adds a constructor for tests. Then, using this, add a test for queueSyncSet which has been missing. Bug: 264536014 Test: atest SyncEngineTests Change-Id: I4a00017038c9355799b1f79494169037e38b7d40 --- .../android/server/wm/BLASTSyncEngine.java | 18 +++++--- .../android/server/wm/SyncEngineTests.java | 45 +++++++++++++++++++ .../android/server/wm/WindowTestsBase.java | 7 ++- 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java index 48cf567ba9bed..9920059146e26 100644 --- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java +++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java @@ -23,6 +23,7 @@ import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Handler; import android.os.Trace; import android.util.ArraySet; import android.util.Slog; @@ -172,7 +173,7 @@ class BLASTSyncEngine { if (ran) { return; } - mWm.mH.removeCallbacks(this); + mHandler.removeCallbacks(this); ran = true; SurfaceControl.Transaction t = new SurfaceControl.Transaction(); for (WindowContainer wc : wcAwaitingCommit) { @@ -199,13 +200,13 @@ class BLASTSyncEngine { }; CommitCallback callback = new CommitCallback(); merged.addTransactionCommittedListener((r) -> { r.run(); }, callback::onCommitted); - mWm.mH.postDelayed(callback, BLAST_TIMEOUT_DURATION); + mHandler.postDelayed(callback, BLAST_TIMEOUT_DURATION); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionReady"); mListener.onTransactionReady(mSyncId, merged); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); mActiveSyncs.remove(mSyncId); - mWm.mH.removeCallbacks(mOnTimeout); + mHandler.removeCallbacks(mOnTimeout); // Immediately start the next pending sync-transaction if there is one. if (mActiveSyncs.size() == 0 && !mPendingSyncSets.isEmpty()) { @@ -216,7 +217,7 @@ class BLASTSyncEngine { throw new IllegalStateException("Pending Sync Set didn't start a sync."); } // Post this so that the now-playing transition setup isn't interrupted. - mWm.mH.post(() -> { + mHandler.post(() -> { synchronized (mWm.mGlobalLock) { pt.mApplySync.run(); } @@ -269,6 +270,7 @@ class BLASTSyncEngine { } private final WindowManagerService mWm; + private final Handler mHandler; private int mNextSyncId = 0; private final SparseArray mActiveSyncs = new SparseArray<>(); @@ -280,7 +282,13 @@ class BLASTSyncEngine { private final ArrayList mPendingSyncSets = new ArrayList<>(); BLASTSyncEngine(WindowManagerService wms) { + this(wms, wms.mH); + } + + @VisibleForTesting + BLASTSyncEngine(WindowManagerService wms, Handler mainHandler) { mWm = wms; + mHandler = mainHandler; } /** @@ -325,7 +333,7 @@ class BLASTSyncEngine { @VisibleForTesting void scheduleTimeout(SyncGroup s, long timeoutMs) { - mWm.mH.postDelayed(s.mOnTimeout, timeoutMs); + mHandler.postDelayed(s.mOnTimeout, timeoutMs); } void addToSyncSet(int id, WindowContainer wc) { diff --git a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java index 8e91ca28fcf1f..77efc4b0d5615 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java @@ -42,6 +42,8 @@ import android.view.SurfaceControl; import androidx.test.filters.SmallTest; +import com.android.server.testutils.TestHandler; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -371,6 +373,49 @@ public class SyncEngineTests extends WindowTestsBase { mAppWindow.removeImmediately(); } + @Test + public void testQueueSyncSet() { + final TestHandler testHandler = new TestHandler(null); + TestWindowContainer mockWC = new TestWindowContainer(mWm, true /* waiter */); + TestWindowContainer mockWC2 = new TestWindowContainer(mWm, true /* waiter */); + + final BLASTSyncEngine bse = createTestBLASTSyncEngine(testHandler); + + BLASTSyncEngine.TransactionReadyListener listener = mock( + BLASTSyncEngine.TransactionReadyListener.class); + + int id = startSyncSet(bse, listener); + bse.addToSyncSet(id, mockWC); + bse.setReady(id); + bse.onSurfacePlacement(); + verify(listener, times(0)).onTransactionReady(eq(id), notNull()); + + final int[] nextId = new int[]{-1}; + bse.queueSyncSet( + () -> nextId[0] = startSyncSet(bse, listener), + () -> { + bse.setReady(nextId[0]); + bse.addToSyncSet(nextId[0], mockWC2); + }); + + // Make sure it is queued + assertEquals(-1, nextId[0]); + + // Finish the original sync and see that we've started a new sync-set immediately but + // that the readiness was posted. + mockWC.onSyncFinishedDrawing(); + verify(mWm.mWindowPlacerLocked).requestTraversal(); + bse.onSurfacePlacement(); + verify(listener, times(1)).onTransactionReady(eq(id), notNull()); + + assertTrue(nextId[0] != -1); + assertFalse(bse.isReady(nextId[0])); + + // now make sure the applySync callback was posted. + testHandler.flush(); + assertTrue(bse.isReady(nextId[0])); + } + static int startSyncSet(BLASTSyncEngine engine, BLASTSyncEngine.TransactionReadyListener listener) { return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "Test"); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 7e3ec55f262a1..f85cdf0b50358 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -77,6 +77,7 @@ import android.hardware.display.DisplayManager; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; @@ -886,7 +887,11 @@ class WindowTestsBase extends SystemServiceTestsBase { } BLASTSyncEngine createTestBLASTSyncEngine() { - return new BLASTSyncEngine(mWm) { + return createTestBLASTSyncEngine(mWm.mH); + } + + BLASTSyncEngine createTestBLASTSyncEngine(Handler handler) { + return new BLASTSyncEngine(mWm, handler) { @Override void scheduleTimeout(SyncGroup s, long timeoutMs) { // Disable timeout.