From d390deb8f564b9aeab0257dfefd8a051d8a57f7f Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Thu, 22 Jun 2017 13:14:28 -0700 Subject: [PATCH] Ensure all WindowStates are considered before determining all drawn. The drawn state of an AppWindowToken is calculated on demand in updateAllDrawn. updateAllDrawn assumes that updateDrawnWindowStates has been called on every child window beforehand. If a window has been added but not had updateDrawnWindowStates called for it, the results of updateAllDrawn will be wrong. This leads to situations where we will determine we are ready to execute a transition to home, yet not have a wallpaper activity. This changelist addresses this issue by recording which WindowStates have had updateDrawnWindowStates called on them and making sure all present children have been processed in updateAllDrawn. Bug: 62846907 Test: go/wm-smoke Test: turn launcher rotation on, open dialer in portrait, turn off screen, rotate to landscape, unlock with fingerprint, press home while rotating. make sure transition is correct. Change-Id: I3d129e686326d868862ae988725fb091a2c86e4e --- .../com/android/server/wm/AppWindowToken.java | 29 +++++++++++++++++-- .../com/android/server/wm/WindowState.java | 28 ++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 8afc4fd6a8df6..d01c8b9ec2260 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -1342,6 +1342,24 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } } + /** + * Returns whether the drawn window states of this {@link AppWindowToken} has considered every + * child {@link WindowState}. A child is considered if it has been passed into + * {@link #updateDrawnWindowStates(WindowState)} after being added. This is used to determine + * whether states, such as {@code allDrawn}, can be set, which relies on state variables such as + * {@code mNumInterestingWindows}, which depend on all {@link WindowState}s being considered. + * + * @return {@code true} If all children have been considered, {@code false}. + */ + private boolean allDrawnStatesConsidered() { + for (WindowState child : mChildren) { + if (!child.getDrawnStatedEvaluated()) { + return false; + } + } + return true; + } + /** * Determines if the token has finished drawing. This should only be called from * {@link DisplayContent#applySurfaceChangesTransaction} @@ -1349,9 +1367,14 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree void updateAllDrawn() { if (!allDrawn) { // Number of drawn windows can be less when a window is being relaunched, wait for - // all windows to be launched and drawn for this token be considered all drawn + // all windows to be launched and drawn for this token be considered all drawn. final int numInteresting = mNumInterestingWindows; - if (numInteresting > 0 && mNumDrawnWindows >= numInteresting && !isRelaunching()) { + + // We must make sure that all present children have been considered (determined by + // {@link #allDrawnStatesConsidered}) before evaluating whether everything has been + // drawn. + if (numInteresting > 0 && allDrawnStatesConsidered() + && mNumDrawnWindows >= numInteresting && !isRelaunching()) { if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows); allDrawn = true; @@ -1396,6 +1419,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree * windows in this app token where not considered drawn as of the last pass. */ boolean updateDrawnWindowStates(WindowState w) { + w.setDrawnStateEvaluated(true /*evaluated*/); + if (DEBUG_STARTING_WINDOW_VERBOSE && w == startingWindow) { Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen() + " allDrawn=" + allDrawn + " freezingScreen=" + mAppAnimator.freezingScreen); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index f74948f8e7f06..769fe67e200e9 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -559,6 +559,13 @@ class WindowState extends WindowContainer implements WindowManagerP */ final Rect mLastSurfaceInsets = new Rect(); + /** + * A flag set by the {@link WindowState} parent to indicate that the parent has examined this + * {@link WindowState} in its overall drawing context. This book-keeping allows the parent to + * make sure all children have been considered. + */ + private boolean mDrawnStateEvaluated; + /** * Compares two window sub-layers and returns -1 if the first is lesser than the second in terms * of z-order and 1 otherwise. @@ -675,6 +682,27 @@ class WindowState extends WindowContainer implements WindowManagerP mSession.windowAddedLocked(mAttrs.packageName); } + /** + * Returns whether this {@link WindowState} has been considered for drawing by its parent. + */ + boolean getDrawnStatedEvaluated() { + return mDrawnStateEvaluated; + } + + /** + * Sets whether this {@link WindowState} has been considered for drawing by its parent. Should + * be cleared when detached from parent. + */ + void setDrawnStateEvaluated(boolean evaluated) { + mDrawnStateEvaluated = evaluated; + } + + @Override + void onParentSet() { + super.onParentSet(); + setDrawnStateEvaluated(false /*evaluated*/); + } + @Override public int getOwningUid() { return mOwnerUid;