From ef4353ebe2f2ae339e3f5f3391ec3eb50e102472 Mon Sep 17 00:00:00 2001 From: Riddle Hsu <riddlehsu@google.com> Date: Wed, 18 Oct 2023 16:51:12 +0800 Subject: [PATCH] Apply perf session for regular window animation This keeps the same behavior: - App transition/rotation/recents -> Set sf early wake -> Pause snapshot persist queue -> Use high refresh rate - Window container with running SurfaceAnimator -> Use high refresh rate Also - Centralize perf sessions to display (fix leaked sessions). - Add support to reuse session for flexibility of management. - Fix non-paired session of transition. Because the transition can be aborted without playing. - Fix non-paired trace of SystemPerformanceHinter. Because the begin/end of name may not match if there are multiple sessions. - Use asyncTraceForTrack, which reduces extra rows in perfetto. Bug: 305987082 Test: TransitionTests#testTransitionsTriggerPerformanceHints WindowContainerTests#testRemoveImmediatelyClearsLeash Change-Id: If5cf41b9a0586f5a0a76d4a9044a5489900502df --- .../window/SystemPerformanceHinter.java | 117 ++++++++++++++---- .../com/android/server/wm/DisplayContent.java | 50 ++++++++ .../com/android/server/wm/Transition.java | 16 ++- .../server/wm/TransitionController.java | 58 +++------ .../com/android/server/wm/WindowAnimator.java | 47 ++++--- .../server/wm/WindowManagerService.java | 6 +- .../server/testutils/StubTransaction.java | 14 ++- .../android/server/wm/TransitionTests.java | 57 ++++----- .../server/wm/WindowContainerTests.java | 6 + 9 files changed, 248 insertions(+), 123 deletions(-) diff --git a/core/java/android/window/SystemPerformanceHinter.java b/core/java/android/window/SystemPerformanceHinter.java index 2736b68845a2b..5b0d8d1233c63 100644 --- a/core/java/android/window/SystemPerformanceHinter.java +++ b/core/java/android/window/SystemPerformanceHinter.java @@ -29,11 +29,11 @@ import android.content.Context; import android.os.PerformanceHintManager; import android.os.Trace; import android.util.Log; +import android.view.Display; import android.view.SurfaceControl; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Random; import java.util.function.Supplier; /** @@ -45,6 +45,7 @@ import java.util.function.Supplier; public class SystemPerformanceHinter { private static final String TAG = "SystemPerformanceHinter"; + private static final int HINT_NO_OP = 0; // Change app and SF wakeup times to allow sf more time to composite a frame public static final int HINT_SF_EARLY_WAKEUP = 1 << 0; // Force max refresh rate @@ -88,14 +89,17 @@ public class SystemPerformanceHinter { private final @HintFlags int hintFlags; private final String reason; private final int displayId; - private final int traceCookie; + private String mTraceName; protected HighPerfSession(@HintFlags int hintFlags, int displayId, @NonNull String reason) { this.hintFlags = hintFlags; this.reason = reason; this.displayId = displayId; - this.traceCookie = new Random().nextInt(); - if (hintFlags != 0) { + } + + /** Makes this session active. It is no-op if this session is already active. */ + public void start() { + if (!mActiveSessions.contains(this)) { startSession(this); } } @@ -103,15 +107,36 @@ public class SystemPerformanceHinter { /** * Closes this session. */ + @Override public void close() { - if (hintFlags != 0) { - endSession(this); - } + endSession(this); } + @Override public void finalize() { close(); } + + boolean asyncTraceBegin() { + if (!Trace.isTagEnabled(mTraceTag)) { + mTraceName = null; + return false; + } + if (mTraceName == null) { + mTraceName = "PerfSession-d" + displayId + "-" + reason; + } + Trace.asyncTraceForTrackBegin(mTraceTag, TAG, mTraceName, + System.identityHashCode(this)); + return true; + } + + boolean asyncTraceEnd() { + if (mTraceName == null) { + return false; + } + Trace.asyncTraceForTrackEnd(mTraceTag, TAG, System.identityHashCode(this)); + return true; + } } /** @@ -119,14 +144,22 @@ public class SystemPerformanceHinter { */ private class NoOpHighPerfSession extends HighPerfSession { public NoOpHighPerfSession() { - super(0 /* hintFlags */, -1 /* displayId */, ""); + super(HINT_NO_OP, Display.INVALID_DISPLAY, ""); + } + + @Override + public void start() { } + @Override public void close() { // Do nothing } } + /** The tag category of trace. */ + public long mTraceTag = Trace.TRACE_TAG_APP; + // The active sessions private final ArrayList<HighPerfSession> mActiveSessions = new ArrayList<>(); private final SurfaceControl.Transaction mTransaction; @@ -134,7 +167,6 @@ public class SystemPerformanceHinter { private @Nullable PerformanceHintManager.Session mAdpfSession; private @Nullable DisplayRootProvider mDisplayRootProvider; - /** * Constructor for the hinter. * @hide @@ -167,12 +199,12 @@ public class SystemPerformanceHinter { mAdpfSession = adpfSession; } - /** - * Starts a session that requires high performance. - * @hide - */ - public HighPerfSession startSession(@HintFlags int hintFlags, int displayId, + /** Creates a session that requires high performance. */ + public HighPerfSession createSession(@HintFlags int hintFlags, int displayId, @NonNull String reason) { + if (hintFlags == HINT_NO_OP) { + throw new IllegalArgumentException("Not allow empty hint flags"); + } if (mDisplayRootProvider == null && (hintFlags & HINT_SF_FRAME_RATE) != 0) { throw new IllegalArgumentException( "Using SF frame rate hints requires a valid display root provider"); @@ -193,9 +225,20 @@ public class SystemPerformanceHinter { } /** - * Starts a session that requires high performance. + * Starts a new session that requires high performance. */ + public HighPerfSession startSession(@HintFlags int hintFlags, int displayId, + @NonNull String reason) { + final HighPerfSession session = createSession(hintFlags, displayId, reason); + if (session.hintFlags != HINT_NO_OP) { + startSession(session); + } + return session; + } + + /** Starts the session that requires high performance. */ private void startSession(HighPerfSession session) { + final boolean isTraceEnabled = session.asyncTraceBegin(); int oldGlobalFlags = calculateActiveHintFlags(HINT_GLOBAL); int oldPerDisplayFlags = calculateActiveHintFlagsForDisplay(HINT_PER_DISPLAY, session.displayId); @@ -217,19 +260,24 @@ public class SystemPerformanceHinter { mTransaction.setFrameRateCategory( displaySurfaceControl, FRAME_RATE_CATEGORY_HIGH, /* smoothSwitchOnly= */ false); transactionChanged = true; - Trace.beginAsyncSection("PerfHint-framerate-" + session.displayId + "-" - + session.reason, session.traceCookie); + if (isTraceEnabled) { + asyncTraceBegin(HINT_SF_FRAME_RATE, session.displayId); + } } // Global flags if (nowEnabled(oldGlobalFlags, newGlobalFlags, HINT_SF_EARLY_WAKEUP)) { mTransaction.setEarlyWakeupStart(); transactionChanged = true; - Trace.beginAsyncSection("PerfHint-early_wakeup-" + session.reason, session.traceCookie); + if (isTraceEnabled) { + asyncTraceBegin(HINT_SF_EARLY_WAKEUP, Display.INVALID_DISPLAY); + } } if (nowEnabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) { mAdpfSession.sendHint(PerformanceHintManager.Session.CPU_LOAD_UP); - Trace.beginAsyncSection("PerfHint-adpf-" + session.reason, session.traceCookie); + if (isTraceEnabled) { + asyncTraceBegin(HINT_ADPF, Display.INVALID_DISPLAY); + } } if (transactionChanged) { mTransaction.applyAsyncUnsafe(); @@ -240,6 +288,7 @@ public class SystemPerformanceHinter { * Ends a session that requires high performance. */ private void endSession(HighPerfSession session) { + final boolean isTraceEnabled = session.asyncTraceEnd(); int oldGlobalFlags = calculateActiveHintFlags(HINT_GLOBAL); int oldPerDisplayFlags = calculateActiveHintFlagsForDisplay(HINT_PER_DISPLAY, session.displayId); @@ -261,19 +310,24 @@ public class SystemPerformanceHinter { mTransaction.setFrameRateCategory(displaySurfaceControl, FRAME_RATE_CATEGORY_DEFAULT, /* smoothSwitchOnly= */ false); transactionChanged = true; - Trace.endAsyncSection("PerfHint-framerate-" + session.displayId + "-" + session.reason, - session.traceCookie); + if (isTraceEnabled) { + asyncTraceEnd(HINT_SF_FRAME_RATE); + } } // Global flags if (nowDisabled(oldGlobalFlags, newGlobalFlags, HINT_SF_EARLY_WAKEUP)) { mTransaction.setEarlyWakeupEnd(); transactionChanged = true; - Trace.endAsyncSection("PerfHint-early_wakeup-" + session.reason, session.traceCookie); + if (isTraceEnabled) { + asyncTraceEnd(HINT_SF_EARLY_WAKEUP); + } } if (nowDisabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) { mAdpfSession.sendHint(PerformanceHintManager.Session.CPU_LOAD_RESET); - Trace.endAsyncSection("PerfHint-adpf-" + session.reason, session.traceCookie); + if (isTraceEnabled) { + asyncTraceEnd(HINT_ADPF); + } } if (transactionChanged) { mTransaction.applyAsyncUnsafe(); @@ -323,6 +377,23 @@ public class SystemPerformanceHinter { return flags; } + private void asyncTraceBegin(@HintFlags int flag, int displayId) { + final String prefix = switch (flag) { + case HINT_SF_EARLY_WAKEUP -> "PerfHint-early_wakeup"; + case HINT_SF_FRAME_RATE -> "PerfHint-framerate"; + case HINT_ADPF -> "PerfHint-adpf"; + default -> "PerfHint-" + flag; + }; + final String name = displayId != Display.INVALID_DISPLAY + ? (prefix + "-d" + displayId) : prefix; + Trace.asyncTraceForTrackBegin(mTraceTag, TAG, name, + flag ^ System.identityHashCode(this)); + } + + private void asyncTraceEnd(@HintFlags int flag) { + Trace.asyncTraceForTrackEnd(mTraceTag, TAG, flag ^ System.identityHashCode(this)); + } + /** * Dumps the existing sessions. */ diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index f31490060fc87..697402016f353 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -160,6 +160,7 @@ import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP; import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW; import static com.android.server.wm.utils.RegionUtils.forEachRectReverse; import static com.android.server.wm.utils.RegionUtils.rectListToRegion; +import static com.android.window.flags.Flags.explicitRefreshRateHints; import android.annotation.IntDef; import android.annotation.NonNull; @@ -245,6 +246,7 @@ import android.window.DisplayWindowPolicyController; import android.window.IDisplayAreaOrganizer; import android.window.ScreenCapture; import android.window.ScreenCapture.SynchronousScreenCaptureListener; +import android.window.SystemPerformanceHinter; import android.window.TransitionRequestInfo; import com.android.internal.R; @@ -571,6 +573,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp private final SurfaceSession mSession = new SurfaceSession(); + /** + * A perf hint session which will boost the refresh rate for the display and change sf duration + * to handle larger workloads. + */ + private SystemPerformanceHinter.HighPerfSession mTransitionPrefSession; + + /** A perf hint session which will boost the refresh rate. */ + private SystemPerformanceHinter.HighPerfSession mHighFrameRateSession; + /** * Window that is currently interacting with the user. This window is responsible for receiving * key events and pointer events from the user. @@ -761,6 +772,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ boolean mDontMoveToTop; + /** Whether this display contains a WindowContainer with running SurfaceAnimator. */ + boolean mLastContainsRunningSurfaceAnimator; + /** Used for windows that want to keep the screen awake. */ private PowerManager.WakeLock mHoldScreenWakeLock; @@ -3447,6 +3461,42 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return dockFrame.bottom - imeFrame.top; } + void enableHighPerfTransition(boolean enable) { + if (!explicitRefreshRateHints()) { + if (enable) { + getPendingTransaction().setEarlyWakeupStart(); + } else { + getPendingTransaction().setEarlyWakeupEnd(); + } + return; + } + if (enable) { + if (mTransitionPrefSession == null) { + mTransitionPrefSession = mWmService.mSystemPerformanceHinter.createSession( + SystemPerformanceHinter.HINT_SF, mDisplayId, "Transition"); + } + mTransitionPrefSession.start(); + } else if (mTransitionPrefSession != null) { + mTransitionPrefSession.close(); + } + } + + void enableHighFrameRate(boolean enable) { + if (!explicitRefreshRateHints()) { + // Done by RefreshRatePolicy. + return; + } + if (enable) { + if (mHighFrameRateSession == null) { + mHighFrameRateSession = mWmService.mSystemPerformanceHinter.createSession( + SystemPerformanceHinter.HINT_SF_FRAME_RATE, mDisplayId, "WindowAnimation"); + } + mHighFrameRateSession.start(); + } else if (mHighFrameRateSession != null) { + mHighFrameRateSession.close(); + } + } + void rotateBounds(@Rotation int oldRotation, @Rotation int newRotation, Rect inOutBounds) { // Get display bounds on oldRotation as parent bounds for the rotation. getBounds(mTmpRect, oldRotation); diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index f6b4972de2509..9594c65ad5fc3 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -249,7 +249,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { private boolean mIsSeamlessRotation = false; private IContainerFreezer mContainerFreezer = null; - private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction(); /** * {@code true} if some other operation may have caused the originally-recorded state (in @@ -628,11 +627,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mLogger.mStartTimeNs = SystemClock.elapsedRealtimeNanos(); - mController.updateAnimatingState(mTmpTransaction); - // merge into the next-time the global transaction is applied. This is too-early to set - // early-wake anyways, so we don't need to apply immediately (in fact applying right now - // can preempt more-important work). - SurfaceControl.mergeToGlobalTransaction(mTmpTransaction); + mController.updateAnimatingState(); } /** @@ -704,7 +699,11 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (dc == null || mTargetDisplays.contains(dc)) return; mTargetDisplays.add(dc); addOnTopTasks(dc, mOnTopTasksStart); - mController.startPerfHintForDisplay(dc.mDisplayId); + // Handle the case {transition.start(); applyTransaction(wct);} that the animating state + // is set before collecting participants. + if (mController.isAnimating()) { + dc.enableHighPerfTransition(true); + } } /** @@ -1407,8 +1406,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { false /* forceRelayout */); } cleanUpInternal(); - mController.updateAnimatingState(mTmpTransaction); - mTmpTransaction.apply(); + mController.updateAnimatingState(); // Handle back animation if it's already started. mController.mAtm.mBackNavigationController.onTransitionFinish(mTargets, this); diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 28c24c82e8305..c134464bc33a6 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -22,10 +22,8 @@ import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS; import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_OPEN; -import static android.window.SystemPerformanceHinter.HINT_SF; import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY; -import static com.android.window.flags.Flags.explicitRefreshRateHints; import android.annotation.NonNull; import android.annotation.Nullable; @@ -41,18 +39,14 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; -import android.view.SurfaceControl; import android.view.WindowManager; import android.window.ITransitionMetricsReporter; import android.window.ITransitionPlayer; import android.window.RemoteTransition; -import android.window.SystemPerformanceHinter; -import android.window.SystemPerformanceHinter.HighPerfSession; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; import android.window.WindowContainerTransaction; @@ -131,7 +125,6 @@ class TransitionController { SnapshotController mSnapshotController; TransitionTracer mTransitionTracer; - private SystemPerformanceHinter mSystemPerformanceHinter; private boolean mFullReadyTracking = false; private final ArrayList<WindowManagerInternal.AppTransitionListener> mLegacyListeners = @@ -185,24 +178,6 @@ class TransitionController { private final IBinder.DeathRecipient mTransitionPlayerDeath; - /** - * Tracks active perf sessions that boost frame rate and hint sf to increase its - * estimated work duration. - */ - private final ArraySet<HighPerfSession> mHighPerfSessions = new ArraySet<>(); - - - /** - * Starts a perf hint session which will boost the refresh rate for the display and change - * sf duration to handle larger workloads. - */ - void startPerfHintForDisplay(int displayId) { - if (explicitRefreshRateHints()) { - mHighPerfSessions.add(mSystemPerformanceHinter.startSession(HINT_SF, displayId, - "Transition collected")); - } - } - static class QueuedTransition { final Transition mTransition; final OnStartCollect mOnStartCollect; @@ -282,15 +257,9 @@ class TransitionController { mIsWaitingForDisplayEnabled = !wms.mDisplayEnabled; registerLegacyListener(wms.mActivityManagerAppTransitionNotifier); setSyncEngine(wms.mSyncEngine); - setSystemPerformanceHinter(wms.mSystemPerformanceHinter); mFullReadyTracking = Flags.transitReadyTracking(); } - @VisibleForTesting - void setSystemPerformanceHinter(SystemPerformanceHinter hinter) { - mSystemPerformanceHinter = hinter; - } - @VisibleForTesting void setSyncEngine(BLASTSyncEngine syncEngine) { mSyncEngine = syncEngine; @@ -508,7 +477,7 @@ class TransitionController { return false; } - /** @return {@code true} if wc is in a participant subtree */ + /** Returns {@code true} if the display contains a running or pending transition. */ boolean isTransitionOnDisplay(@NonNull DisplayContent dc) { if (mCollectingTransition != null && mCollectingTransition.isOnDisplay(dc)) { return true; @@ -1240,12 +1209,22 @@ class TransitionController { } } - void updateAnimatingState(SurfaceControl.Transaction t) { + /** Returns {@code true} if a transition is playing or the collecting transition is started. */ + boolean isAnimating() { + return mAnimatingState; + } + + void updateAnimatingState() { final boolean animatingState = !mPlayingTransitions.isEmpty() || (mCollectingTransition != null && mCollectingTransition.isStarted()); if (animatingState && !mAnimatingState) { - if (!explicitRefreshRateHints()) { - t.setEarlyWakeupStart(); + // Note that Transition#start() can be called before adding participants, so the + // enableHighPerfTransition(true) is also called in Transition#recordDisplay. + for (int i = mAtm.mRootWindowContainer.getChildCount() - 1; i >= 0; i--) { + final DisplayContent dc = mAtm.mRootWindowContainer.getChildAt(i); + if (isTransitionOnDisplay(dc)) { + dc.enableHighPerfTransition(true); + } } // Usually transitions put quite a load onto the system already (with all the things // happening in app), so pause task snapshot persisting to not increase the load. @@ -1253,18 +1232,13 @@ class TransitionController { mAnimatingState = true; Transition.asyncTraceBegin("animating", 0x41bfaf1 /* hashcode of TAG */); } else if (!animatingState && mAnimatingState) { - if (!explicitRefreshRateHints()) { - t.setEarlyWakeupEnd(); + for (int i = mAtm.mRootWindowContainer.getChildCount() - 1; i >= 0; i--) { + mAtm.mRootWindowContainer.getChildAt(i).enableHighPerfTransition(false); } mAtm.mWindowManager.scheduleAnimationLocked(); mSnapshotController.setPause(false); mAnimatingState = false; Transition.asyncTraceEnd(0x41bfaf1 /* hashcode of TAG */); - // We close all perf sessions here when all transitions finish. The sessions are created - // when we collect transitions because we have access to the display id. - for (HighPerfSession perfSession : mHighPerfSessions) { - perfSession.close(); - } } } diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index adc0595f305b7..e95d2651504b9 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -117,6 +117,9 @@ public class WindowAnimator { scheduleAnimation(); final RootWindowContainer root = mService.mRoot; + final boolean useShellTransition = root.mTransitionController.isShellTransitionsEnabled(); + final int animationFlags = useShellTransition ? CHILDREN : (TRANSITION | CHILDREN); + boolean rootAnimating = false; mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS; mBulkUpdateParams = 0; root.mOrientationChangeComplete = true; @@ -149,6 +152,17 @@ public class WindowAnimator { accessibilityController.drawMagnifiedRegionBorderIfNeeded(dc.mDisplayId, mTransaction); } + + if (dc.isAnimating(animationFlags, ANIMATION_TYPE_ALL)) { + rootAnimating = true; + if (!dc.mLastContainsRunningSurfaceAnimator) { + dc.mLastContainsRunningSurfaceAnimator = true; + dc.enableHighFrameRate(true); + } + } else if (dc.mLastContainsRunningSurfaceAnimator) { + dc.mLastContainsRunningSurfaceAnimator = false; + dc.enableHighFrameRate(false); + } } cancelAnimation(); @@ -168,8 +182,6 @@ public class WindowAnimator { mService.mWindowPlacerLocked.requestTraversal(); } - final boolean rootAnimating = root.isAnimating(TRANSITION | CHILDREN /* flags */, - ANIMATION_TYPE_ALL /* typesToCheck */); if (rootAnimating && !mLastRootAnimating) { Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0); } @@ -179,20 +191,10 @@ public class WindowAnimator { } mLastRootAnimating = rootAnimating; - final boolean runningExpensiveAnimations = - root.isAnimating(TRANSITION | CHILDREN /* flags */, - ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_SCREEN_ROTATION - | ANIMATION_TYPE_RECENTS /* typesToCheck */); - if (runningExpensiveAnimations && !mRunningExpensiveAnimations) { - // Usually app transitions put quite a load onto the system already (with all the things - // happening in app), so pause snapshot persisting to not increase the load. - mService.mSnapshotController.setPause(true); - mTransaction.setEarlyWakeupStart(); - } else if (!runningExpensiveAnimations && mRunningExpensiveAnimations) { - mService.mSnapshotController.setPause(false); - mTransaction.setEarlyWakeupEnd(); + // APP_TRANSITION, SCREEN_ROTATION, TYPE_RECENTS are handled by shell transition. + if (!useShellTransition) { + updateRunningExpensiveAnimationsLegacy(); } - mRunningExpensiveAnimations = runningExpensiveAnimations; SurfaceControl.mergeToGlobalTransaction(mTransaction); mService.closeSurfaceTransaction("WindowAnimator"); @@ -208,6 +210,21 @@ public class WindowAnimator { } } + private void updateRunningExpensiveAnimationsLegacy() { + final boolean runningExpensiveAnimations = + mService.mRoot.isAnimating(TRANSITION | CHILDREN /* flags */, + ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_SCREEN_ROTATION + | ANIMATION_TYPE_RECENTS /* typesToCheck */); + if (runningExpensiveAnimations && !mRunningExpensiveAnimations) { + mService.mSnapshotController.setPause(true); + mTransaction.setEarlyWakeupStart(); + } else if (!runningExpensiveAnimations && mRunningExpensiveAnimations) { + mService.mSnapshotController.setPause(false); + mTransaction.setEarlyWakeupEnd(); + } + mRunningExpensiveAnimations = runningExpensiveAnimations; + } + private static String bulkUpdateParamsToString(int bulkUpdateParams) { StringBuilder builder = new StringBuilder(128); if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 4a074ff25c741..a90e08e4f3725 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1346,8 +1346,8 @@ public class WindowManagerService extends IWindowManager.Stub DisplayContent dc = mRoot.getDisplayContent(displayId); return (dc == null) ? null : dc.getSurfaceControl(); } - }, mTransactionFactory); + mSystemPerformanceHinter.mTraceTag = TRACE_TAG_WINDOW_MANAGER; } DisplayAreaPolicy.Provider getDisplayAreaPolicyProvider() { @@ -7195,6 +7195,10 @@ public class WindowManagerService extends IWindowManager.Stub pw.println(separator); } mConstants.dump(pw); + if (dumpAll) { + pw.println(separator); + } + mSystemPerformanceHinter.dump(pw, ""); } } diff --git a/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java b/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java index 34e8ff2ec5c4f..b8dcecdbfb959 100644 --- a/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java +++ b/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java @@ -30,8 +30,6 @@ import android.view.InputWindowHandle; import android.view.Surface; import android.view.SurfaceControl; -import com.android.server.testutils.StubTransaction; - import java.util.HashSet; import java.util.concurrent.Executor; @@ -261,6 +259,18 @@ public class StubTransaction extends SurfaceControl.Transaction { return this; } + @Override + public SurfaceControl.Transaction setFrameRateCategory(SurfaceControl sc, int category, + boolean smoothSwitchOnly) { + return this; + } + + @Override + public SurfaceControl.Transaction setFrameRateSelectionStrategy(SurfaceControl sc, + int strategy) { + return this; + } + @Override public SurfaceControl.Transaction unsetColor(SurfaceControl sc) { return this; diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 47730237f675b..baf259461847c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -2438,41 +2438,36 @@ public class TransitionTests extends WindowTestsBase { @Test public void testTransitionsTriggerPerformanceHints() { - assumeTrue(explicitRefreshRateHints()); - SystemPerformanceHinter systemPerformanceHinter = mock(SystemPerformanceHinter.class); - final TransitionController controller = new TestTransitionController(mAtm); + final boolean explicitRefreshRateHints = explicitRefreshRateHints(); + final var session = new SystemPerformanceHinter.HighPerfSession[1]; + if (explicitRefreshRateHints) { + final SystemPerformanceHinter perfHinter = mWm.mSystemPerformanceHinter; + spyOn(perfHinter); + doAnswer(invocation -> { + session[0] = (SystemPerformanceHinter.HighPerfSession) invocation.callRealMethod(); + return session[0]; + }).when(perfHinter).createSession(anyInt(), anyInt(), anyString()); + } + final TransitionController controller = mDisplayContent.mTransitionController; final TestTransitionPlayer player = registerTestTransitionPlayer(); - - mSyncEngine = createTestBLASTSyncEngine(); - controller.setSyncEngine(mSyncEngine); - controller.setSystemPerformanceHinter(systemPerformanceHinter); - SystemPerformanceHinter.HighPerfSession session = mock( - SystemPerformanceHinter.HighPerfSession.class); - doReturn(session).when(systemPerformanceHinter).startSession(anyInt(), anyInt(), - anyString()); - + final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build(); final Transition transitA = createTestTransition(TRANSIT_OPEN, controller); - final Task task = createTask(mDisplayContent, - WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); - final ActivityRecord act = createActivityRecord(task); - act.setVisibleRequested(true); - act.setVisible(true); - - controller.startCollectOrQueue(transitA, (deferred) -> { - }); - transitA.collect(act); - - verify(systemPerformanceHinter).startSession( - eq(SystemPerformanceHinter.HINT_SF), anyInt(), eq("Transition collected")); + controller.moveToCollecting(transitA); + transitA.collectExistenceChange(app); + controller.requestStartTransition(transitA, app.getTask(), + null /* remoteTransition */, null /* displayChange */); + player.start(); - transitA.start(); - transitA.setAllReady(); + verify(mDisplayContent).enableHighPerfTransition(true); + if (explicitRefreshRateHints) { + verify(session[0]).start(); + } - // Aborting here doesn't abort the transition, it aborts the sync allowing the transition to - // finish successfully. - mSyncEngine.abort(transitA.getSyncId()); - controller.finishTransition(transitA); - verify(session).close(); + player.finish(); + verify(mDisplayContent).enableHighPerfTransition(false); + if (explicitRefreshRateHints) { + verify(session[0]).close(); + } } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index a82459fc1baa0..55a00fc0ec89a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -293,6 +293,7 @@ public class WindowContainerTests extends WindowTestsBase { public void testRemoveImmediatelyClearsLeash() { final AnimationAdapter animAdapter = mock(AnimationAdapter.class); final WindowToken token = createTestWindowToken(TYPE_APPLICATION_OVERLAY, mDisplayContent); + mWm.mAnimator.ready(); final SurfaceControl.Transaction t = token.getPendingTransaction(); token.startAnimation(t, animAdapter, false /* hidden */, SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION); @@ -300,9 +301,14 @@ public class WindowContainerTests extends WindowTestsBase { ArgumentCaptor.forClass(SurfaceControl.class); verify(animAdapter).startAnimation(leashCaptor.capture(), eq(t), anyInt(), any()); assertTrue(token.mSurfaceAnimator.hasLeash()); + waitUntilWindowAnimatorIdle(); + verify(mDisplayContent).enableHighFrameRate(true); + token.removeImmediately(); assertFalse(token.mSurfaceAnimator.hasLeash()); verify(t).remove(eq(leashCaptor.getValue())); + waitUntilWindowAnimatorIdle(); + verify(mDisplayContent).enableHighFrameRate(false); } @Test -- GitLab