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

Commit 73e24a2f authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Clear seamless rotation transform for transaction commit timeout

For example:
The rotation transition is ready while the cutout is not yet drawn
for new rotation, then the start transaction of transition will contain
the unrotate-transform to keep the same appearance. But if the
transition player is somehow slow, BLASTSyncEngine will apply the
start transaction after 5s timeout. Then AsyncRotationController will
receive the transaction commit callback to clear the rotation transform
because the display projection transaction was applied.

But the transition player may be still alive, then it still applies
the start transaction again after a few seconds, which causes the
cutout to unrotate while display is already rotated.

So when the timeout case happens, put the recovery transform in the
cleanup transaction which will be applied when the transition is
finished. That avoids keeping a stale transform.

Note that the recovery transform should not be always set in cleanup
transaction, because the seamless windows need to sync until it
reports drawn. Otherwise it will cause flickering.

Bug: 300677147
Test: Set break point at the beginning of
      com.android.wm.shell.transitionon.Transitions#TransitionReady
      Rotate device and wait until log "WM sent Transaction
        to organized, but never received commit callback.
        Application ANR likely to follow." appears.
      Resume the break point and check the cutout shows correctly.

Change-Id: Ibbfcb4a16f08147edf909ace8a8029c4bcf24b14
parent a93ce5ac
Loading
Loading
Loading
Loading
+38 −5
Original line number Diff line number Diff line
@@ -275,15 +275,18 @@ class AsyncRotationController extends FadeAnimationController implements Consume
            // The previous animation leash will be dropped when preparing fade-in animation, so
            // simply apply new animation without restoring the transformation.
            fadeWindowToken(true /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
        } else if (op.mAction == Operation.ACTION_SEAMLESS
                && op.mLeash != null && op.mLeash.isValid()) {
        } else if (op.isValidSeamless()) {
            if (DEBUG) Slog.d(TAG, "finishOp undo seamless " + windowToken.getTopChild());
            final SurfaceControl.Transaction t = windowToken.getSyncTransaction();
            t.setMatrix(op.mLeash, 1, 0, 0, 1);
            t.setPosition(op.mLeash, 0, 0);
            clearTransform(t, op.mLeash);
        }
    }

    private static void clearTransform(SurfaceControl.Transaction t, SurfaceControl sc) {
        t.setMatrix(sc, 1, 0, 0, 1);
        t.setPosition(sc, 0, 0);
    }

    /**
     * Completes all operations such as applying fade-in animation on the previously hidden window
     * tokens. This is called if all windows are ready in new rotation or timed out.
@@ -400,7 +403,19 @@ class AsyncRotationController extends FadeAnimationController implements Consume
                synchronized (mService.mGlobalLock) {
                    Slog.i(TAG, "Async rotation timeout: " + (!mIsStartTransactionCommitted
                            ? " start transaction is not committed" : mTargetWindowTokens));
                    mIsStartTransactionCommitted = true;
                    if (!mIsStartTransactionCommitted) {
                        // The transaction commit timeout will be handled by:
                        // 1. BLASTSyncEngine will notify onTransactionCommitTimeout() and then
                        //    apply the start transaction of transition.
                        // 2. The TransactionCommittedListener in setupStartTransaction() will be
                        //    notified to finish the operations of mTargetWindowTokens.
                        // 3. The slow remote side will also apply the start transaction which may
                        //    contain stale surface transform.
                        // 4. Finally, the slow remote reports transition finished. The cleanup
                        //    transaction from step (1) will be applied when finishing transition,
                        //    which will recover the stale state from (3).
                        return;
                    }
                    mDisplayContent.finishAsyncRotationIfPossible();
                    mService.mWindowPlacerLocked.performSurfacePlacement();
                }
@@ -539,6 +554,20 @@ class AsyncRotationController extends FadeAnimationController implements Consume
        });
    }

    /** Called when the start transition is ready, but it is not applied in time. */
    void onTransactionCommitTimeout(SurfaceControl.Transaction t) {
        if (mIsStartTransactionCommitted) return;
        for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
            final Operation op = mTargetWindowTokens.valueAt(i);
            op.mIsCompletionPending = true;
            if (op.isValidSeamless()) {
                Slog.d(TAG, "Transaction timeout. Clear transform for "
                        + mTargetWindowTokens.keyAt(i).getTopChild());
                clearTransform(t, op.mLeash);
            }
        }
    }

    /** Called when the transition by shell is done. */
    void onTransitionFinished() {
        if (mTransitionOp == OP_CHANGE) {
@@ -681,6 +710,10 @@ class AsyncRotationController extends FadeAnimationController implements Consume
            mAction = action;
        }

        boolean isValidSeamless() {
            return mAction == ACTION_SEAMLESS && mLeash != null && mLeash.isValid();
        }

        @Override
        public String toString() {
            return "Operation{a=" + mAction + " pending=" + mIsCompletionPending + '}';
+2 −0
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ class BLASTSyncEngine {

    interface TransactionReadyListener {
        void onTransactionReady(int mSyncId, SurfaceControl.Transaction transaction);
        default void onTransactionCommitTimeout() {}
    }

    /**
@@ -249,6 +250,7 @@ class BLASTSyncEngine {
                           " commit callback. Application ANR likely to follow.");
                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                    synchronized (mWm.mGlobalLock) {
                        mListener.onTransactionCommitTimeout();
                        onCommitted(merged.mNativeObject != 0
                                ? merged : mWm.mTransactionFactory.get());
                    }
+12 −0
Original line number Diff line number Diff line
@@ -1683,6 +1683,18 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        }
    }

    @Override
    public void onTransactionCommitTimeout() {
        if (mCleanupTransaction == null) return;
        for (int i = mTargetDisplays.size() - 1; i >= 0; --i) {
            final DisplayContent dc = mTargetDisplays.get(i);
            final AsyncRotationController asyncRotationController = dc.getAsyncRotationController();
            if (asyncRotationController != null && containsChangeFor(dc, mTargets)) {
                asyncRotationController.onTransactionCommitTimeout(mCleanupTransaction);
            }
        }
    }

    /**
     * Collect tasks which moved-to-top as part of this transition. This also updates the
     * controller's latest-reported when relevant.