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

Commit b8afa7f7 authored by Chavi Weingarten's avatar Chavi Weingarten
Browse files

Make SurfaceSyncGroup AIDL interface and add cross process syncs

When two processes are involved in a sync, we don't want them to
exchange Transaction info because it may contain SurfaceControls that
the two transactions shouldn't exchange. Instead, have system server
take care of the cross process syncs and ensure SurfaceSyncGroup
sends the data to system server instead of to the two apps.

This is done by the following flow:
1. P1 creates a SyncGroup
2. P1 adds something local to the SyncGroup. No WM API is called.
3. P1 adds something in P2 to SyncGroup
3a. P1 creates a SyncGroup in WM with P1's SyncGroup as token
3b. P1 notifies P2 that it should be added to the SyncGroup with a
specified token
3c. P2 invokes WM call and adds itself to the same SyncGroup in WM

When P1 and P2 groups are done, they will invoke the transaction
callback to WM, who will merge into a single transaction

4. P1 marks SyncGroup as ready, which calls into WM to mark the
   associated SyncGroup as ready. When all callbacks are complete, it
   will apply the final transaction

Test: SurfaceSyncGroupContinuousTest
Bug: 237804605
Change-Id: I0f52f2e2d1a95e0ecc2b95b6dddd2ebb5b3edb54
parent 3ad4f200
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -19,13 +19,19 @@ package android.view;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.view.InsetsState;
import android.window.ISurfaceSyncGroup;

/**
 * API from content embedder back to embedded content in SurfaceControlViewHost
 * {@hide}
 */
oneway interface ISurfaceControlViewHost {
    void onConfigurationChanged(in Configuration newConfig);
    void onDispatchDetachedFromWindow();
    void onInsetsChanged(in InsetsState state, in Rect insetFrame);
interface ISurfaceControlViewHost {
    /**
     * TODO (b/263273252): Investigate the need for these to be blocking calls or add additional
     * APIs that are blocking
     */
    oneway void onConfigurationChanged(in Configuration newConfig);
    oneway void onDispatchDetachedFromWindow();
    oneway void onInsetsChanged(in InsetsState state, in Rect insetFrame);
    ISurfaceSyncGroup getSurfaceSyncGroup();
}
+16 −0
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@ import android.view.WindowManager;
import android.view.SurfaceControl;
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
import android.window.AddToSurfaceSyncGroupResult;
import android.window.ISurfaceSyncGroupCompletedListener;
import android.window.ITaskFpsCallback;
import android.window.ScreenCapture;

@@ -985,4 +987,18 @@ interface IWindowManager
     * @return {@code true} if the key will be handled globally.
     */
    boolean isGlobalKey(int keyCode);

    /**
     * Create or add to a SurfaceSyncGroup in WindowManager. WindowManager maintains some
     * SurfaceSyncGroups to ensure multiple processes can sync with each other without sharing
     * SurfaceControls
     */
    boolean addToSurfaceSyncGroup(in IBinder syncGroupToken, boolean parentSyncGroupMerge,
                in @nullable ISurfaceSyncGroupCompletedListener completedListener,
                out AddToSurfaceSyncGroupResult addToSurfaceSyncGroupResult);

    /**
     * Mark a SurfaceSyncGroup stored in WindowManager as ready.
     */
    oneway void markSurfaceSyncGroupReady(in IBinder syncGroupToken);
}
+18 −0
Original line number Diff line number Diff line
@@ -29,9 +29,14 @@ import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
import android.view.accessibility.IAccessibilityEmbeddedConnection;
import android.window.ISurfaceSyncGroup;
import android.window.WindowTokenClient;

import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Utility class for adding a View hierarchy to a {@link SurfaceControl}. The View hierarchy
@@ -87,6 +92,19 @@ public class SurfaceControlViewHost {
            }
            mWm.setInsetsState(state);
        }

        @Override
        public ISurfaceSyncGroup getSurfaceSyncGroup() {
            CompletableFuture<ISurfaceSyncGroup> surfaceSyncGroup = new CompletableFuture<>();
            mViewRoot.mHandler.post(
                    () -> surfaceSyncGroup.complete(mViewRoot.getOrCreateSurfaceSyncGroup()));
            try {
                return surfaceSyncGroup.get(1, TimeUnit.SECONDS);
            } catch (InterruptedException | ExecutionException | TimeoutException e) {
                Log.e(TAG, "Failed to get SurfaceSyncGroup for SCVH", e);
            }
            return null;
        }
    }

    private ISurfaceControlViewHost mRemoteInterface = new ISurfaceControlViewHostImpl();
+3 −2
Original line number Diff line number Diff line
@@ -1091,7 +1091,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
                t = syncBufferTransactionCallback.waitForTransaction();
            }

            surfaceSyncGroup.onTransactionReady(t);
            surfaceSyncGroup.addTransactionToSync(t);
            surfaceSyncGroup.markSyncReady();
            onDrawFinished();
        });
    }
@@ -1106,7 +1107,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
            synchronized (mSyncGroups) {
                mSyncGroups.remove(surfaceSyncGroup);
            }
            surfaceSyncGroup.onTransactionReady(null);
            surfaceSyncGroup.markSyncReady();
            onDrawFinished();
        });

+57 −14
Original line number Diff line number Diff line
@@ -231,6 +231,7 @@ import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

/**
 * The top of a view hierarchy, implementing the needed protocol between View
@@ -863,6 +864,8 @@ public final class ViewRootImpl implements ViewParent,
    // animations until all are done.
    private static int sNumSyncsInProgress = 0;

    private int mNumPausedForSync = 0;

    private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;

    private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
@@ -2811,6 +2814,19 @@ public final class ViewRootImpl implements ViewParent,
            return;
        }

        if (mNumPausedForSync > 0) {
            if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                Trace.instant(Trace.TRACE_TAG_VIEW,
                        TextUtils.formatSimple("performTraversals#mNumPausedForSync=%d",
                                mNumPausedForSync));
            }
            if (DEBUG_BLAST) {
                Log.d(mTag, "Skipping traversal due to sync " + mNumPausedForSync);
            }
            mLastPerformTraversalsSkipDrawReason = "paused_for_sync";
            return;
        }

        mIsInTraversal = true;
        mWillDrawSoon = true;
        boolean cancelDraw = false;
@@ -3677,7 +3693,7 @@ public final class ViewRootImpl implements ViewParent,
            }

            if (mActiveSurfaceSyncGroup != null) {
                mActiveSurfaceSyncGroup.onTransactionReady(null);
                mActiveSurfaceSyncGroup.markSyncReady();
            }
        } else if (cancelAndRedraw) {
            mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
@@ -3693,7 +3709,7 @@ public final class ViewRootImpl implements ViewParent,
                mPendingTransitions.clear();
            }
            if (!performDraw() && mActiveSurfaceSyncGroup != null) {
                mActiveSurfaceSyncGroup.onTransactionReady(null);
                mActiveSurfaceSyncGroup.markSyncReady();
            }
        }

@@ -3710,7 +3726,7 @@ public final class ViewRootImpl implements ViewParent,
            mActiveSurfaceSyncGroup = null;
            mSyncBuffer = false;
            if (isInWMSRequestedSync()) {
                mWmsRequestSyncGroup.onTransactionReady(null);
                mWmsRequestSyncGroup.markSyncReady();
                mWmsRequestSyncGroup = null;
                mWmsRequestSyncGroupState = WMS_SYNC_NONE;
            }
@@ -4553,7 +4569,7 @@ public final class ViewRootImpl implements ViewParent,
            if (mSurfaceHolder != null && mSurface.isValid()) {
                final SurfaceSyncGroup surfaceSyncGroup = mActiveSurfaceSyncGroup;
                SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() ->
                        mHandler.post(() -> surfaceSyncGroup.onTransactionReady(null)));
                        mHandler.post(() -> surfaceSyncGroup.markSyncReady()));
                mActiveSurfaceSyncGroup = null;

                SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
@@ -4566,7 +4582,7 @@ public final class ViewRootImpl implements ViewParent,
            }
        }
        if (mActiveSurfaceSyncGroup != null && !usingAsyncReport) {
            mActiveSurfaceSyncGroup.onTransactionReady(null);
            mActiveSurfaceSyncGroup.markSyncReady();
        }
        if (mPerformContentCapture) {
            performContentCaptureInitialReport();
@@ -11281,8 +11297,9 @@ public final class ViewRootImpl implements ViewParent,
                // pendingDrawFinished.
                if ((syncResult
                        & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
                    surfaceSyncGroup.onTransactionReady(
                    surfaceSyncGroup.addTransactionToSync(
                            mBlastBufferQueue.gatherPendingTransactions(frame));
                    surfaceSyncGroup.markSyncReady();
                    return null;
                }

@@ -11291,8 +11308,13 @@ public final class ViewRootImpl implements ViewParent,
                }

                if (syncBuffer) {
                    mBlastBufferQueue.syncNextTransaction(
                            surfaceSyncGroup::onTransactionReady);
                    mBlastBufferQueue.syncNextTransaction(new Consumer<Transaction>() {
                        @Override
                        public void accept(Transaction transaction) {
                            surfaceSyncGroup.addTransactionToSync(transaction);
                            surfaceSyncGroup.markSyncReady();
                        }
                    });
                }

                return didProduceBuffer -> {
@@ -11312,8 +11334,9 @@ public final class ViewRootImpl implements ViewParent,
                        // since the frame didn't draw on this vsync. It's possible the frame will
                        // draw later, but it's better to not be sync than to block on a frame that
                        // may never come.
                        surfaceSyncGroup.onTransactionReady(
                        surfaceSyncGroup.addTransactionToSync(
                                mBlastBufferQueue.gatherPendingTransactions(frame));
                        surfaceSyncGroup.markSyncReady();
                        return;
                    }

@@ -11321,22 +11344,41 @@ public final class ViewRootImpl implements ViewParent,
                    // syncNextTransaction callback. Instead, just report back to the Syncer so it
                    // knows that this sync request is complete.
                    if (!syncBuffer) {
                        surfaceSyncGroup.onTransactionReady(null);
                        surfaceSyncGroup.markSyncReady();
                    }
                };
            }
        });
    }

    private class VRISurfaceSyncGroup extends SurfaceSyncGroup {
        VRISurfaceSyncGroup(String name) {
            super(name);
        }

        @Override
        public void onSyncReady() {
            Runnable runnable = () -> {
                mNumPausedForSync--;
                if (!mIsInTraversal && mNumPausedForSync == 0) {
                    scheduleTraversals();
                }
            };

            if (Thread.currentThread() == mThread) {
                runnable.run();
            } else {
                mHandler.post(runnable);
            }
        }
    }

    @Override
    public SurfaceSyncGroup getOrCreateSurfaceSyncGroup() {
        boolean newSyncGroup = false;
        if (mActiveSurfaceSyncGroup == null) {
            mActiveSurfaceSyncGroup = new SurfaceSyncGroup(mTag);
            mActiveSurfaceSyncGroup = new VRISurfaceSyncGroup(mTag);
            updateSyncInProgressCount(mActiveSurfaceSyncGroup);
            if (!mIsInTraversal && !mTraversalScheduled) {
                scheduleTraversals();
            }
            newSyncGroup = true;
        }

@@ -11352,6 +11394,7 @@ public final class ViewRootImpl implements ViewParent,
            }
        }

        mNumPausedForSync++;
        return mActiveSurfaceSyncGroup;
    };

Loading