From 2d2e953cd35e6baad56e9d32c76762a51f00290c Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Mon, 8 May 2023 20:56:10 +0800 Subject: [PATCH] Do not redraw if no change on reparent An example is when transferring a starting window in a task with embedded activities. The configuration of the starting window will be overridden by task, so there won't be configuration change when transferring the window between activities. And if the window was drawn, it is unnecessary to request redraw by onSyncReparent -> WindowState#prepareSync() -> requestRedrawForSync(). Though this can avoid potential SurfaceSyncGroup timeout indirectly, this is still a reasonable performance optimization. Bug: 279798720 Test: atest SyncEngineTests#testReparentIn Change-Id: Iebfb662b579eceecc470719fa6a2dc8ba8df332f --- .../com/android/server/wm/WindowContainer.java | 8 ++++++++ .../java/com/android/server/wm/WindowState.java | 7 +++++++ .../com/android/server/wm/SyncEngineTests.java | 16 ++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 829a33d4bfb73..e94748f111f40 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -3990,6 +3990,9 @@ class WindowContainer extends ConfigurationContainer< } // Otherwise this is the "root" of a synced subtree, so continue on to preparation. } + if (oldParent != null && newParent != null && !shouldUpdateSyncOnReparent()) { + return; + } // This container's situation has changed so we need to restart its sync. // We cannot reset the sync without a chance of a deadlock since it will request a new @@ -4004,6 +4007,11 @@ class WindowContainer extends ConfigurationContainer< prepareSync(); } + /** Returns {@code true} if {@link #mSyncState} needs to be updated when reparenting. */ + protected boolean shouldUpdateSyncOnReparent() { + return true; + } + void registerWindowContainerListener(WindowContainerListener listener) { registerWindowContainerListener(listener, true /* shouldPropConfig */); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 032f08a92abb2..bab7a78a72862 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -5634,6 +5634,13 @@ class WindowState extends WindowContainer implements WindowManagerP t.unsetBuffer(viewSurface); } + @Override + protected boolean shouldUpdateSyncOnReparent() { + // Keep the sync state in case the client is drawing for the latest conifguration or the + // configuration is not changed after reparenting. This avoids a redundant redraw request. + return mSyncState != SYNC_STATE_NONE && !mLastConfigReportedToClient; + } + @Override boolean prepareSync() { if (!mDrawHandlers.isEmpty()) { 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 a3a36841d8071..5eebe746d64b1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java @@ -26,6 +26,7 @@ import static com.android.server.wm.BLASTSyncEngine.METHOD_NONE; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowContainer.SYNC_STATE_NONE; +import static com.android.server.wm.WindowContainer.SYNC_STATE_READY; import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION; import static org.junit.Assert.assertEquals; @@ -38,7 +39,9 @@ import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.spy; import android.platform.test.annotations.Presubmit; +import android.util.MergedConfiguration; import android.view.SurfaceControl; +import android.window.ClientWindowFrames; import androidx.test.filters.SmallTest; @@ -306,6 +309,19 @@ public class SyncEngineTests extends WindowTestsBase { assertEquals(SYNC_STATE_NONE, parentWC.mSyncState); assertEquals(SYNC_STATE_NONE, topChildWC.mSyncState); assertEquals(SYNC_STATE_NONE, botChildWC.mSyncState); + + // If the appearance of window won't change after reparenting, its sync state can be kept. + final WindowState w = createWindow(null, TYPE_BASE_APPLICATION, "win"); + parentWC.onRequestedOverrideConfigurationChanged(w.getConfiguration()); + w.reparent(botChildWC, POSITION_TOP); + parentWC.prepareSync(); + // Assume the window has drawn with the latest configuration. + w.fillClientWindowFramesAndConfiguration(new ClientWindowFrames(), + new MergedConfiguration(), true /* useLatestConfig */, true /* relayoutVisible */); + assertTrue(w.onSyncFinishedDrawing()); + assertEquals(SYNC_STATE_READY, w.mSyncState); + w.reparent(topChildWC, POSITION_TOP); + assertEquals(SYNC_STATE_READY, w.mSyncState); } @Test