Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef4353eb authored by Riddle Hsu's avatar Riddle Hsu
Browse files

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
parent 82516899
Loading
Loading
Loading
Loading
+94 −23
Original line number Diff line number Diff line
@@ -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);
        }
        }

        @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.
     */
+50 −0
Original line number Diff line number Diff line
@@ -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);
+7 −9
Original line number Diff line number Diff line
@@ -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);
+16 −42
Original line number Diff line number Diff line
@@ -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();
            }
        }
    }

+32 −15
Original line number Diff line number Diff line
@@ -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) {
Loading