summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Winson Chung <winsonc@google.com> 2022-08-04 22:43:36 +0000
committer Winson Chung <winsonc@google.com> 2022-08-05 20:58:44 +0000
commit8564942f36064b630b5f358becb17a16f95653e6 (patch)
tree53c329c1517d702f38de19aeb54fbc01fbeda39d
parent9c2b0e1cf07324747b0ac56d91e608b73bab57b2 (diff)
Add some client side logging for interrupted draws to the dump
In particular, these are to try and narrow down why the app window isn't drawing in b/235463625 where the draw state for launcher is stuck in DRAW_PENDING. - mLastReportNextDrawReason: the reason the last draw was requested, maybe useful in telling if wm is not requesting a draw if not set - mLastPerformTraversalsSkipDrawReason: the reason perform traversals returned without drawing (includes wm/predraw cancel reasons) - mLastPerformDrawSkippedReason: the reason perform draw returned without drawing - mLocalSyncState: extra logging to confirm that the last sync actually completes Bug: 235463625 Test: dumpsys -T 60000 activity -v all Test: dumpsys activity activities Change-Id: I10118470fe62075920e9ce29fe449b0cfc8570c9
-rw-r--r--core/java/android/view/SurfaceControlViewHost.java2
-rw-r--r--core/java/android/view/ViewRootImpl.java69
-rw-r--r--core/java/android/view/ViewTreeObserver.java19
3 files changed, 79 insertions, 11 deletions
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index d75ff2fc7dc2..5721fa6dd11a 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -422,7 +422,7 @@ public class SurfaceControlViewHost {
public void relayout(WindowManager.LayoutParams attrs,
WindowlessWindowManager.ResizeCompleteCallback callback) {
mViewRoot.setLayoutParams(attrs, false);
- mViewRoot.setReportNextDraw(true /* syncBuffer */);
+ mViewRoot.setReportNextDraw(true /* syncBuffer */, "scvh_relayout");
mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e1966a0f1177..4d094ffd287f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -587,8 +587,21 @@ public final class ViewRootImpl implements ViewParent,
int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED;
boolean mPerformContentCapture;
-
boolean mReportNextDraw;
+ /** Set only while mReportNextDraw=true, indicating the last reason that was triggered */
+ String mLastReportNextDrawReason;
+ /** The reaason the last call to performDraw() returned false */
+ String mLastPerformDrawSkippedReason;
+ /** The reason the last call to performTraversals() returned without drawing */
+ String mLastPerformTraversalsSkipDrawReason;
+ /** The state of the local sync, if one is in progress. Can be one of the states below. */
+ int mLocalSyncState;
+
+ // The possible states of the local sync, see createSyncIfNeeded()
+ private final int LOCAL_SYNC_NONE = 0;
+ private final int LOCAL_SYNC_PENDING = 1;
+ private final int LOCAL_SYNC_RETURNED = 2;
+ private final int LOCAL_SYNC_MERGED = 3;
/**
* Set whether the draw should send the buffer to system server. When set to true, VRI will
@@ -1836,7 +1849,7 @@ public final class ViewRootImpl implements ViewParent,
mSyncSeqId = args.argi4 > mSyncSeqId ? args.argi4 : mSyncSeqId;
if (msg == MSG_RESIZED_REPORT) {
- reportNextDraw();
+ reportNextDraw("resized");
}
if (mView != null && (frameChanged || configChanged)) {
@@ -2741,6 +2754,8 @@ public final class ViewRootImpl implements ViewParent,
}
private void performTraversals() {
+ mLastPerformTraversalsSkipDrawReason = null;
+
// cache mView since it is used so much below...
final View host = mView;
if (DBG) {
@@ -2750,12 +2765,14 @@ public final class ViewRootImpl implements ViewParent,
}
if (host == null || !mAdded) {
+ mLastPerformTraversalsSkipDrawReason = host == null ? "no_host" : "not_added";
return;
}
mIsInTraversal = true;
mWillDrawSoon = true;
boolean cancelDraw = false;
+ String cancelReason = null;
boolean isSyncRequest = false;
boolean windowSizeMayChange = false;
@@ -3038,13 +3055,14 @@ public final class ViewRootImpl implements ViewParent,
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
cancelDraw = (relayoutResult & RELAYOUT_RES_CANCEL_AND_REDRAW)
== RELAYOUT_RES_CANCEL_AND_REDRAW;
+ cancelReason = "relayout";
final boolean dragResizing = mPendingDragResizing;
if (mSyncSeqId > mLastSyncSeqId) {
mLastSyncSeqId = mSyncSeqId;
if (DEBUG_BLAST) {
Log.d(mTag, "Relayout called with blastSync");
}
- reportNextDraw();
+ reportNextDraw("relayout");
mSyncBuffer = true;
isSyncRequest = true;
if (!cancelDraw) {
@@ -3147,6 +3165,7 @@ public final class ViewRootImpl implements ViewParent,
}
} catch (OutOfResourcesException e) {
handleOutOfResourcesException(e);
+ mLastPerformTraversalsSkipDrawReason = "oom_initialize_renderer";
return;
}
}
@@ -3184,6 +3203,7 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
} catch (OutOfResourcesException e) {
handleOutOfResourcesException(e);
+ mLastPerformTraversalsSkipDrawReason = "oom_update_surface";
return;
}
}
@@ -3349,6 +3369,7 @@ public final class ViewRootImpl implements ViewParent,
if (mCheckIfCanDraw) {
try {
cancelDraw = mWindowSession.cancelDraw(mWindow);
+ cancelReason = "wm_sync";
if (DEBUG_BLAST) {
Log.d(mTag, "cancelDraw returned " + cancelDraw);
}
@@ -3571,19 +3592,21 @@ public final class ViewRootImpl implements ViewParent,
mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
- reportNextDraw();
+ reportNextDraw("first_relayout");
}
mCheckIfCanDraw = isSyncRequest || cancelDraw;
- boolean cancelAndRedraw =
- mAttachInfo.mTreeObserver.dispatchOnPreDraw() || (cancelDraw && mDrewOnceForSync);
+ boolean cancelDueToPreDrawListener = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
+ boolean cancelAndRedraw = cancelDueToPreDrawListener
+ || (cancelDraw && mDrewOnceForSync);
if (!cancelAndRedraw) {
createSyncIfNeeded();
mDrewOnceForSync = true;
}
if (!isViewVisible) {
+ mLastPerformTraversalsSkipDrawReason = "view_not_visible";
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).endChangingAnimations();
@@ -3595,6 +3618,9 @@ public final class ViewRootImpl implements ViewParent,
mSyncBufferCallback.onBufferReady(null);
}
} else if (cancelAndRedraw) {
+ mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
+ ? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason()
+ : "cancel_" + cancelReason;
// Try again
scheduleTraversals();
} else {
@@ -3618,11 +3644,13 @@ public final class ViewRootImpl implements ViewParent,
if (!cancelAndRedraw) {
mReportNextDraw = false;
+ mLastReportNextDrawReason = null;
mSyncBufferCallback = null;
mSyncBuffer = false;
if (isInLocalSync()) {
mSyncGroup.markSyncReady();
mSyncGroup = null;
+ mLocalSyncState = LOCAL_SYNC_NONE;
}
}
}
@@ -3634,12 +3662,15 @@ public final class ViewRootImpl implements ViewParent,
}
final int seqId = mSyncSeqId;
+ mLocalSyncState = LOCAL_SYNC_PENDING;
mSyncGroup = new SurfaceSyncGroup(transaction -> {
+ mLocalSyncState = LOCAL_SYNC_RETURNED;
// Callback will be invoked on executor thread so post to main thread.
mHandler.postAtFrontOfQueue(() -> {
if (transaction != null) {
mSurfaceChangedTransaction.merge(transaction);
}
+ mLocalSyncState = LOCAL_SYNC_MERGED;
reportDrawFinished(seqId);
});
});
@@ -4353,9 +4384,12 @@ public final class ViewRootImpl implements ViewParent,
}
private boolean performDraw() {
+ mLastPerformDrawSkippedReason = null;
if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
+ mLastPerformDrawSkippedReason = "screen_off";
return false;
} else if (mView == null) {
+ mLastPerformDrawSkippedReason = "no_root_view";
return false;
}
@@ -8458,6 +8492,21 @@ public final class ViewRootImpl implements ViewParent,
if (mTraversalScheduled) {
writer.println(innerPrefix + " (barrier=" + mTraversalBarrier + ")");
}
+ writer.println(innerPrefix + "mReportNextDraw=" + mReportNextDraw);
+ if (mReportNextDraw) {
+ writer.println(innerPrefix + " (reason=" + mLastReportNextDrawReason + ")");
+ }
+ if (mLastPerformTraversalsSkipDrawReason != null) {
+ writer.println(innerPrefix + "mLastPerformTraversalsFailedReason="
+ + mLastPerformTraversalsSkipDrawReason);
+ }
+ if (mLastPerformDrawSkippedReason != null) {
+ writer.println(innerPrefix + "mLastPerformDrawFailedReason="
+ + mLastPerformDrawSkippedReason);
+ }
+ if (mLocalSyncState != LOCAL_SYNC_NONE) {
+ writer.println(innerPrefix + "mLocalSyncState=" + mLocalSyncState);
+ }
writer.println(innerPrefix + "mIsAmbientMode=" + mIsAmbientMode);
writer.println(innerPrefix + "mUnbufferedInputSource="
+ Integer.toHexString(mUnbufferedInputSource));
@@ -9958,11 +10007,12 @@ public final class ViewRootImpl implements ViewParent,
}
}
- private void reportNextDraw() {
+ private void reportNextDraw(String reason) {
if (DEBUG_BLAST) {
Log.d(mTag, "reportNextDraw " + Debug.getCallers(5));
}
mReportNextDraw = true;
+ mLastReportNextDrawReason = reason;
}
/**
@@ -9975,11 +10025,12 @@ public final class ViewRootImpl implements ViewParent,
* @param syncBuffer If true, the transaction that contains the buffer from the draw should be
* sent to system to be synced. If false, VRI will not try to sync the buffer,
* but only report back that a buffer was drawn.
+ * @param reason A debug string indicating the reason for reporting the next draw
* @hide
*/
- public void setReportNextDraw(boolean syncBuffer) {
+ public void setReportNextDraw(boolean syncBuffer, String reason) {
mSyncBuffer = syncBuffer;
- reportNextDraw();
+ reportNextDraw(reason);
invalidate();
}
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 2c077c3e9e63..c9526fde27df 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -74,6 +74,9 @@ public final class ViewTreeObserver {
* that the listener will be immediately called. */
private boolean mWindowShown;
+ // The reason that the last call to dispatchOnPreDraw() returned true to cancel and redraw
+ private String mLastDispatchOnPreDrawCanceledReason;
+
private boolean mAlive = true;
/**
@@ -1161,6 +1164,7 @@ public final class ViewTreeObserver {
*/
@SuppressWarnings("unchecked")
public final boolean dispatchOnPreDraw() {
+ mLastDispatchOnPreDrawCanceledReason = null;
boolean cancelDraw = false;
final CopyOnWriteArray<OnPreDrawListener> listeners = mOnPreDrawListeners;
if (listeners != null && listeners.size() > 0) {
@@ -1168,7 +1172,11 @@ public final class ViewTreeObserver {
try {
int count = access.size();
for (int i = 0; i < count; i++) {
- cancelDraw |= !(access.get(i).onPreDraw());
+ final OnPreDrawListener preDrawListener = access.get(i);
+ cancelDraw |= !(preDrawListener.onPreDraw());
+ if (cancelDraw) {
+ mLastDispatchOnPreDrawCanceledReason = preDrawListener.getClass().getName();
+ }
}
} finally {
listeners.end();
@@ -1178,6 +1186,15 @@ public final class ViewTreeObserver {
}
/**
+ * @return the reason that the last call to dispatchOnPreDraw() returned true to cancel the
+ * current draw, or null if the last call did not cancel.
+ * @hide
+ */
+ final String getLastDispatchOnPreDrawCanceledReason() {
+ return mLastDispatchOnPreDrawCanceledReason;
+ }
+
+ /**
* Notifies registered listeners that the window is now shown
* @hide
*/