Always apply postDrawTransaction started during sync

ViewRootImpl tracks the full lifetime of all sync buffers.
This means its important to apply all transactions which have
a sync buffer or ViewRootImpl will not draw new frames.

This CL makes it so that even if a window is no-longer in a
sync-set, the post-draw transaction will be applied as long
as it was in a sync transaction at the time it was requested.

Bug: 183993924
Test: atest WindowUntrustedTouchTest
Change-Id: Id89d039328bd9b091d4ed78a1616bc78d1bd83fa
This commit is contained in:
Evan Rosky
2021-08-24 15:22:09 -07:00
parent e7b6834733
commit 2ff244d199
2 changed files with 25 additions and 5 deletions

View File

@@ -371,6 +371,14 @@ class WindowState extends WindowContainer<WindowState> 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<WindowState> 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<WindowState> 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<WindowState> 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;
}

View File

@@ -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);
}
}