Loading services/core/java/com/android/server/wm/AsyncRotationController.java +22 −11 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); } } Loading Loading @@ -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; } Loading Loading @@ -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; } Loading Loading @@ -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) Loading @@ -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; } } } services/core/java/com/android/server/wm/BLASTSyncEngine.java +15 −8 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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"); Loading Loading @@ -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; } Loading Loading @@ -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); } Loading services/core/java/com/android/server/wm/Transition.java +3 −8 Original line number Diff line number Diff line Loading @@ -369,7 +369,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return mState; } @VisibleForTesting int getSyncId() { return mSyncId; } Loading Loading @@ -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(); Loading services/core/java/com/android/server/wm/TransitionController.java +10 −8 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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."); } Loading @@ -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(); Loading Loading @@ -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)) { Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +1 −1 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading
services/core/java/com/android/server/wm/AsyncRotationController.java +22 −11 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); } } Loading Loading @@ -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; } Loading Loading @@ -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; } Loading Loading @@ -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) Loading @@ -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; } } }
services/core/java/com/android/server/wm/BLASTSyncEngine.java +15 −8 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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"); Loading Loading @@ -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; } Loading Loading @@ -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); } Loading
services/core/java/com/android/server/wm/Transition.java +3 −8 Original line number Diff line number Diff line Loading @@ -369,7 +369,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return mState; } @VisibleForTesting int getSyncId() { return mSyncId; } Loading Loading @@ -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(); Loading
services/core/java/com/android/server/wm/TransitionController.java +10 −8 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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."); } Loading @@ -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(); Loading Loading @@ -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)) { Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +1 −1 Original line number Diff line number Diff line Loading @@ -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; } Loading