summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/etc/services.core.protolog.json24
-rw-r--r--services/core/java/com/android/server/wm/BLASTSyncEngine.java66
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java45
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java120
5 files changed, 189 insertions, 73 deletions
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 89aa662db2f9..5d42c89240a2 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -13,12 +13,6 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "-2125618712": {
- "message": "PendingStartTransition found",
- "level": "VERBOSE",
- "group": "WM_DEBUG_WINDOW_TRANSITIONS",
- "at": "com\/android\/server\/wm\/TransitionController.java"
- },
"-2121056984": {
"message": "%s",
"level": "WARN",
@@ -2785,6 +2779,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
+ "800698875": {
+ "message": "SyncGroup %d: Started when there is other active SyncGroup",
+ "level": "WARN",
+ "group": "WM_DEBUG_SYNC_ENGINE",
+ "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+ },
"806891543": {
"message": "Setting mOrientationChangeComplete=true because wtoken %s numInteresting=%d numDrawn=%d",
"level": "INFO",
@@ -3685,12 +3685,6 @@
"group": "WM_DEBUG_WINDOW_ORGANIZER",
"at": "com\/android\/server\/wm\/DisplayAreaPolicyBuilder.java"
},
- "1884961873": {
- "message": "Sleep still need to stop %d activities",
- "level": "VERBOSE",
- "group": "WM_DEBUG_STATES",
- "at": "com\/android\/server\/wm\/Task.java"
- },
"1891501279": {
"message": "cancelAnimation(): reason=%s",
"level": "DEBUG",
@@ -3823,6 +3817,12 @@
"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 bb4519cfc679..5c1ddd964325 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -64,6 +64,11 @@ class BLASTSyncEngine {
void onTransactionReady(int mSyncId, SurfaceControl.Transaction transaction);
}
+ interface SyncEngineListener {
+ /** Called when there is no more active sync set. */
+ void onSyncEngineFree();
+ }
+
/**
* Holds state associated with a single synchronous set of operations.
*/
@@ -137,6 +142,9 @@ class BLASTSyncEngine {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
mActiveSyncs.remove(mSyncId);
mWm.mH.removeCallbacks(mOnTimeout);
+ if (mSyncEngineListener != null && mActiveSyncs.size() == 0) {
+ mSyncEngineListener.onSyncEngineFree();
+ }
}
private void setReady(boolean ready) {
@@ -175,22 +183,54 @@ class BLASTSyncEngine {
private final WindowManagerService mWm;
private int mNextSyncId = 0;
private final SparseArray<SyncGroup> mActiveSyncs = new SparseArray<>();
+ private SyncEngineListener mSyncEngineListener;
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}.
+ */
+ SyncGroup prepareSyncSet(TransactionReadyListener listener, String name) {
+ return new SyncGroup(listener, mNextSyncId++, name);
+ }
+
int startSyncSet(TransactionReadyListener listener) {
return startSyncSet(listener, WindowState.BLAST_TIMEOUT_DURATION, "");
}
int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name) {
- final int id = mNextSyncId++;
- final SyncGroup s = new SyncGroup(listener, id, name);
- mActiveSyncs.put(id, s);
- ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started for listener: %s", id, listener);
+ final SyncGroup s = prepareSyncSet(listener, name);
+ startSyncSet(s, timeoutMs);
+ return s.mSyncId;
+ }
+
+ void startSyncSet(SyncGroup s) {
+ startSyncSet(s, WindowState.BLAST_TIMEOUT_DURATION);
+ }
+
+ void startSyncSet(SyncGroup s, long timeoutMs) {
+ if (mActiveSyncs.size() != 0) {
+ // We currently only support one sync at a time, so start a new SyncGroup when there is
+ // another may cause issue.
+ ProtoLog.w(WM_DEBUG_SYNC_ENGINE,
+ "SyncGroup %d: Started when there is other active SyncGroup", s.mSyncId);
+ }
+ mActiveSyncs.put(s.mSyncId, s);
+ ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started for listener: %s",
+ s.mSyncId, s.mListener);
scheduleTimeout(s, timeoutMs);
- return id;
+ }
+
+ boolean hasActiveSync() {
+ return mActiveSyncs.size() != 0;
}
@VisibleForTesting
@@ -199,11 +239,11 @@ class BLASTSyncEngine {
}
void addToSyncSet(int id, WindowContainer wc) {
- mActiveSyncs.get(id).addToSync(wc);
+ getSyncGroup(id).addToSync(wc);
}
void setReady(int id, boolean ready) {
- mActiveSyncs.get(id).setReady(ready);
+ getSyncGroup(id).setReady(ready);
}
void setReady(int id) {
@@ -211,14 +251,22 @@ class BLASTSyncEngine {
}
boolean isReady(int id) {
- return mActiveSyncs.get(id).mReady;
+ return getSyncGroup(id).mReady;
}
/**
* Aborts the sync (ie. it doesn't wait for ready or anything to finish)
*/
void abort(int id) {
- mActiveSyncs.get(id).finishNow();
+ getSyncGroup(id).finishNow();
+ }
+
+ private SyncGroup getSyncGroup(int id) {
+ final SyncGroup syncGroup = mActiveSyncs.get(id);
+ if (syncGroup == null) {
+ throw new IllegalStateException("SyncGroup is not started yet id=" + id);
+ }
+ return syncGroup;
}
void onSurfacePlacement() {
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index b482cfa0d482..7a031db3a226 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -30,7 +30,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IApplicationThread;
-import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
@@ -92,20 +91,6 @@ class TransitionController {
/** The transition currently being constructed (collecting participants). */
private Transition mCollectingTransition = null;
- /**
- * A queue of transitions waiting for their turn to collect. We can only collect 1 transition
- * at a time because 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 at arbitrary times via
- * {@link WindowOrganizerController#startTransition}, so we have to support those coming in
- * at any time (even while already collecting).
- *
- * This is really just a back-up for unrealistic situations (eg. during tests). In practice,
- * this shouldn't ever happen.
- */
- private final ArrayList<PendingStartTransition> mPendingStartTransitions = new ArrayList<>();
-
// TODO(b/188595497): remove when not needed.
final StatusBarManagerInternal mStatusBar;
@@ -175,9 +160,13 @@ class TransitionController {
}
final PendingStartTransition out = new PendingStartTransition(new Transition(type,
0 /* flags */, this, mAtm.mWindowManager.mSyncEngine));
+ // We want to start collecting immediately when the engine is free, otherwise it may
+ // be busy again.
+ out.setStartSync(() -> {
+ moveToCollecting(out.mTransition);
+ });
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Creating PendingTransition: %s",
out.mTransition);
- mPendingStartTransitions.add(out);
return out;
}
@@ -451,15 +440,6 @@ class TransitionController {
throw new IllegalStateException("Trying to move non-collecting transition to playing");
}
mCollectingTransition = null;
- if (!mPendingStartTransitions.isEmpty()) {
- ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "PendingStartTransition found");
- final PendingStartTransition p = mPendingStartTransitions.remove(0);
- moveToCollecting(p.mTransition);
- if (p.mOnStartCollecting != null) {
- // Post this so that the now-playing transition setup isn't interrupted.
- p.mHandler.post(p.mOnStartCollecting);
- }
- }
if (mPlayingTransitions.isEmpty()) {
setAnimationRunning(true /* running */);
}
@@ -557,24 +537,13 @@ class TransitionController {
proto.end(token);
}
- /** Represents a startTransition call made while a transition was already collecting. */
- static class PendingStartTransition {
+ /** Represents a startTransition call made while there is other active BLAST SyncGroup. */
+ class PendingStartTransition extends WindowOrganizerController.PendingTransaction {
final Transition mTransition;
- /** Handler to post the collecting callback onto. */
- private Handler mHandler;
-
- /** Runnable to post to `mHandler` once this pending transition starts collecting. */
- private Runnable mOnStartCollecting;
-
PendingStartTransition(Transition transition) {
mTransition = transition;
}
-
- void setOnStartCollecting(@NonNull Handler handler, @NonNull Runnable callback) {
- mHandler = handler;
- mOnStartCollecting = callback;
- }
}
static class TransitionMetricsReporter extends ITransitionMetricsReporter.Stub {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 400684840467..1205dee595b9 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -85,8 +85,8 @@ import android.view.MagnificationSpec;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
import android.view.SurfaceControl.Builder;
+import android.view.SurfaceControlViewHost;
import android.view.SurfaceSession;
import android.view.TaskTransitionSpec;
import android.view.WindowManager;
@@ -3331,7 +3331,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "setSyncGroup #%d on %s", group.mSyncId, this);
if (group != null) {
if (mSyncGroup != null && mSyncGroup != group) {
- throw new IllegalStateException("Can't sync on 2 engines simultaneously");
+ // This can still happen if WMCore starts a new transition when there is ongoing
+ // sync transaction from Shell. Please file a bug if it happens.
+ throw new IllegalStateException("Can't sync on 2 engines simultaneously"
+ + " currentSyncId=" + mSyncGroup.mSyncId + " newSyncId=" + group.mSyncId);
}
}
mSyncGroup = group;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index d0f0220a796b..27024ce77bd2 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -76,6 +76,7 @@ import android.window.TaskFragmentCreationParams;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.pooled.PooledConsumer;
@@ -94,7 +95,7 @@ import java.util.Map;
* @see android.window.WindowOrganizer
*/
class WindowOrganizerController extends IWindowOrganizerController.Stub
- implements BLASTSyncEngine.TransactionReadyListener {
+ implements BLASTSyncEngine.TransactionReadyListener, BLASTSyncEngine.SyncEngineListener {
private static final String TAG = "WindowOrganizerController";
@@ -117,6 +118,21 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
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;
@@ -140,6 +156,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
void setWindowManager(WindowManagerService wms) {
mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController);
mTransitionController.registerLegacyListener(wms.mActivityManagerAppTransitionNotifier);
+ wms.mSyncEngine.setSyncEngineListener(this);
}
TransitionController getTransitionController() {
@@ -184,6 +201,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ if (callback == null) {
+ applyTransaction(t, -1 /* syncId*/, null /*transition*/, caller);
+ return -1;
+ }
+
/**
* If callback is non-null we are looking to synchronize this transaction by
* collecting all the results in to a SurfaceFlinger transaction and then delivering
@@ -196,13 +218,25 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
* all the WindowContainers will eventually finish applying their changes and notify
* the BLASTSyncEngine which will deliver the Transaction to the callback.
*/
- int syncId = -1;
- if (callback != null) {
- syncId = startSyncWithOrganizer(callback);
- }
- applyTransaction(t, syncId, null /*transition*/, caller);
- if (syncId >= 0) {
+ final BLASTSyncEngine.SyncGroup syncGroup = prepareSyncWithOrganizer(callback);
+ final int syncId = syncGroup.mSyncId;
+ if (!mService.mWindowManager.mSyncEngine.hasActiveSync()) {
+ mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup);
+ applyTransaction(t, syncId, null /*transition*/, caller);
setSyncReady(syncId);
+ } 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);
}
return syncId;
}
@@ -244,17 +278,19 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
// return that. The actual start and apply will then be deferred until that
// transition starts collecting. This should almost never happen except during
// tests.
- if (mTransitionController.isCollecting()) {
+ if (mService.mWindowManager.mSyncEngine.hasActiveSync()) {
Slog.e(TAG, "startTransition() while one is already collecting.");
final TransitionController.PendingStartTransition pt =
mTransitionController.createPendingTransition(type);
- pt.setOnStartCollecting(mService.mH, () -> {
+ // 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;
}
transition = mTransitionController.createTransition(type);
@@ -1052,11 +1088,24 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return mTaskFragmentOrganizerController;
}
+ /**
+ * This will prepare a {@link BLASTSyncEngine.SyncGroup} for the organizer to track, but the
+ * {@link BLASTSyncEngine.SyncGroup} may not be active until the {@link BLASTSyncEngine} is
+ * free.
+ */
+ private BLASTSyncEngine.SyncGroup prepareSyncWithOrganizer(
+ IWindowContainerTransactionCallback callback) {
+ final BLASTSyncEngine.SyncGroup s = mService.mWindowManager.mSyncEngine
+ .prepareSyncSet(this, "");
+ mTransactionCallbacksByPendingSyncId.put(s.mSyncId, callback);
+ return s;
+ }
+
@VisibleForTesting
int startSyncWithOrganizer(IWindowContainerTransactionCallback callback) {
- int id = mService.mWindowManager.mSyncEngine.startSyncSet(this);
- mTransactionCallbacksByPendingSyncId.put(id, callback);
- return id;
+ final BLASTSyncEngine.SyncGroup s = prepareSyncWithOrganizer(callback);
+ mService.mWindowManager.mSyncEngine.startSyncSet(s);
+ return s.mSyncId;
}
@VisibleForTesting
@@ -1088,6 +1137,19 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
@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(pt::startTransaction);
+ }
+
+ @Override
public void registerTransitionPlayer(ITransitionPlayer player) {
enforceTaskPermission("registerTransitionPlayer()");
final int callerPid = Binder.getCallingPid();
@@ -1345,4 +1407,38 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
+ 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();
+ }
+ }
}