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

Commit 32d5c465 authored by Chavi Weingarten's avatar Chavi Weingarten Committed by Automerger Merge Worker
Browse files

Merge "Don't clear mUsingBLASTSyncTransaction until sending callback" into...

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

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

Change-Id: I0938755bc870b4f777d762f528e8549943c2a900
parents 5b14ecb0 6ba9944c
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();
    }
}