diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 79abf25d4f7e8..e325d6fffe817 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2602,7 +2602,7 @@ public class WindowManagerService extends IWindowManager.Stub void repositionChild(Session session, IWindow client, int left, int top, int right, int bottom, - long deferTransactionUntilFrame, Rect outFrame) { + long frameNumber, Rect outFrame) { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "repositionChild"); long origId = Binder.clearCallingIdentity(); @@ -2638,10 +2638,8 @@ public class WindowManagerService extends IWindowManager.Stub win.mWinAnimator.setSurfaceBoundariesLocked(false); - if (deferTransactionUntilFrame > 0) { - win.mWinAnimator.mSurfaceController.deferTransactionUntil( - win.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(), - deferTransactionUntilFrame); + if (frameNumber > 0) { + win.mWinAnimator.deferTransactionUntilParentFrame(frameNumber); } } finally { diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 0245513401667..329cbbdd38f65 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -220,6 +220,10 @@ class WindowStateAnimator { int mAttrType; + static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100; + long mDeferTransactionUntilFrame = -1; + long mDeferTransactionTime = -1; + private final Rect mTmpSize = new Rect(); WindowStateAnimator(final WindowState win) { @@ -1880,4 +1884,36 @@ class WindowStateAnimator { mAnimDy = mWin.mLastFrame.top - top; mAnimateMove = true; } + + void deferTransactionUntilParentFrame(long frameNumber) { + if (!mWin.isChildWindow()) { + return; + } + mDeferTransactionUntilFrame = frameNumber; + mDeferTransactionTime = System.currentTimeMillis(); + mSurfaceController.deferTransactionUntil( + mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(), + frameNumber); + } + + // Defer the current transaction to the frame number of the last saved transaction. + // We do this to avoid shooting through an unsynchronized transaction while something is + // pending. This is generally fine, as either we will get in on the synchronization, + // or SurfaceFlinger will see that the frame has already occured. The only + // potential problem is in frame number resets so we reset things with a timeout + // every so often to be careful. + void deferToPendingTransaction() { + if (mDeferTransactionUntilFrame < 0) { + return; + } + long time = System.currentTimeMillis(); + if (time > mDeferTransactionTime + PENDING_TRANSACTION_FINISH_WAIT_TIME) { + mDeferTransactionTime = -1; + mDeferTransactionUntilFrame = -1; + } else { + mSurfaceController.deferTransactionUntil( + mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(), + mDeferTransactionUntilFrame); + } + } } diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index 04aa735bc99d4..1e6c585da12de 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -721,6 +721,10 @@ class WindowSurfacePlacer { // Moved from updateWindowsAndWallpaperLocked(). if (w.mHasSurface) { + // If we have recently synchronized a previous transaction for this + // window ensure we don't push through an unsynchronized one now. + winAnimator.deferToPendingTransaction(); + // Take care of the window being ready to display. final boolean committed = winAnimator.commitFinishDrawingLocked(); if (isDefaultDisplay && committed) {