diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 6c93f81f611b4..62093a0cbad3b 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -371,6 +371,14 @@ class WindowState extends WindowContainer implements WindowManagerP private int mResizeMode; private boolean mRedrawForSyncReported; + /** + * {@code true} when the client was still drawing for sync when the sync-set was finished or + * cancelled. This can happen if the window goes away during a sync. In this situation we need + * to make sure to still apply the postDrawTransaction when it finishes to prevent the client + * from getting stuck in a bad state. + */ + boolean mClientWasDrawingForSync = false; + /** * Special mode that is intended only for the rounded corner overlay: during rotation * transition, we un-rotate the window token such that the window appears as it did before the @@ -6009,6 +6017,14 @@ class WindowState extends WindowContainer implements WindowManagerP return super.isSyncFinished(); } + @Override + void finishSync(Transaction outMergedTransaction, boolean cancel) { + if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mRedrawForSyncReported) { + mClientWasDrawingForSync = true; + } + super.finishSync(outMergedTransaction, cancel); + } + boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction) { if (mOrientationChangeRedrawRequestTime > 0) { final long duration = @@ -6024,8 +6040,11 @@ class WindowState extends WindowContainer implements WindowManagerP } executeDrawHandlers(postDrawTransaction); + + final boolean applyPostDrawNow = mClientWasDrawingForSync && postDrawTransaction != null; + mClientWasDrawingForSync = false; if (!onSyncFinishedDrawing()) { - return mWinAnimator.finishDrawingLocked(postDrawTransaction); + return mWinAnimator.finishDrawingLocked(postDrawTransaction, applyPostDrawNow); } if (mActivityRecord != null @@ -6039,7 +6058,7 @@ class WindowState extends WindowContainer implements WindowManagerP mSyncTransaction.merge(postDrawTransaction); } - mWinAnimator.finishDrawingLocked(null); + mWinAnimator.finishDrawingLocked(null, false /* forceApplyNow */); // We always want to force a traversal after a finish draw for blast sync. return true; } diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 81f06d9cbaca0..0e110b6074eca 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -228,7 +228,8 @@ class WindowStateAnimator { } } - boolean finishDrawingLocked(SurfaceControl.Transaction postDrawTransaction) { + boolean finishDrawingLocked(SurfaceControl.Transaction postDrawTransaction, + boolean forceApplyNow) { final boolean startingWindow = mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; if (startingWindow) { @@ -253,11 +254,11 @@ class WindowStateAnimator { // If there is no surface, the last draw was for the previous surface. We don't want to // wait until the new surface is shown and instead just apply the transaction right // away. - if (mLastHidden && mDrawState != NO_SURFACE) { + if (mLastHidden && mDrawState != NO_SURFACE && !forceApplyNow) { mPostDrawTransaction.merge(postDrawTransaction); layoutNeeded = true; } else { - postDrawTransaction.apply(); + mWin.getSyncTransaction().merge(postDrawTransaction); } }