From 0ca6ebbae4035f47dc29c3c88213f8329924b477 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Tue, 20 Jun 2023 16:43:55 +0800 Subject: [PATCH] Apply rotation change on display thread This aligns the same behavior as legacy that posts continueDisplayChange to display thread. Otherwise the display info change (triggered from DisplayContent#updateDisplayAndOrientation -> setDisplayInfoOverrideFromWindowManager and then dispatch on display thread) will reach client before window manger requests resizing with buffer synchronization (shouldSyncWithBuffers). This can also reduce about 10ms in WM lock because the display thread is set to top-app sched group that usually runs on the big core. Also with this and [1] (transform hint), the workaround to force full-blast-sync for 180 degree rotation is no longer needed. [1]: Id4ad45adb9719b078f46040a09f786092c325a8a Bug: 288105083 Test: Rotate device by 180 degree and observe display cutout doesn't show on opposite position. Change-Id: I7e1de5b5fe12cb30b5f48808ea6b0a2214c0f339 --- .../com/android/server/wm/Transition.java | 21 +++++++++++++++++++ .../server/wm/TransitionController.java | 9 -------- .../server/wm/WindowOrganizerController.java | 13 ++++++++++-- .../server/wm/DisplayContentTests.java | 1 + 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 79a54c3cfb32d..a510b3076c7ba 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -77,6 +77,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.IRemoteCallback; +import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -2686,6 +2687,26 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { }); } + /** + * Returns {@code true} if the transition and the corresponding transaction should be applied + * on display thread. Currently, this only checks for display rotation change because the order + * of dispatching the new display info will be after requesting the windows to sync drawing. + * That avoids potential flickering of screen overlays (e.g. cutout, rounded corner). Also, + * because the display thread has a higher priority, it is faster to perform the configuration + * changes and window hierarchy traversal. + */ + boolean shouldApplyOnDisplayThread() { + for (int i = mParticipants.size() - 1; i >= 0; --i) { + final DisplayContent dc = mParticipants.valueAt(i).asDisplayContent(); + if (dc == null) continue; + final ChangeInfo changeInfo = mChanges.get(dc); + if (changeInfo != null && changeInfo.mRotation != dc.getRotation()) { + return Looper.myLooper() != mController.mAtm.mWindowManager.mH.getLooper(); + } + } + return false; + } + /** Applies the new configuration for the changed displays. */ void applyDisplayChangeIfNeeded() { for (int i = mParticipants.size() - 1; i >= 0; --i) { diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index a539a4893d4f6..79cb61be5948b 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -588,15 +588,6 @@ class TransitionController { /** Sets the sync method for the display change. */ private void setDisplaySyncMethod(@NonNull TransitionRequestInfo.DisplayChange displayChange, @NonNull Transition displayTransition, @NonNull DisplayContent displayContent) { - final int startRotation = displayChange.getStartRotation(); - final int endRotation = displayChange.getEndRotation(); - if (startRotation != endRotation && (startRotation + endRotation) % 2 == 0) { - // 180 degrees rotation change may not change screen size. So the clients may draw - // some frames before and after the display projection transaction is applied by the - // remote player. That may cause some buffers to show in different rotation. So use - // sync method to pause clients drawing until the projection transaction is applied. - mSyncEngine.setSyncMethod(displayTransition.getSyncId(), BLASTSyncEngine.METHOD_BLAST); - } final Rect startBounds = displayChange.getStartAbsBounds(); final Rect endBounds = displayChange.getEndAbsBounds(); if (startBounds == null || endBounds == null) return; diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index a2f7ba499fdff..31918f478e444 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -321,9 +321,18 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub applyTransaction(wct, -1 /*syncId*/, null /*transition*/, caller); return transition.getToken(); } - transition.start(); transition.mLogger.mStartWCT = wct; - applyTransaction(wct, -1 /*syncId*/, transition, caller); + if (transition.shouldApplyOnDisplayThread()) { + mService.mH.post(() -> { + synchronized (mService.mGlobalLock) { + transition.start(); + applyTransaction(wct, -1 /* syncId */, transition, caller); + } + }); + } else { + transition.start(); + applyTransaction(wct, -1 /* syncId */, transition, caller); + } // Since the transition is already provided, it means WMCore is determining the // "readiness lifecycle" outside the provided transaction, so don't set ready here. return transition.getToken(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 5369b93c95346..bdd178b0b3178 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -2046,6 +2046,7 @@ public class DisplayContentTests extends WindowTestsBase { // Once transition starts, rotation is applied and transition shows DC rotating. testPlayer.startTransition(); + waitUntilHandlersIdle(); assertNotEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation()); assertNotNull(testPlayer.mLastReady); assertTrue(testPlayer.mController.isPlaying());