Loading core/java/android/window/SystemPerformanceHinter.java +94 −23 Original line number Diff line number Diff line Loading @@ -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; /** Loading @@ -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 Loading Loading @@ -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); } } Loading @@ -103,15 +107,36 @@ public class SystemPerformanceHinter { /** * Closes this session. */ @Override public void close() { if (hintFlags != 0) { 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; } } /** Loading @@ -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; Loading @@ -134,7 +167,6 @@ public class SystemPerformanceHinter { private @Nullable PerformanceHintManager.Session mAdpfSession; private @Nullable DisplayRootProvider mDisplayRootProvider; /** * Constructor for the hinter. * @hide Loading Loading @@ -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"); Loading @@ -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); Loading @@ -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(); Loading @@ -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); Loading @@ -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(); Loading Loading @@ -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. */ Loading services/core/java/com/android/server/wm/DisplayContent.java +50 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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; Loading Loading @@ -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); Loading services/core/java/com/android/server/wm/Transition.java +7 −9 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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(); } /** Loading Loading @@ -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); } } /** Loading Loading @@ -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); Loading services/core/java/com/android/server/wm/TransitionController.java +16 −42 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -131,7 +125,6 @@ class TransitionController { SnapshotController mSnapshotController; TransitionTracer mTransitionTracer; private SystemPerformanceHinter mSystemPerformanceHinter; private boolean mFullReadyTracking = false; private final ArrayList<WindowManagerInternal.AppTransitionListener> mLegacyListeners = Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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. Loading @@ -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(); } } } Loading services/core/java/com/android/server/wm/WindowAnimator.java +32 −15 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading @@ -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); } Loading @@ -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"); Loading @@ -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) { Loading Loading
core/java/android/window/SystemPerformanceHinter.java +94 −23 Original line number Diff line number Diff line Loading @@ -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; /** Loading @@ -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 Loading Loading @@ -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); } } Loading @@ -103,15 +107,36 @@ public class SystemPerformanceHinter { /** * Closes this session. */ @Override public void close() { if (hintFlags != 0) { 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; } } /** Loading @@ -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; Loading @@ -134,7 +167,6 @@ public class SystemPerformanceHinter { private @Nullable PerformanceHintManager.Session mAdpfSession; private @Nullable DisplayRootProvider mDisplayRootProvider; /** * Constructor for the hinter. * @hide Loading Loading @@ -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"); Loading @@ -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); Loading @@ -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(); Loading @@ -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); Loading @@ -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(); Loading Loading @@ -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. */ Loading
services/core/java/com/android/server/wm/DisplayContent.java +50 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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; Loading Loading @@ -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); Loading
services/core/java/com/android/server/wm/Transition.java +7 −9 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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(); } /** Loading Loading @@ -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); } } /** Loading Loading @@ -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); Loading
services/core/java/com/android/server/wm/TransitionController.java +16 −42 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -131,7 +125,6 @@ class TransitionController { SnapshotController mSnapshotController; TransitionTracer mTransitionTracer; private SystemPerformanceHinter mSystemPerformanceHinter; private boolean mFullReadyTracking = false; private final ArrayList<WindowManagerInternal.AppTransitionListener> mLegacyListeners = Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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. Loading @@ -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(); } } } Loading
services/core/java/com/android/server/wm/WindowAnimator.java +32 −15 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading @@ -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); } Loading @@ -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"); Loading @@ -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) { Loading