Merge "Move the pendingTransaction stuff into BLASTSyncEngine" into tm-dev
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index bde18f3..5bbea77 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -3439,12 +3439,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "1333520287": {
- "message": "Creating PendingTransition: %s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_WINDOW_TRANSITIONS",
- "at": "com\/android\/server\/wm\/TransitionController.java"
- },
"1335791109": {
"message": "createSurface %s: mDrawState=DRAW_PENDING",
"level": "INFO",
@@ -3739,6 +3733,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/InsetsStateController.java"
},
+ "1667162379": {
+ "message": "Creating Pending Transition: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+ },
"1670933628": {
"message": " Setting allReady override",
"level": "VERBOSE",
@@ -3793,6 +3793,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1730300180": {
+ "message": "PendingStartTransaction found",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_SYNC_ENGINE",
+ "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+ },
"1739298851": {
"message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d",
"level": "WARN",
@@ -4105,12 +4111,6 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "2034988903": {
- "message": "PendingStartTransaction found",
- "level": "VERBOSE",
- "group": "WM_DEBUG_WINDOW_TRANSITIONS",
- "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
- },
"2039056415": {
"message": "Found matching affinity candidate!",
"level": "DEBUG",
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 5c1ddd9..6e205be 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -30,6 +30,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
+import java.util.ArrayList;
+
/**
* Utility class for collecting WindowContainers that will merge transactions.
* For example to use to synchronously resize all the children of a window container
@@ -64,9 +66,17 @@
void onTransactionReady(int mSyncId, SurfaceControl.Transaction transaction);
}
- interface SyncEngineListener {
- /** Called when there is no more active sync set. */
- void onSyncEngineFree();
+ /**
+ * Represents the desire to make a {@link BLASTSyncEngine.SyncGroup} while another is active.
+ *
+ * @see #queueSyncSet
+ */
+ private static class PendingSyncSet {
+ /** Called immediately when the {@link BLASTSyncEngine} is free. */
+ private Runnable mStartSync;
+
+ /** Posted to the main handler after {@link #mStartSync} is called. */
+ private Runnable mApplySync;
}
/**
@@ -142,8 +152,21 @@
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
mActiveSyncs.remove(mSyncId);
mWm.mH.removeCallbacks(mOnTimeout);
- if (mSyncEngineListener != null && mActiveSyncs.size() == 0) {
- mSyncEngineListener.onSyncEngineFree();
+
+ // Immediately start the next pending sync-transaction if there is one.
+ if (mActiveSyncs.size() == 0 && !mPendingSyncSets.isEmpty()) {
+ ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "PendingStartTransaction found");
+ final PendingSyncSet pt = mPendingSyncSets.remove(0);
+ pt.mStartSync.run();
+ if (mActiveSyncs.size() == 0) {
+ throw new IllegalStateException("Pending Sync Set didn't start a sync.");
+ }
+ // Post this so that the now-playing transition setup isn't interrupted.
+ mWm.mH.post(() -> {
+ synchronized (mWm.mGlobalLock) {
+ pt.mApplySync.run();
+ }
+ });
}
}
@@ -183,17 +206,18 @@
private final WindowManagerService mWm;
private int mNextSyncId = 0;
private final SparseArray<SyncGroup> mActiveSyncs = new SparseArray<>();
- private SyncEngineListener mSyncEngineListener;
+
+ /**
+ * A queue of pending sync-sets waiting for their turn to run.
+ *
+ * @see #queueSyncSet
+ */
+ private final ArrayList<PendingSyncSet> mPendingSyncSets = new ArrayList<>();
BLASTSyncEngine(WindowManagerService wms) {
mWm = wms;
}
- /** Sets listener listening to whether the sync engine is free. */
- void setSyncEngineListener(SyncEngineListener listener) {
- mSyncEngineListener = listener;
- }
-
/**
* Prepares a {@link SyncGroup} that is not active yet. Caller must call {@link #startSyncSet}
* before calling {@link #addToSyncSet(int, WindowContainer)} on any {@link WindowContainer}.
@@ -275,4 +299,31 @@
mActiveSyncs.valueAt(i).onSurfacePlacement();
}
}
+
+ /**
+ * Queues a sync operation onto this engine. It will wait until any current/prior sync-sets
+ * have finished to run. This is needed right now because currently {@link BLASTSyncEngine}
+ * only supports 1 sync at a time.
+ *
+ * Code-paths should avoid using this unless absolutely necessary. Usually, we use this for
+ * difficult edge-cases that we hope to clean-up later.
+ *
+ * @param startSync will be called immediately when the {@link BLASTSyncEngine} is free to
+ * "reserve" the {@link BLASTSyncEngine} by calling one of the
+ * {@link BLASTSyncEngine#startSyncSet} variants.
+ * @param applySync will be posted to the main handler after {@code startSync} has been
+ * called. This is posted so that it doesn't interrupt any clean-up for the
+ * prior sync-set.
+ */
+ void queueSyncSet(@NonNull Runnable startSync, @NonNull Runnable applySync) {
+ final PendingSyncSet pt = new PendingSyncSet();
+ pt.mStartSync = startSync;
+ pt.mApplySync = applySync;
+ mPendingSyncSets.add(pt);
+ }
+
+ /** @return {@code true} if there are any sync-sets waiting to start. */
+ boolean hasPendingSyncSets() {
+ return !mPendingSyncSets.isEmpty();
+ }
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 18851b3..23479a2 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -99,9 +99,6 @@
// TODO(b/188595497): remove when not needed.
final StatusBarManagerInternal mStatusBar;
- /** Pending transitions from Shell that are waiting the SyncEngine to be free. */
- private final ArrayList<PendingStartTransition> mPendingTransitions = new ArrayList<>();
-
TransitionController(ActivityTaskManagerService atm,
TaskSnapshotController taskSnapshotController) {
mAtm = atm;
@@ -146,7 +143,7 @@
}
/** Starts Collecting */
- private void moveToCollecting(@NonNull Transition transition) {
+ void moveToCollecting(@NonNull Transition transition) {
if (mCollectingTransition != null) {
throw new IllegalStateException("Simultaneous transition collection not supported.");
}
@@ -160,26 +157,6 @@
dispatchLegacyAppTransitionPending();
}
- /** Creates a transition representation but doesn't start collecting. */
- @NonNull
- PendingStartTransition createPendingTransition(@WindowManager.TransitionType int type) {
- if (mTransitionPlayer == null) {
- throw new IllegalStateException("Shell Transitions not enabled");
- }
- final PendingStartTransition out = new PendingStartTransition(new Transition(type,
- 0 /* flags */, this, mAtm.mWindowManager.mSyncEngine));
- mPendingTransitions.add(out);
- // We want to start collecting immediately when the engine is free, otherwise it may
- // be busy again.
- out.setStartSync(() -> {
- mPendingTransitions.remove(out);
- moveToCollecting(out.mTransition);
- });
- ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Creating PendingTransition: %s",
- out.mTransition);
- return out;
- }
-
void registerTransitionPlayer(@Nullable ITransitionPlayer player,
@Nullable IApplicationThread appThread) {
try {
@@ -601,24 +578,16 @@
if (!mPlayingTransitions.isEmpty()) {
state = LEGACY_STATE_RUNNING;
} else if ((mCollectingTransition != null && mCollectingTransition.getLegacyIsReady())
- || !mPendingTransitions.isEmpty()) {
- // The transition may not be "ready", but we have transition waiting to start, so it
- // can't be IDLE for test purpose. Ideally, we should have a STATE_COLLECTING.
+ || mAtm.mWindowManager.mSyncEngine.hasPendingSyncSets()) {
+ // The transition may not be "ready", but we have a sync-transaction waiting to start.
+ // Usually the pending transaction is for a transition, so assuming that is the case,
+ // we can't be IDLE for test purposes. Ideally, we should have a STATE_COLLECTING.
state = LEGACY_STATE_READY;
}
proto.write(AppTransitionProto.APP_TRANSITION_STATE, state);
proto.end(token);
}
- /** Represents a startTransition call made while there is other active BLAST SyncGroup. */
- class PendingStartTransition extends WindowOrganizerController.PendingTransaction {
- final Transition mTransition;
-
- PendingStartTransition(Transition transition) {
- mTransition = transition;
- }
- }
-
static class TransitionMetricsReporter extends ITransitionMetricsReporter.Stub {
private final ArrayMap<IBinder, LongConsumer> mMetricConsumers = new ArrayMap<>();
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 3b1d2db..b5cf708 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -99,7 +99,7 @@
* @see android.window.WindowOrganizer
*/
class WindowOrganizerController extends IWindowOrganizerController.Stub
- implements BLASTSyncEngine.TransactionReadyListener, BLASTSyncEngine.SyncEngineListener {
+ implements BLASTSyncEngine.TransactionReadyListener {
private static final String TAG = "WindowOrganizerController";
@@ -122,21 +122,6 @@
private final HashMap<Integer, IWindowContainerTransactionCallback>
mTransactionCallbacksByPendingSyncId = new HashMap();
- /**
- * A queue of transaction waiting for their turn to sync. Currently {@link BLASTSyncEngine} only
- * supports 1 sync at a time, so we have to queue them.
- *
- * WMCore has enough information to ensure that it won't end up collecting multiple transitions
- * in parallel by itself; however, Shell can start transitions/apply sync transaction at
- * arbitrary times via {@link WindowOrganizerController#startTransition} and
- * {@link WindowOrganizerController#applySyncTransaction}, so we have to support those coming in
- * at any time (even while already syncing).
- *
- * This is really just a back-up for unrealistic situations (eg. during tests). In practice,
- * this shouldn't ever happen.
- */
- private final ArrayList<PendingTransaction> mPendingTransactions = new ArrayList<>();
-
final TaskOrganizerController mTaskOrganizerController;
final DisplayAreaOrganizerController mDisplayAreaOrganizerController;
final TaskFragmentOrganizerController mTaskFragmentOrganizerController;
@@ -160,7 +145,6 @@
void setWindowManager(WindowManagerService wms) {
mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController);
mTransitionController.registerLegacyListener(wms.mActivityManagerAppTransitionNotifier);
- wms.mSyncEngine.setSyncEngineListener(this);
}
TransitionController getTransitionController() {
@@ -231,16 +215,12 @@
} else {
// Because the BLAST engine only supports one sync at a time, queue the
// transaction.
- final PendingTransaction pt = new PendingTransaction();
- // Start sync group immediately when the SyncEngine is free.
- pt.setStartSync(() ->
- mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup));
- // Those will be post so that it won't interrupt ongoing transition.
- pt.setStartTransaction(() -> {
- applyTransaction(t, syncId, null /*transition*/, caller);
- setSyncReady(syncId);
- });
- mPendingTransactions.add(pt);
+ mService.mWindowManager.mSyncEngine.queueSyncSet(
+ () -> mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup),
+ () -> {
+ applyTransaction(t, syncId, null /*transition*/, caller);
+ setSyncReady(syncId);
+ });
}
return syncId;
}
@@ -283,19 +263,24 @@
// transition starts collecting. This should almost never happen except during
// tests.
if (mService.mWindowManager.mSyncEngine.hasActiveSync()) {
- Slog.e(TAG, "startTransition() while one is already collecting.");
- final TransitionController.PendingStartTransition pt =
- mTransitionController.createPendingTransition(type);
- // Those will be post so that it won't interrupt ongoing transition.
- pt.setStartTransaction(() -> {
- pt.mTransition.start();
- applyTransaction(wct, -1 /*syncId*/, pt.mTransition, caller);
- if (needsSetReady) {
- pt.mTransition.setAllReady();
- }
- });
- mPendingTransactions.add(pt);
- return pt.mTransition;
+ Slog.w(TAG, "startTransition() while one is already collecting.");
+ final Transition nextTransition = new Transition(type, 0 /* flags */,
+ mTransitionController, mService.mWindowManager.mSyncEngine);
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ "Creating Pending Transition: %s", nextTransition);
+ mService.mWindowManager.mSyncEngine.queueSyncSet(
+ // Make sure to collect immediately to prevent another transition
+ // from sneaking in before it. Note: moveToCollecting internally
+ // calls startSyncSet.
+ () -> mTransitionController.moveToCollecting(nextTransition),
+ () -> {
+ nextTransition.start();
+ applyTransaction(wct, -1 /*syncId*/, nextTransition, caller);
+ if (needsSetReady) {
+ nextTransition.setAllReady();
+ }
+ });
+ return nextTransition;
}
transition = mTransitionController.createTransition(type);
}
@@ -1198,23 +1183,6 @@
}
@Override
- public void onSyncEngineFree() {
- if (mPendingTransactions.isEmpty()) {
- return;
- }
-
- ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "PendingStartTransaction found");
- final PendingTransaction pt = mPendingTransactions.remove(0);
- pt.startSync();
- // Post this so that the now-playing transition setup isn't interrupted.
- mService.mH.post(() -> {
- synchronized (mGlobalLock) {
- pt.startTransaction();
- }
- });
- }
-
- @Override
public void registerTransitionPlayer(ITransitionPlayer player) {
enforceTaskPermission("registerTransitionPlayer()");
final int callerPid = Binder.getCallingPid();
@@ -1563,38 +1531,4 @@
+ result + " when starting " + intent);
}
}
-
- /**
- * Represents a sync {@link WindowContainerTransaction} call made while there is other active
- * {@link BLASTSyncEngine.SyncGroup}.
- */
- static class PendingTransaction {
- private Runnable mStartSync;
- private Runnable mStartTransaction;
-
- /**
- * The callback will be called immediately when the {@link BLASTSyncEngine} is free. One
- * should call {@link BLASTSyncEngine#startSyncSet(BLASTSyncEngine.SyncGroup)} here to
- * reserve the {@link BLASTSyncEngine}.
- */
- void setStartSync(@NonNull Runnable callback) {
- mStartSync = callback;
- }
-
- /**
- * The callback will be post to the main handler after the {@link BLASTSyncEngine} is free
- * to apply the pending {@link WindowContainerTransaction}.
- */
- void setStartTransaction(@NonNull Runnable callback) {
- mStartTransaction = callback;
- }
-
- private void startSync() {
- mStartSync.run();
- }
-
- private void startTransaction() {
- mStartTransaction.run();
- }
- }
}