diff options
8 files changed, 59 insertions, 48 deletions
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java index 5c9c81300e0d..7a11120132bd 100644 --- a/services/core/java/com/android/server/wm/AsyncRotationController.java +++ b/services/core/java/com/android/server/wm/AsyncRotationController.java @@ -93,6 +93,9 @@ class AsyncRotationController extends FadeAnimationController implements Consume /** Whether the start transaction of the transition is committed (by shell). */ private boolean mIsStartTransactionCommitted; + /** Whether all windows should wait for the start transaction. */ + private boolean mAlwaysWaitForStartTransaction; + /** Whether the target windows have been requested to sync their draw transactions. */ private boolean mIsSyncDrawRequested; @@ -144,6 +147,15 @@ class AsyncRotationController extends FadeAnimationController implements Consume if (mTransitionOp == OP_LEGACY) { mIsStartTransactionCommitted = true; } else if (displayContent.mTransitionController.isCollecting(displayContent)) { + final Transition transition = + mDisplayContent.mTransitionController.getCollectingTransition(); + if (transition != null) { + final BLASTSyncEngine.SyncGroup syncGroup = + mDisplayContent.mWmService.mSyncEngine.getSyncSet(transition.getSyncId()); + if (syncGroup != null && syncGroup.mSyncMethod == BLASTSyncEngine.METHOD_BLAST) { + mAlwaysWaitForStartTransaction = true; + } + } keepAppearanceInPreviousRotation(); } } @@ -202,7 +214,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume // target windows. But the windows still need to use sync transaction to keep the appearance // in previous rotation, so request a no-op sync to keep the state. for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) { - if (mTargetWindowTokens.valueAt(i).canDrawBeforeStartTransaction()) { + if (canDrawBeforeStartTransaction(mTargetWindowTokens.valueAt(i))) { // Expect a screenshot layer will cover the non seamless windows. continue; } @@ -521,7 +533,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume if (op == null) return false; if (DEBUG) Slog.d(TAG, "handleFinishDrawing " + w); if (postDrawTransaction == null || !mIsSyncDrawRequested - || op.canDrawBeforeStartTransaction()) { + || canDrawBeforeStartTransaction(op)) { mDisplayContent.finishAsyncRotation(w.mToken); return false; } @@ -563,6 +575,14 @@ class AsyncRotationController extends FadeAnimationController implements Consume return super.getFadeOutAnimation(); } + /** + * Returns {@code true} if the corresponding window can draw its latest content before the + * start transaction of rotation transition is applied. + */ + private boolean canDrawBeforeStartTransaction(Operation op) { + return !mAlwaysWaitForStartTransaction && op.mAction != Operation.ACTION_SEAMLESS; + } + /** The operation to control the rotation appearance associated with window token. */ private static class Operation { @Retention(RetentionPolicy.SOURCE) @@ -588,14 +608,5 @@ class AsyncRotationController extends FadeAnimationController implements Consume Operation(@Action int action) { mAction = action; } - - /** - * Returns {@code true} if the corresponding window can draw its latest content before the - * start transaction of rotation transition is applied. - */ - boolean canDrawBeforeStartTransaction() { - return TransitionController.SYNC_METHOD != BLASTSyncEngine.METHOD_BLAST - && mAction != ACTION_SEAMLESS; - } } } diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java index cd26e2eb9c53..48cf567ba9be 100644 --- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java +++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java @@ -95,7 +95,7 @@ class BLASTSyncEngine { */ class SyncGroup { final int mSyncId; - final int mSyncMethod; + int mSyncMethod = METHOD_BLAST; final TransactionReadyListener mListener; final Runnable mOnTimeout; boolean mReady = false; @@ -103,9 +103,8 @@ class BLASTSyncEngine { private SurfaceControl.Transaction mOrphanTransaction = null; private String mTraceName; - private SyncGroup(TransactionReadyListener listener, int id, String name, int method) { + private SyncGroup(TransactionReadyListener listener, int id, String name) { mSyncId = id; - mSyncMethod = method; mListener = listener; mOnTimeout = () -> { Slog.w(TAG, "Sync group " + mSyncId + " timeout"); @@ -288,13 +287,12 @@ class BLASTSyncEngine { * 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, int method) { - return new SyncGroup(listener, mNextSyncId++, name, method); + SyncGroup prepareSyncSet(TransactionReadyListener listener, String name) { + return new SyncGroup(listener, mNextSyncId++, name); } - int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name, - int method) { - final SyncGroup s = prepareSyncSet(listener, name, method); + int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name) { + final SyncGroup s = prepareSyncSet(listener, name); startSyncSet(s, timeoutMs); return s.mSyncId; } @@ -334,6 +332,15 @@ class BLASTSyncEngine { getSyncGroup(id).addToSync(wc); } + void setSyncMethod(int id, int method) { + final SyncGroup syncGroup = getSyncGroup(id); + if (!syncGroup.mRootMembers.isEmpty()) { + throw new IllegalStateException( + "Not allow to change sync method after adding group member, id=" + id); + } + syncGroup.mSyncMethod = method; + } + void setReady(int id, boolean ready) { getSyncGroup(id).setReady(ready); } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index f2e4937aabbf..606f011ae55c 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -369,7 +369,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return mState; } - @VisibleForTesting int getSyncId() { return mSyncId; } @@ -409,18 +408,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return mState == STATE_FINISHED; } - @VisibleForTesting - void startCollecting(long timeoutMs) { - startCollecting(timeoutMs, TransitionController.SYNC_METHOD); - } - /** Starts collecting phase. Once this starts, all relevant surface operations are sync. */ - void startCollecting(long timeoutMs, int method) { + void startCollecting(long timeoutMs) { if (mState != STATE_PENDING) { throw new IllegalStateException("Attempting to re-use a transition"); } mState = STATE_COLLECTING; - mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG, method); + mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG); + mSyncEngine.setSyncMethod(mSyncId, TransitionController.SYNC_METHOD); mLogger.mSyncId = mSyncId; mLogger.mCollectTimeNs = SystemClock.elapsedRealtimeNanos(); diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 6c951bfc5f9a..bacc6e615ed1 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -51,7 +51,6 @@ import android.window.TransitionRequestInfo; import android.window.WindowContainerTransaction; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLogGroup; import com.android.internal.protolog.common.ProtoLog; import com.android.server.FgThread; @@ -200,12 +199,6 @@ class TransitionController { /** Starts Collecting */ void moveToCollecting(@NonNull Transition transition) { - moveToCollecting(transition, SYNC_METHOD); - } - - /** Starts Collecting */ - @VisibleForTesting - void moveToCollecting(@NonNull Transition transition, int method) { if (mCollectingTransition != null) { throw new IllegalStateException("Simultaneous transition collection not supported."); } @@ -219,7 +212,7 @@ class TransitionController { // Distinguish change type because the response time is usually expected to be not too long. final long timeoutMs = transition.mType == TRANSIT_CHANGE ? CHANGE_TIMEOUT_MS : DEFAULT_TIMEOUT_MS; - mCollectingTransition.startCollecting(timeoutMs, method); + mCollectingTransition.startCollecting(timeoutMs); ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Start collecting in Transition: %s", mCollectingTransition); dispatchLegacyAppTransitionPending(); @@ -492,6 +485,15 @@ class TransitionController { } else { newTransition = requestStartTransition(createTransition(type, flags), trigger != null ? trigger.asTask() : null, remoteTransition, displayChange); + if (newTransition != null && displayChange != null && (displayChange.getStartRotation() + + displayChange.getEndRotation()) % 2 == 0) { + // 180 degrees rotation change may not change screen size. So the clients may draw + // some frames before and after the display projection transaction is applied by the + // remote player. That may cause some buffers to show in different rotation. So use + // sync method to pause clients drawing until the projection transaction is applied. + mAtm.mWindowManager.mSyncEngine.setSyncMethod(newTransition.getSyncId(), + BLASTSyncEngine.METHOD_BLAST); + } } if (trigger != null) { if (isExistenceType(type)) { diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 495d7ce4e90b..c3c87af51b15 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -1648,7 +1648,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub private BLASTSyncEngine.SyncGroup prepareSyncWithOrganizer( IWindowContainerTransactionCallback callback) { final BLASTSyncEngine.SyncGroup s = mService.mWindowManager.mSyncEngine - .prepareSyncSet(this, "", BLASTSyncEngine.METHOD_BLAST); + .prepareSyncSet(this, "Organizer"); mTransactionCallbacksByPendingSyncId.put(s.mSyncId, callback); return s; } diff --git a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java index aff9c1a9372a..8e91ca28fcf1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java @@ -22,7 +22,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static com.android.server.wm.BLASTSyncEngine.METHOD_BLAST; import static com.android.server.wm.BLASTSyncEngine.METHOD_NONE; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; import static com.android.server.wm.WindowContainer.POSITION_TOP; @@ -363,7 +362,8 @@ public class SyncEngineTests extends WindowTestsBase { BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); - int id = startSyncSet(bse, listener, METHOD_NONE); + final int id = startSyncSet(bse, listener); + bse.setSyncMethod(id, METHOD_NONE); bse.addToSyncSet(id, mAppWindow.mToken); mAppWindow.prepareSync(); assertFalse(mAppWindow.shouldSyncWithBuffers()); @@ -373,12 +373,7 @@ public class SyncEngineTests extends WindowTestsBase { static int startSyncSet(BLASTSyncEngine engine, BLASTSyncEngine.TransactionReadyListener listener) { - return startSyncSet(engine, listener, METHOD_BLAST); - } - - static int startSyncSet(BLASTSyncEngine engine, - BLASTSyncEngine.TransactionReadyListener listener, int method) { - return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "", method); + return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "Test"); } static class TestWindowContainer extends WindowContainer { diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 048e2ccc82b4..debfc841e52d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -1704,7 +1704,8 @@ public class TransitionTests extends WindowTestsBase { mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); final Transition transition = new Transition(TRANSIT_OPEN, 0 /* flags */, app.mTransitionController, mWm.mSyncEngine); - app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE); + app.mTransitionController.moveToCollecting(transition); + mWm.mSyncEngine.setSyncMethod(transition.getSyncId(), BLASTSyncEngine.METHOD_NONE); final ArrayList<WindowContainer> freezeCalls = new ArrayList<>(); transition.setContainerFreezer(new Transition.IContainerFreezer() { @Override @@ -1755,7 +1756,8 @@ public class TransitionTests extends WindowTestsBase { mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */, app.mTransitionController, mWm.mSyncEngine); - app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE); + app.mTransitionController.moveToCollecting(transition); + mWm.mSyncEngine.setSyncMethod(transition.getSyncId(), BLASTSyncEngine.METHOD_NONE); final SurfaceControl mockSnapshot = mock(SurfaceControl.class); transition.setContainerFreezer(new Transition.IContainerFreezer() { @Override diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index d7e4c5523eee..a68a573079a3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -42,7 +42,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static com.android.server.wm.ActivityRecord.State.RESUMED; -import static com.android.server.wm.BLASTSyncEngine.METHOD_BLAST; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowContainer.SYNC_STATE_READY; import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION; @@ -1001,7 +1000,7 @@ public class WindowOrganizerTests extends WindowTestsBase { BLASTSyncEngine.TransactionReadyListener transactionListener = mock(BLASTSyncEngine.TransactionReadyListener.class); - int id = bse.startSyncSet(transactionListener, BLAST_TIMEOUT_DURATION, "", METHOD_BLAST); + final int id = bse.startSyncSet(transactionListener, BLAST_TIMEOUT_DURATION, "Test"); bse.addToSyncSet(id, task); bse.setReady(id); bse.onSurfacePlacement(); |