From 03de64bece0fe350f249b691682ffc44cf9fff73 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Thu, 1 Dec 2022 16:56:02 +0800 Subject: Finish sync for unchanged drawn window A window may be collected while it is drawn without state changes. So after surface placement, if the window is not added to be resizing (updateResizingWindowIfNeeded is not called), the window can be considered as ready to reduce the time of waiting next redraw or even transition timeout. For example (shell transition): Activity X starts Y in the same task and X finishes when the previous transition animation is running. X's draw state (drawn) and visibility (visible) are not changed. Then the closing transition may be timeout. Though the timeout can also be fixed by calling DC#setLayoutNeeded (to trigger updateResizingWindowIfNeeded) in SyncGroup#setReady, it means that the transition needs to wait for the unnecessary redraw. This can also handle the case of I49746b56e7dda76c530366663000b0d11ae779f3 Bug: 260059642 Test: atest SyncEngineTests WindowOrganizerTests Change-Id: I4615eb17553ffb6635a0c39c849b44c80d03f41e --- .../core/java/com/android/server/wm/WindowContainer.java | 5 ++--- .../java/com/android/server/wm/WindowManagerService.java | 6 ------ services/core/java/com/android/server/wm/WindowState.java | 15 ++++++++++----- .../src/com/android/server/wm/SyncEngineTests.java | 5 ++--- .../src/com/android/server/wm/WindowOrganizerTests.java | 3 ++- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 5c893de6b920..a576c167483f 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -3744,7 +3744,6 @@ class WindowContainer extends ConfigurationContainer< if (mSyncState == SYNC_STATE_NONE) return false; mSyncState = SYNC_STATE_READY; mSyncMethodOverride = BLASTSyncEngine.METHOD_UNDEFINED; - mWmService.mWindowPlacerLocked.requestTraversal(); ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "onSyncFinishedDrawing %s", this); return true; } @@ -3814,8 +3813,8 @@ class WindowContainer extends ConfigurationContainer< /** * Checks if the subtree rooted at this container is finished syncing (everything is ready or - * not visible). NOTE, this is not const: it will cancel/prepare itself depending on its state - * in the hierarchy. + * not visible). NOTE, this is not const: it may cancel/prepare/complete itself depending on + * its state in the hierarchy. * * @return {@code true} if this subtree is finished waiting for sync participants. */ diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index b3a7754bc2d5..4e32a7ca3bf4 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2587,12 +2587,6 @@ public class WindowManagerService extends IWindowManager.Stub && win.mSyncSeqId > lastSyncSeqId) { maybeSyncSeqId = win.shouldSyncWithBuffers() ? win.mSyncSeqId : -1; win.markRedrawForSyncReported(); - if (win.mSyncState == WindowContainer.SYNC_STATE_WAITING_FOR_DRAW - && winAnimator.mDrawState == WindowStateAnimator.HAS_DRAWN - && maybeSyncSeqId < 0) { - // Do not wait for a drawn window which won't report draw. - win.onSyncFinishedDrawing(); - } } else { maybeSyncSeqId = -1; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 2f55d1824c07..04699619bfc8 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -6004,12 +6004,16 @@ class WindowState extends WindowContainer implements WindowManagerP @Override boolean isSyncFinished() { - if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mViewVisibility != View.VISIBLE - && !isVisibleRequested()) { + if (!isVisibleRequested()) { // Don't wait for invisible windows. However, we don't alter the state in case the // window becomes visible while the sync group is still active. return true; } + if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mWinAnimator.mDrawState == HAS_DRAWN + && !mRedrawForSyncReported && !mWmService.mResizingWindows.contains(this)) { + // Complete the sync state immediately for a drawn window that doesn't need to redraw. + onSyncFinishedDrawing(); + } return super.isSyncFinished(); } @@ -6060,6 +6064,7 @@ class WindowState extends WindowContainer implements WindowManagerP final boolean hasSyncHandlers = executeDrawHandlers(postDrawTransaction, syncSeqId); boolean skipLayout = false; + boolean layoutNeeded = false; // Control the timing to switch the appearance of window with different rotations. final AsyncRotationController asyncRotationController = mDisplayContent.getAsyncRotationController(); @@ -6072,7 +6077,7 @@ class WindowState extends WindowContainer implements WindowManagerP } else if (syncActive) { // Currently in a Sync that is using BLAST. if (!syncStillPending) { - onSyncFinishedDrawing(); + layoutNeeded = onSyncFinishedDrawing(); } if (postDrawTransaction != null) { mSyncTransaction.merge(postDrawTransaction); @@ -6081,10 +6086,10 @@ class WindowState extends WindowContainer implements WindowManagerP } } else if (useBLASTSync()) { // Sync that is not using BLAST - onSyncFinishedDrawing(); + layoutNeeded = onSyncFinishedDrawing(); } - final boolean layoutNeeded = + layoutNeeded |= mWinAnimator.finishDrawingLocked(postDrawTransaction, mClientWasDrawingForSync); mClientWasDrawingForSync = false; // We always want to force a traversal after a finish draw for blast sync. 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 df7b3cdebe28..aff9c1a9372a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java @@ -31,6 +31,7 @@ import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -108,9 +109,7 @@ public class SyncEngineTests extends WindowTestsBase { bse.onSurfacePlacement(); verify(listener, times(0)).onTransactionReady(anyInt(), any()); - mockWC.onSyncFinishedDrawing(); - // Make sure the second traversal is requested. - verify(mWm.mWindowPlacerLocked, times(2)).requestTraversal(); + assertTrue(mockWC.onSyncFinishedDrawing()); bse.onSurfacePlacement(); verify(listener, times(1)).onTransactionReady(eq(id), notNull()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index df3b306d6739..fa98537f8909 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -1240,7 +1240,8 @@ public class WindowOrganizerTests extends WindowTestsBase { assertTrue(w1.useBLASTSync()); assertTrue(w2.useBLASTSync()); - w1.immediatelyNotifyBlastSync(); + // A drawn window can complete the sync state automatically. + w1.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; mWm.mSyncEngine.onSurfacePlacement(); verify(mockCallback).onTransactionReady(anyInt(), any()); assertFalse(w1.useBLASTSync()); -- cgit v1.2.3-59-g8ed1b