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
This commit is contained in:
Riddle Hsu
2023-05-08 20:56:10 +08:00
parent f3475fcf11
commit 2d2e953cd3
3 changed files with 31 additions and 0 deletions

View File

@@ -3990,6 +3990,9 @@ class WindowContainer<E extends 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<E extends 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 */);
}

View File

@@ -5634,6 +5634,13 @@ class WindowState extends WindowContainer<WindowState> 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()) {

View File

@@ -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