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

Commit b04a67a9 authored by Evan Rosky's avatar Evan Rosky Committed by Automerger Merge Worker
Browse files

Merge "Add support for (explicitly) parallel sync-groups" into udc-dev am:...

Merge "Add support for (explicitly) parallel sync-groups" into udc-dev am: 66c3f036 am: a7b7c653

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



Change-Id: Idea8d1556973d64c4b05e10490dac9ffb48f1911
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 3cb16792 a7b7c653
Loading
Loading
Loading
Loading
+12 −6
Original line number Original line Diff line number Diff line
@@ -307,6 +307,12 @@
      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
    },
    },
    "-1828118576": {
      "message": "SyncGroup %d: Started %sfor listener: %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_SYNC_ENGINE",
      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
    },
    "-1824578273": {
    "-1824578273": {
      "message": "Reporting new frame to %s: %s",
      "message": "Reporting new frame to %s: %s",
      "level": "VERBOSE",
      "level": "VERBOSE",
@@ -2893,12 +2899,6 @@
      "group": "WM_DEBUG_BOOT",
      "group": "WM_DEBUG_BOOT",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    },
    "550717438": {
      "message": "SyncGroup %d: Started for listener: %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_SYNC_ENGINE",
      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
    },
    "556758086": {
    "556758086": {
      "message": "Applying new update lock state '%s' for %s",
      "message": "Applying new update lock state '%s' for %s",
      "level": "DEBUG",
      "level": "DEBUG",
@@ -4129,6 +4129,12 @@
      "group": "WM_DEBUG_ANIM",
      "group": "WM_DEBUG_ANIM",
      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
    },
    },
    "1820873642": {
      "message": "SyncGroup %d:  Unfinished dependencies: %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_SYNC_ENGINE",
      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
    },
    "1822314934": {
    "1822314934": {
      "message": "Expected target rootTask=%s to restored behind rootTask=%s but it is behind rootTask=%s",
      "message": "Expected target rootTask=%s to restored behind rootTask=%s but it is behind rootTask=%s",
      "level": "WARN",
      "level": "WARN",
+7 −4
Original line number Original line Diff line number Diff line
@@ -10551,8 +10551,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    }
    }


    @Override
    @Override
    boolean isSyncFinished() {
    boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) {
        if (!super.isSyncFinished()) return false;
        if (!super.isSyncFinished(group)) return false;
        if (mDisplayContent != null && mDisplayContent.mUnknownAppVisibilityController
        if (mDisplayContent != null && mDisplayContent.mUnknownAppVisibilityController
                .isVisibilityUnknown(this)) {
                .isVisibilityUnknown(this)) {
            return false;
            return false;
@@ -10572,11 +10572,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    }
    }


    @Override
    @Override
    void finishSync(Transaction outMergedTransaction, boolean cancel) {
    void finishSync(Transaction outMergedTransaction, BLASTSyncEngine.SyncGroup group,
            boolean cancel) {
        // This override is just for getting metrics. allFinished needs to be checked before
        // This override is just for getting metrics. allFinished needs to be checked before
        // finish because finish resets all the states.
        // finish because finish resets all the states.
        final BLASTSyncEngine.SyncGroup syncGroup = getSyncGroup();
        if (syncGroup != null && group != getSyncGroup()) return;
        mLastAllReadyAtSync = allSyncFinished();
        mLastAllReadyAtSync = allSyncFinished();
        super.finishSync(outMergedTransaction, cancel);
        super.finishSync(outMergedTransaction, group, cancel);
    }
    }


    @Nullable
    @Nullable
+207 −34
Original line number Original line Diff line number Diff line
@@ -27,7 +27,6 @@ import android.os.Handler;
import android.os.Trace;
import android.os.Trace;
import android.util.ArraySet;
import android.util.ArraySet;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.view.SurfaceControl;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
@@ -61,6 +60,26 @@ import java.util.ArrayList;
 * This works primarily by setting-up state and then watching/waiting for the registered subtrees
 * This works primarily by setting-up state and then watching/waiting for the registered subtrees
 * to enter into a "finished" state (either by receiving drawn content or by disappearing). This
 * to enter into a "finished" state (either by receiving drawn content or by disappearing). This
 * checks the subtrees during surface-placement.
 * checks the subtrees during surface-placement.
 *
 * By default, all Syncs will be serialized (and it is an error to start one while another is
 * active). However, a sync can be explicitly started in "parallel". This does not guarantee that
 * it will run in parallel; however, it will run in parallel as long as it's watched hierarchy
 * doesn't overlap with any other syncs' watched hierarchies.
 *
 * Currently, a sync that is started as "parallel" implicitly ignores the subtree below it's
 * direct members unless those members are activities (WindowStates are considered "part of" the
 * activity). This allows "stratified" parallelism where, eg, a sync that is only at Task-level
 * can run in parallel with another sync that includes only the task's activities.
 *
 * If, at any time, a container is added to a parallel sync that *is* watched by another sync, it
 * will be forced to serialize with it. This is done by adding a dependency. A sync will only
 * finish if it has no active dependencies. At this point it is effectively not parallel anymore.
 *
 * To avoid dependency cycles, if a sync B ultimately depends on a sync A and a container is added
 * to A which is watched by B, that container will, instead, be moved from B to A instead of
 * creating a cyclic dependency.
 *
 * When syncs overlap, this will attempt to finish everything in the order they were started.
 */
 */
class BLASTSyncEngine {
class BLASTSyncEngine {
    private static final String TAG = "BLASTSyncEngine";
    private static final String TAG = "BLASTSyncEngine";
@@ -104,6 +123,18 @@ class BLASTSyncEngine {
        private SurfaceControl.Transaction mOrphanTransaction = null;
        private SurfaceControl.Transaction mOrphanTransaction = null;
        private String mTraceName;
        private String mTraceName;


        private static final ArrayList<SyncGroup> NO_DEPENDENCIES = new ArrayList<>();

        /**
         * When `true`, this SyncGroup will only wait for mRootMembers to draw; otherwise,
         * it waits for the whole subtree(s) rooted at the mRootMembers.
         */
        boolean mIgnoreIndirectMembers = false;

        /** List of SyncGroups that must finish before this one can. */
        @NonNull
        ArrayList<SyncGroup> mDependencies = NO_DEPENDENCIES;

        private SyncGroup(TransactionReadyListener listener, int id, String name) {
        private SyncGroup(TransactionReadyListener listener, int id, String name) {
            mSyncId = id;
            mSyncId = id;
            mListener = listener;
            mListener = listener;
@@ -133,19 +164,43 @@ class BLASTSyncEngine {
            return mOrphanTransaction;
            return mOrphanTransaction;
        }
        }


        private void tryFinish() {
        /**
            if (!mReady) return;
         * Check if the sync-group ignores a particular container. This is used to allow syncs at
         * different levels to run in parallel. The primary example is Recents while an activity
         * sync is happening.
         */
        boolean isIgnoring(WindowContainer wc) {
            // Some heuristics to avoid unnecessary work:
            // 1. For now, require an explicit acknowledgement of potential "parallelism" across
            //    hierarchy levels (horizontal).
            if (!mIgnoreIndirectMembers) return false;
            // 2. Don't check WindowStates since they are below the relevant abstraction level (
            //    anything activity/token and above).
            if (wc.asWindowState() != null) return false;
            // Obviously, don't ignore anything that is directly part of this group.
            return wc.mSyncGroup != this;
        }

        /** @return `true` if it finished. */
        private boolean tryFinish() {
            if (!mReady) return false;
            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: onSurfacePlacement checking %s",
            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: onSurfacePlacement checking %s",
                    mSyncId, mRootMembers);
                    mSyncId, mRootMembers);
            if (!mDependencies.isEmpty()) {
                ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d:  Unfinished dependencies: %s",
                        mSyncId, mDependencies);
                return false;
            }
            for (int i = mRootMembers.size() - 1; i >= 0; --i) {
            for (int i = mRootMembers.size() - 1; i >= 0; --i) {
                final WindowContainer wc = mRootMembers.valueAt(i);
                final WindowContainer wc = mRootMembers.valueAt(i);
                if (!wc.isSyncFinished()) {
                if (!wc.isSyncFinished(this)) {
                    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d:  Unfinished container: %s",
                    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d:  Unfinished container: %s",
                            mSyncId, wc);
                            mSyncId, wc);
                    return;
                    return false;
                }
                }
            }
            }
            finishNow();
            finishNow();
            return true;
        }
        }


        private void finishNow() {
        private void finishNow() {
@@ -158,7 +213,7 @@ class BLASTSyncEngine {
                merged.merge(mOrphanTransaction);
                merged.merge(mOrphanTransaction);
            }
            }
            for (WindowContainer wc : mRootMembers) {
            for (WindowContainer wc : mRootMembers) {
                wc.finishSync(merged, false /* cancel */);
                wc.finishSync(merged, this, false /* cancel */);
            }
            }


            final ArraySet<WindowContainer> wcAwaitingCommit = new ArraySet<>();
            final ArraySet<WindowContainer> wcAwaitingCommit = new ArraySet<>();
@@ -204,7 +259,7 @@ class BLASTSyncEngine {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionReady");
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionReady");
            mListener.onTransactionReady(mSyncId, merged);
            mListener.onTransactionReady(mSyncId, merged);
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            mActiveSyncs.remove(mSyncId);
            mActiveSyncs.remove(this);
            mHandler.removeCallbacks(mOnTimeout);
            mHandler.removeCallbacks(mOnTimeout);


            // Immediately start the next pending sync-transaction if there is one.
            // Immediately start the next pending sync-transaction if there is one.
@@ -230,54 +285,115 @@ class BLASTSyncEngine {
            }
            }
        }
        }


        private void setReady(boolean ready) {
        /** returns true if readiness changed. */
        private boolean setReady(boolean ready) {
            if (mReady == ready) {
            if (mReady == ready) {
                return;
                return false;
            }
            }
            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Set ready %b", mSyncId, ready);
            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Set ready %b", mSyncId, ready);
            mReady = ready;
            mReady = ready;
            if (!ready) return;
            if (ready) {
                mWm.mWindowPlacerLocked.requestTraversal();
                mWm.mWindowPlacerLocked.requestTraversal();
            }
            }
            return true;
        }


        private void addToSync(WindowContainer wc) {
        private void addToSync(WindowContainer wc) {
            if (!mRootMembers.add(wc)) {
            if (mRootMembers.contains(wc)) {
                return;
                return;
            }
            }
            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Adding to group: %s", mSyncId, wc);
            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Adding to group: %s", mSyncId, wc);
            final SyncGroup dependency = wc.getSyncGroup();
            if (dependency != null && dependency != this && !dependency.isIgnoring(wc)) {
                // This syncgroup now conflicts with another one, so the whole group now must
                // wait on the other group.
                Slog.w(TAG, "SyncGroup " + mSyncId + " conflicts with " + dependency.mSyncId
                        + ": Making " + mSyncId + " depend on " + dependency.mSyncId);
                if (mDependencies.contains(dependency)) {
                    // nothing, it's already a dependency.
                } else if (dependency.dependsOn(this)) {
                    Slog.w(TAG, " Detected dependency cycle between " + mSyncId + " and "
                            + dependency.mSyncId + ": Moving " + wc + " to " + mSyncId);
                    // Since dependency already depends on this, make this now `wc`'s watcher
                    if (wc.mSyncGroup == null) {
                        wc.setSyncGroup(this);
                    } else {
                        // Explicit replacement.
                        wc.mSyncGroup.mRootMembers.remove(wc);
                        mRootMembers.add(wc);
                        wc.mSyncGroup = this;
                    }
                } else {
                    if (mDependencies == NO_DEPENDENCIES) {
                        mDependencies = new ArrayList<>();
                    }
                    mDependencies.add(dependency);
                }
            } else {
                mRootMembers.add(wc);
                wc.setSyncGroup(this);
                wc.setSyncGroup(this);
            }
            wc.prepareSync();
            wc.prepareSync();
            if (mReady) {
            if (mReady) {
                mWm.mWindowPlacerLocked.requestTraversal();
                mWm.mWindowPlacerLocked.requestTraversal();
            }
            }
        }
        }


        private boolean dependsOn(SyncGroup group) {
            if (mDependencies.isEmpty()) return false;
            // BFS search with membership check. We don't expect cycle here (since this is
            // explicitly called to avoid cycles) but just to be safe.
            final ArrayList<SyncGroup> fringe = mTmpFringe;
            fringe.clear();
            fringe.add(this);
            for (int head = 0; head < fringe.size(); ++head) {
                final SyncGroup next = fringe.get(head);
                if (next == group) {
                    fringe.clear();
                    return true;
                }
                for (int i = 0; i < next.mDependencies.size(); ++i) {
                    if (fringe.contains(next.mDependencies.get(i))) continue;
                    fringe.add(next.mDependencies.get(i));
                }
            }
            fringe.clear();
            return false;
        }

        void onCancelSync(WindowContainer wc) {
        void onCancelSync(WindowContainer wc) {
            mRootMembers.remove(wc);
            mRootMembers.remove(wc);
        }
        }


        private void onTimeout() {
        private void onTimeout() {
            if (!mActiveSyncs.contains(mSyncId)) return;
            if (!mActiveSyncs.contains(this)) return;
            boolean allFinished = true;
            boolean allFinished = true;
            for (int i = mRootMembers.size() - 1; i >= 0; --i) {
            for (int i = mRootMembers.size() - 1; i >= 0; --i) {
                final WindowContainer<?> wc = mRootMembers.valueAt(i);
                final WindowContainer<?> wc = mRootMembers.valueAt(i);
                if (!wc.isSyncFinished()) {
                if (!wc.isSyncFinished(this)) {
                    allFinished = false;
                    allFinished = false;
                    Slog.i(TAG, "Unfinished container: " + wc);
                    Slog.i(TAG, "Unfinished container: " + wc);
                }
                }
            }
            }
            for (int i = mDependencies.size() - 1; i >= 0; --i) {
                allFinished = false;
                Slog.i(TAG, "Unfinished dependency: " + mDependencies.get(i).mSyncId);
            }
            if (allFinished && !mReady) {
            if (allFinished && !mReady) {
                Slog.w(TAG, "Sync group " + mSyncId + " timed-out because not ready. If you see "
                Slog.w(TAG, "Sync group " + mSyncId + " timed-out because not ready. If you see "
                        + "this, please file a bug.");
                        + "this, please file a bug.");
            }
            }
            finishNow();
            finishNow();
            removeFromDependencies(this);
        }
        }
    }
    }


    private final WindowManagerService mWm;
    private final WindowManagerService mWm;
    private final Handler mHandler;
    private final Handler mHandler;
    private int mNextSyncId = 0;
    private int mNextSyncId = 0;
    private final SparseArray<SyncGroup> mActiveSyncs = new SparseArray<>();

    /** Currently active syncs. Intentionally ordered by start time. */
    private final ArrayList<SyncGroup> mActiveSyncs = new ArrayList<>();


    /**
    /**
     * A queue of pending sync-sets waiting for their turn to run.
     * A queue of pending sync-sets waiting for their turn to run.
@@ -288,6 +404,9 @@ class BLASTSyncEngine {


    private final ArrayList<Runnable> mOnIdleListeners = new ArrayList<>();
    private final ArrayList<Runnable> mOnIdleListeners = new ArrayList<>();


    private final ArrayList<SyncGroup> mTmpFinishQueue = new ArrayList<>();
    private final ArrayList<SyncGroup> mTmpFringe = new ArrayList<>();

    BLASTSyncEngine(WindowManagerService wms) {
    BLASTSyncEngine(WindowManagerService wms) {
        this(wms, wms.mH);
        this(wms, wms.mH);
    }
    }
@@ -306,32 +425,39 @@ class BLASTSyncEngine {
        return new SyncGroup(listener, mNextSyncId++, name);
        return new SyncGroup(listener, mNextSyncId++, name);
    }
    }


    int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name) {
    int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name,
            boolean parallel) {
        final SyncGroup s = prepareSyncSet(listener, name);
        final SyncGroup s = prepareSyncSet(listener, name);
        startSyncSet(s, timeoutMs);
        startSyncSet(s, timeoutMs, parallel);
        return s.mSyncId;
        return s.mSyncId;
    }
    }


    void startSyncSet(SyncGroup s) {
    void startSyncSet(SyncGroup s) {
        startSyncSet(s, BLAST_TIMEOUT_DURATION);
        startSyncSet(s, BLAST_TIMEOUT_DURATION, false /* parallel */);
    }
    }


    void startSyncSet(SyncGroup s, long timeoutMs) {
    void startSyncSet(SyncGroup s, long timeoutMs, boolean parallel) {
        if (mActiveSyncs.size() != 0) {
        final boolean alreadyRunning = mActiveSyncs.size() > 0;
            // We currently only support one sync at a time, so start a new SyncGroup when there is
        if (!parallel && alreadyRunning) {
            // another may cause issue.
            // We only support overlapping syncs when explicitly declared `parallel`.
            Slog.e(TAG, "SyncGroup " + s.mSyncId
            Slog.e(TAG, "SyncGroup " + s.mSyncId
                    + ": Started when there is other active SyncGroup");
                    + ": Started when there is other active SyncGroup");
        }
        }
        mActiveSyncs.put(s.mSyncId, s);
        mActiveSyncs.add(s);
        ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started for listener: %s",
        // For now, parallel implies this.
                s.mSyncId, s.mListener);
        s.mIgnoreIndirectMembers = parallel;
        ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started %sfor listener: %s",
                s.mSyncId, (parallel && alreadyRunning ? "(in parallel) " : ""), s.mListener);
        scheduleTimeout(s, timeoutMs);
        scheduleTimeout(s, timeoutMs);
    }
    }


    @Nullable
    @Nullable
    SyncGroup getSyncSet(int id) {
    SyncGroup getSyncSet(int id) {
        return mActiveSyncs.get(id);
        for (int i = 0; i < mActiveSyncs.size(); ++i) {
            if (mActiveSyncs.get(i).mSyncId != id) continue;
            return mActiveSyncs.get(i);
        }
        return null;
    }
    }


    boolean hasActiveSync() {
    boolean hasActiveSync() {
@@ -356,8 +482,8 @@ class BLASTSyncEngine {
        syncGroup.mSyncMethod = method;
        syncGroup.mSyncMethod = method;
    }
    }


    void setReady(int id, boolean ready) {
    boolean setReady(int id, boolean ready) {
        getSyncGroup(id).setReady(ready);
        return getSyncGroup(id).setReady(ready);
    }
    }


    void setReady(int id) {
    void setReady(int id) {
@@ -372,21 +498,68 @@ class BLASTSyncEngine {
     * Aborts the sync (ie. it doesn't wait for ready or anything to finish)
     * Aborts the sync (ie. it doesn't wait for ready or anything to finish)
     */
     */
    void abort(int id) {
    void abort(int id) {
        getSyncGroup(id).finishNow();
        final SyncGroup group = getSyncGroup(id);
        group.finishNow();
        removeFromDependencies(group);
    }
    }


    private SyncGroup getSyncGroup(int id) {
    private SyncGroup getSyncGroup(int id) {
        final SyncGroup syncGroup = mActiveSyncs.get(id);
        final SyncGroup syncGroup = getSyncSet(id);
        if (syncGroup == null) {
        if (syncGroup == null) {
            throw new IllegalStateException("SyncGroup is not started yet id=" + id);
            throw new IllegalStateException("SyncGroup is not started yet id=" + id);
        }
        }
        return syncGroup;
        return syncGroup;
    }
    }


    /**
     * Just removes `group` from any dependency lists. Does not try to evaluate anything. However,
     * it will schedule traversals if any groups were changed in a way that could make them ready.
     */
    private void removeFromDependencies(SyncGroup group) {
        boolean anyChange = false;
        for (int i = 0; i < mActiveSyncs.size(); ++i) {
            final SyncGroup active = mActiveSyncs.get(i);
            if (!active.mDependencies.remove(group)) continue;
            if (!active.mDependencies.isEmpty()) continue;
            anyChange = true;
        }
        if (!anyChange) return;
        mWm.mWindowPlacerLocked.requestTraversal();
    }

    void onSurfacePlacement() {
    void onSurfacePlacement() {
        // backwards since each state can remove itself if finished
        if (mActiveSyncs.isEmpty()) return;
        for (int i = mActiveSyncs.size() - 1; i >= 0; --i) {
        // queue in-order since we want interdependent syncs to become ready in the same order they
            mActiveSyncs.valueAt(i).tryFinish();
        // started in.
        mTmpFinishQueue.addAll(mActiveSyncs);
        // There shouldn't be any dependency cycles or duplicates, but add an upper-bound just
        // in case. Assuming absolute worst case, each visit will try and revisit everything
        // before it, so n + (n-1) + (n-2) ... = (n+1)*n/2
        int visitBounds = ((mActiveSyncs.size() + 1) * mActiveSyncs.size()) / 2;
        while (!mTmpFinishQueue.isEmpty()) {
            if (visitBounds <= 0) {
                Slog.e(TAG, "Trying to finish more syncs than theoretically possible. This "
                        + "should never happen. Most likely a dependency cycle wasn't detected.");
            }
            --visitBounds;
            final SyncGroup group = mTmpFinishQueue.remove(0);
            final int grpIdx = mActiveSyncs.indexOf(group);
            // Skip if it's already finished:
            if (grpIdx < 0) continue;
            if (!group.tryFinish()) continue;
            // Finished, so update dependencies of any prior groups and retry if unblocked.
            int insertAt = 0;
            for (int i = 0; i < mActiveSyncs.size(); ++i) {
                final SyncGroup active = mActiveSyncs.get(i);
                if (!active.mDependencies.remove(group)) continue;
                // Anything afterwards is already in queue.
                if (i >= grpIdx) continue;
                if (!active.mDependencies.isEmpty()) continue;
                // `active` became unblocked so it can finish, since it started earlier, it should
                // be checked next to maintain order.
                mTmpFinishQueue.add(insertAt, mActiveSyncs.get(i));
                insertAt += 1;
            }
        }
        }
    }
    }


+1 −1
Original line number Original line Diff line number Diff line
@@ -1755,7 +1755,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
    }
    }


    @Override
    @Override
    boolean isSyncFinished() {
    boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) {
        // Do not consider children because if they are requested to be synced, they should be
        // Do not consider children because if they are requested to be synced, they should be
        // added to sync group explicitly.
        // added to sync group explicitly.
        return !mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange();
        return !mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange();
+2 −2
Original line number Original line Diff line number Diff line
@@ -2547,8 +2547,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
    }
    }


    @Override
    @Override
    boolean isSyncFinished() {
    boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) {
        return super.isSyncFinished() && isReadyToTransit();
        return super.isSyncFinished(group) && isReadyToTransit();
    }
    }


    @Override
    @Override
Loading