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

Commit 6608bfd5 authored by Chavi Weingarten's avatar Chavi Weingarten
Browse files

Ensure pendingTransactions are applied if the VRI is torn down

When callers invoke the applyTransactionOnDraw, the code previously set
up an RT frame callback and only merged the transaction once a draw
started. However, if VRI is being torn down before a traversal starts,
the callback will never be invoked and the transaction will be left in
memory until GC. The cleanest way is to immediately apply the
transaction when the VRI is getting torn down to avoid leaving a stale
transaction with reference to SCs in it.

This required a bit of cleanup to ensure the UI thread still had access
to the SurfaceControl until a traversal was called. The new behavior
merges all incoming transactions from applyTransactionOnDraw into a
single Transaction. Then in the traversal path, it will either
piggy-back on the frame callback from sync transaction or create a new
one. The Transaction and flag are cleared in the traversal path since if
draw has been invoked, we are guaranteed the callback even if VRI dies.
This is because HardwareRenderer is not destroyed until everything
in the queue completes.

Test: presubmit
Bug: 248162583
Change-Id: I4d28b917545f530a068b237bf95de431afd749cb
parent e0dfbbbe
Loading
Loading
Loading
Loading
+27 −9
Original line number Diff line number Diff line
@@ -647,11 +647,18 @@ public final class ViewRootImpl implements ViewParent,
    boolean mForceNextWindowRelayout;
    CountDownLatch mWindowDrawCountDown;

    // Whether we have used applyTransactionOnDraw to schedule an RT
    // frame callback consuming a passed in transaction. In this case
    // we also need to schedule a commit callback so we can observe
    // if the draw was skipped, and the BBQ pending transactions.
    /**
     * Value to indicate whether someone has called {@link #applyTransactionOnDraw}before the
     * traversal. This is used to determine whether a RT frame callback needs to be registered to
     * merge the transaction with the next frame. The value is cleared after the VRI has run a
     * traversal pass.
     */
    boolean mHasPendingTransactions;
    /**
     * The combined transactions passed in from {@link #applyTransactionOnDraw}
     */
    private Transaction mPendingTransaction = new Transaction();


    boolean mIsDrawing;
    int mLastSystemUiVisibility;
@@ -4538,9 +4545,13 @@ public final class ViewRootImpl implements ViewParent,
    }

    private void registerCallbackForPendingTransactions() {
        Transaction t = new Transaction();
        t.merge(mPendingTransaction);

        registerRtFrameCallback(new FrameDrawingCallback() {
            @Override
            public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
                mergeWithNextTransaction(t, frame);
                if ((syncResult
                        & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
                    mBlastBufferQueue.applyPendingTransactions(frame);
@@ -8770,6 +8781,9 @@ public final class ViewRootImpl implements ViewParent,
            mActiveSurfaceSyncGroup.markSyncReady();
            mActiveSurfaceSyncGroup = null;
        }
        if (mHasPendingTransactions) {
            mPendingTransaction.apply();
        }
        WindowManagerGlobal.getInstance().doRemoveView(this);
    }

@@ -11104,12 +11118,11 @@ public final class ViewRootImpl implements ViewParent,
        } else {
            // Copy and clear the passed in transaction for thread safety. The new transaction is
            // accessed on the render thread.
            var localTransaction = new Transaction();
            localTransaction.merge(t);
            mPendingTransaction.merge(t);
            mHasPendingTransactions = true;
            registerRtFrameCallback(frame -> {
                mergeWithNextTransaction(localTransaction, frame);
            });
            // Schedule the traversal to ensure there's an attempt to draw a frame and apply the
            // pending transactions. This is also where the registerFrameCallback will be scheduled.
            scheduleTraversals();
        }
        return true;
    }
@@ -11250,6 +11263,10 @@ public final class ViewRootImpl implements ViewParent,
        if (DEBUG_BLAST) {
            Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer);
        }

        Transaction t = new Transaction();
        t.merge(mPendingTransaction);

        mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
            @Override
            public void onFrameDraw(long frame) {
@@ -11263,6 +11280,7 @@ public final class ViewRootImpl implements ViewParent,
                                    + frame + ".");
                }

                mergeWithNextTransaction(t, frame);
                // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or
                // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up
                // any blast sync or commit callback, and the code should directly call