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

Commit 7b772844 authored by Chavi Weingarten's avatar Chavi Weingarten Committed by Automerger Merge Worker
Browse files

Merge "Don't clear mUsingBLASTSyncTransaction until sending callback" into rvc-dev am: 259309f1

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11854634

Change-Id: Iff678b6a82353c3a2520707a2881513e0aa06651
parents ca3cc25e 259309f1
Loading
Loading
Loading
Loading
+18 −15
Original line number Diff line number Diff line
@@ -16,17 +16,19 @@

package com.android.server.wm;

import android.view.SurfaceControl;
import android.util.ArrayMap;
import android.util.ArraySet;

import java.util.HashMap;
import java.util.Set;

/**
 * Utility class for collecting and merging transactions from various sources asynchronously.
 * Utility class for collecting WindowContainers that will merge transactions.
 * For example to use to synchronously resize all the children of a window container
 *   1. Open a new sync set, and pass the listener that will be invoked
 *        int id startSyncSet(TransactionReadyListener)
 *      the returned ID will be eventually passed to the TransactionReadyListener in combination
 *      with the prepared transaction. You also use it to refer to the operation in future steps.
 *      with a set of WindowContainers that are ready, meaning onTransactionReady was called for
 *      those WindowContainers. You also use it to refer to the operation in future steps.
 *   2. Ask each child to participate:
 *       addToSyncSet(int id, WindowContainer wc)
 *      if the child thinks it will be affected by a configuration change (a.k.a. has a visible
@@ -38,35 +40,37 @@ import java.util.HashMap;
 *       setReady(int id)
 *   5. If there were no sub windows anywhere in the hierarchy to wait on, then
 *      transactionReady is immediately invoked, otherwise all the windows are poked
 *      to redraw and to deliver a buffer to WMS#finishDrawing.
 *      Once all this drawing is complete the combined transaction of all the buffers
 *      and pending transaction hierarchy changes will be delivered to the TransactionReadyListener
 *      to redraw and to deliver a buffer to {@link WindowState#finishDrawing}.
 *      Once all this drawing is complete the WindowContainer that's ready will be added to the
 *      set of ready WindowContainers. When the final onTransactionReady is called, it will merge
 *      the transactions of the all the WindowContainers and will be delivered to the
 *      TransactionReadyListener
 */
class BLASTSyncEngine {
    private static final String TAG = "BLASTSyncEngine";

    interface TransactionReadyListener {
        void onTransactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction);
        void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady);
    };

    // Holds state associated with a single synchronous set of operations.
    class SyncState implements TransactionReadyListener {
        int mSyncId;
        SurfaceControl.Transaction mMergedTransaction;
        int mRemainingTransactions;
        TransactionReadyListener mListener;
        boolean mReady = false;
        Set<WindowContainer> mWindowContainersReady = new ArraySet<>();

        private void tryFinish() {
            if (mRemainingTransactions == 0 && mReady) {
                mListener.onTransactionReady(mSyncId, mMergedTransaction);
                mListener.onTransactionReady(mSyncId, mWindowContainersReady);
                mPendingSyncs.remove(mSyncId);
            }
        }

        public void onTransactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction) {
        public void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady) {
            mRemainingTransactions--;
            mMergedTransaction.merge(mergedTransaction);
            mWindowContainersReady.addAll(windowContainersReady);
            tryFinish();
        }

@@ -86,14 +90,13 @@ class BLASTSyncEngine {
        SyncState(TransactionReadyListener l, int id) {
            mListener = l;
            mSyncId = id;
            mMergedTransaction = new SurfaceControl.Transaction();
            mRemainingTransactions = 0;
        }
    };

    int mNextSyncId = 0;
    private int mNextSyncId = 0;

    final HashMap<Integer, SyncState> mPendingSyncs = new HashMap();
    private final ArrayMap<Integer, SyncState> mPendingSyncs = new ArrayMap<>();

    BLASTSyncEngine() {
    }
+12 −4
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -2685,11 +2686,13 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
    }

    @Override
    public void onTransactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction) {
        mergedTransaction.merge(mBLASTSyncTransaction);
        mUsingBLASTSyncTransaction = false;
    public void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady) {
        if (mWaitingListener == null) {
            return;
        }

        mWaitingListener.onTransactionReady(mWaitingSyncId, mergedTransaction);
        windowContainersReady.add(this);
        mWaitingListener.onTransactionReady(mWaitingSyncId, windowContainersReady);

        mWaitingListener = null;
        mWaitingSyncId = -1;
@@ -2740,4 +2743,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
    boolean useBLASTSync() {
        return mUsingBLASTSyncTransaction;
    }

    void mergeBlastSyncTransaction(Transaction t) {
        t.merge(mBLASTSyncTransaction);
        mUsingBLASTSyncTransaction = false;
    }
}
+17 −3
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import android.window.IWindowOrganizerController;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;

@@ -51,6 +52,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Server side implementation for the interface for organizing windows
@@ -142,7 +144,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
                        // operations so we don't end up splitting effects between the WM
                        // pending transaction and the BLASTSync transaction.
                        if (syncId >= 0) {
                            mBLASTSyncEngine.addToSyncSet(syncId, wc);
                            addToSyncSet(syncId, wc);
                        }

                        int containerEffect = applyWindowContainerChange(wc, entry.getValue());
@@ -164,7 +166,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
                            continue;
                        }
                        if (syncId >= 0) {
                            mBLASTSyncEngine.addToSyncSet(syncId, wc);
                            addToSyncSet(syncId, wc);
                        }
                        effects |= sanitizeAndApplyHierarchyOp(wc, hop);
                    }
@@ -396,21 +398,33 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
        return mDisplayAreaOrganizerController;
    }

    @VisibleForTesting
    int startSyncWithOrganizer(IWindowContainerTransactionCallback callback) {
        int id = mBLASTSyncEngine.startSyncSet(this);
        mTransactionCallbacksByPendingSyncId.put(id, callback);
        return id;
    }

    @VisibleForTesting
    void setSyncReady(int id) {
        mBLASTSyncEngine.setReady(id);
    }

    @VisibleForTesting
    void addToSyncSet(int syncId, WindowContainer wc) {
        mBLASTSyncEngine.addToSyncSet(syncId, wc);
    }

    @Override
    public void onTransactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction) {
    public void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady) {
        final IWindowContainerTransactionCallback callback =
                mTransactionCallbacksByPendingSyncId.get(mSyncId);

        SurfaceControl.Transaction mergedTransaction = new SurfaceControl.Transaction();
        for (WindowContainer container : windowContainersReady) {
            container.mergeBlastSyncTransaction(mergedTransaction);
        }

        try {
            callback.onTransactionReady(mSyncId, mergedTransaction);
        } catch (RemoteException e) {
+26 −4
Original line number Diff line number Diff line
@@ -242,8 +242,10 @@ import com.android.server.wm.utils.WmDisplayCutout;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

/** A window in the window manager. */
@@ -655,6 +657,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP

    private static final StringBuilder sTmpSB = new StringBuilder();

    /**
     * Whether the next surfacePlacement call should notify that the blast sync is ready.
     * This is set to true when {@link #finishDrawing(Transaction)} is called so
     * {@link #onTransactionReady(int, Set)} is called after the next surfacePlacement. This allows
     * Transactions to get flushed into the syncTransaction before notifying {@link BLASTSyncEngine}
     * that this WindowState is ready.
     */
    private boolean mNotifyBlastOnSurfacePlacement;

    /**
     * Compares two window sub-layers and returns -1 if the first is lesser than the second in terms
     * of z-order and 1 otherwise.
@@ -5346,6 +5357,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        updateFrameRateSelectionPriorityIfNeeded();

        mWinAnimator.prepareSurfaceLocked(true);
        notifyBlastSyncTransaction();
        super.prepareSurfaces();
    }

@@ -5837,6 +5849,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
            mBLASTSyncTransaction.merge(postDrawTransaction);
        }

        mNotifyBlastOnSurfacePlacement = true;
        return mWinAnimator.finishDrawingLocked(null);
    }

    @VisibleForTesting
    void notifyBlastSyncTransaction() {
        if (!mNotifyBlastOnSurfacePlacement || mWaitingListener == null) {
            mNotifyBlastOnSurfacePlacement = false;
            return;
        }

        // If localSyncId is >0 then we are syncing with children and will
        // invoke transaction ready from our own #transactionReady callback
        // we just need to signal our side of the sync (setReady). But if we
@@ -5844,15 +5867,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        // be invoked and we need to invoke it ourself.
        if (mLocalSyncId >= 0) {
            mBLASTSyncEngine.setReady(mLocalSyncId);
            return mWinAnimator.finishDrawingLocked(null);
            return;
        }

        mWaitingListener.onTransactionReady(mWaitingSyncId, mBLASTSyncTransaction);
        mUsingBLASTSyncTransaction = false;
        mWaitingListener.onTransactionReady(mWaitingSyncId,  Collections.singleton(this));

        mWaitingSyncId = 0;
        mWaitingListener = null;
        return mWinAnimator.finishDrawingLocked(null);
        mNotifyBlastOnSurfacePlacement = false;
    }

    private boolean requestResizeForBlastSync() {
+43 −4
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import android.util.Rational;
import android.view.Display;
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.IWindowContainerTransactionCallback;
import android.window.WindowContainerTransaction;

import androidx.test.filters.SmallTest;
@@ -728,7 +729,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
        // We should be rejected from the second sync since we are already
        // in one.
        assertEquals(false, bse.addToSyncSet(id2, task));
        w.finishDrawing(null);
        finishAndNotifyDrawing(w);
        assertEquals(true, bse.addToSyncSet(id2, task));
        bse.setReady(id2);
    }
@@ -752,7 +753,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
        // Since we have a window we have to wait for it to draw to finish sync.
        verify(transactionListener, never())
            .onTransactionReady(anyInt(), any());
        w.finishDrawing(null);
        finishAndNotifyDrawing(w);
        verify(transactionListener)
            .onTransactionReady(anyInt(), any());
    }
@@ -820,14 +821,14 @@ public class WindowOrganizerTests extends WindowTestsBase {
        int id = bse.startSyncSet(transactionListener);
        assertEquals(true, bse.addToSyncSet(id, task));
        bse.setReady(id);
        w.finishDrawing(null);
        finishAndNotifyDrawing(w);

        // Since we have a child window we still shouldn't be done.
        verify(transactionListener, never())
            .onTransactionReady(anyInt(), any());
        reset(transactionListener);

        child.finishDrawing(null);
        finishAndNotifyDrawing(child);
        // Ah finally! Done
        verify(transactionListener)
                .onTransactionReady(anyInt(), any());
@@ -979,4 +980,42 @@ public class WindowOrganizerTests extends WindowTestsBase {
                new IRequestFinishCallback.Default());
        verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
    }

    @Test
    public void testBLASTCallbackWithMultipleWindows() throws Exception {
        final ActivityStack stackController = createStack();
        final Task task = createTask(stackController);
        final ITaskOrganizer organizer = registerMockOrganizer();
        final WindowState w1 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 1");
        final WindowState w2 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 2");
        makeWindowVisible(w1);
        makeWindowVisible(w2);

        IWindowContainerTransactionCallback mockCallback =
                mock(IWindowContainerTransactionCallback.class);
        int id = mWm.mAtmService.mWindowOrganizerController.startSyncWithOrganizer(mockCallback);

        mWm.mAtmService.mWindowOrganizerController.addToSyncSet(id, task);
        mWm.mAtmService.mWindowOrganizerController.setSyncReady(id);

        // Since we have a window we have to wait for it to draw to finish sync.
        verify(mockCallback, never()).onTransactionReady(anyInt(), any());
        assertTrue(w1.useBLASTSync());
        assertTrue(w2.useBLASTSync());
        finishAndNotifyDrawing(w1);

        // Even though one Window finished drawing, both windows should still be using blast sync
        assertTrue(w1.useBLASTSync());
        assertTrue(w2.useBLASTSync());

        finishAndNotifyDrawing(w2);
        verify(mockCallback).onTransactionReady(anyInt(), any());
        assertFalse(w1.useBLASTSync());
        assertFalse(w2.useBLASTSync());
    }

    private void finishAndNotifyDrawing(WindowState ws) {
        ws.finishDrawing(null);
        ws.notifyBlastSyncTransaction();
    }
}