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

Commit 9b19fd42 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Do not hold WM lock while closing animation transaction

Animation transactions can be blocking, leading to total
window manager starvation. Fix this by not holding lock.

Test: Double tap recents button, make sure it's always responsive
Change-Id: I8e09e04f243d2bfc09fb68097846a42e76c7cab5
Fixes: 38192114
parent 152f6c8e
Loading
Loading
Loading
Loading
+125 −109
Original line number Diff line number Diff line
@@ -115,8 +115,8 @@ public class WindowAnimator {
        mAnimationTick = () -> {
            synchronized (mService.mWindowMap) {
                mAnimationTickScheduled = false;
                animateLocked(mCurrentFrameTime);
            }
            animate(mCurrentFrameTime);
        };
        mAnimationFrameCallback = frameTimeNs -> {
            synchronized (mService.mWindowMap) {
@@ -126,8 +126,8 @@ public class WindowAnimator {
                    return;
                }
                mAnimationTickScheduled = true;
                mSfChoreographer.scheduleAtSfVsync(mAnimationTick);
            }
            mSfChoreographer.scheduleAtSfVsync(mAnimationTick);
        };
    }

@@ -151,25 +151,34 @@ public class WindowAnimator {
        mDisplayContentsAnimators.delete(displayId);
    }

    /** Locked on mService.mWindowMap. */
    private void animateLocked(long frameTimeNs) {
    /**
     * DO NOT HOLD THE WINDOW MANAGER LOCK WHILE CALLING THIS METHOD. Reason: the method closes
     * an animation transaction, that might be blocking until the next sf-vsync, so we want to make
     * sure other threads can make progress if this happens.
     */
    private void animate(long frameTimeNs) {
        boolean transactionOpen = false;
        boolean wasAnimating = false;
        try {
            synchronized (mService.mWindowMap) {
                if (!mInitialized) {
                    return;
                }

                mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
                mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
        boolean wasAnimating = mAnimating;
                wasAnimating = mAnimating;
                setAnimating(false);
                mAppWindowAnimating = false;
                if (DEBUG_WINDOW_TRACE) {
                    Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
                }

        if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animateLocked");
                if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate");
                mService.openSurfaceTransaction();
                transactionOpen = true;
                SurfaceControl.setAnimationTransaction();
        try {

                final AccessibilityController accessibilityController =
                        mService.mAccessibilityController;
                final int numDisplays = mDisplayContentsAnimators.size();
@@ -189,10 +198,11 @@ public class WindowAnimator {
                            screenRotationAnimation.kill();
                            displayAnimator.mScreenRotationAnimation = null;

                        //TODO (multidisplay): Accessibility supported only for the default display.
                            //TODO (multidisplay): Accessibility supported only for the default
                            // display.
                            if (accessibilityController != null && dc.isDefaultDisplay) {
                            // We just finished rotation animation which means we did not announce
                            // the rotation and waited for it to end, announce now.
                                // We just finished rotation animation which means we did not
                                // announce the rotation and waited for it to end, announce now.
                                accessibilityController.onRotationChangedLocked(
                                        mService.getDefaultDisplayContentLocked());
                            }
@@ -238,13 +248,17 @@ public class WindowAnimator {
                if (mService.mWatermark != null) {
                    mService.mWatermark.drawIfNeeded();
                }
            }
        } catch (RuntimeException e) {
            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
        } finally {
            if (transactionOpen) {
                mService.closeSurfaceTransaction();
            if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animateLocked");
                if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
            }
        }

        synchronized (mService.mWindowMap) {
            boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
            boolean doRequest = false;
            if (mBulkUpdateParams != 0) {
@@ -257,8 +271,9 @@ public class WindowAnimator {

            if (mAnimating && !wasAnimating) {

            // Usually app transitions but quite a load onto the system already (with all the things
            // happening in app), so pause task snapshot persisting to not increase the load.
                // Usually app transitions but quite a load onto the system already (with all the
                // things happening in app), so pause task snapshot persisting to not increase the
                // load.
                mService.mTaskSnapshotController.setPersisterPaused(true);
                if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
                    Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
@@ -289,6 +304,7 @@ public class WindowAnimator {
                        + Integer.toHexString(getPendingLayoutChanges(DEFAULT_DISPLAY)));
            }
        }
    }

    private static String bulkUpdateParamsToString(int bulkUpdateParams) {
        StringBuilder builder = new StringBuilder(128);