Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32e2b596 authored by Winson Chung's avatar Winson Chung
Browse files

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
Merged-In: I10118470fe62075920e9ce29fe449b0cfc8570c9
parent a745ebf3
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -422,7 +422,7 @@ public class SurfaceControlViewHost {
    public void relayout(WindowManager.LayoutParams attrs,
    public void relayout(WindowManager.LayoutParams attrs,
            WindowlessWindowManager.ResizeCompleteCallback callback) {
            WindowlessWindowManager.ResizeCompleteCallback callback) {
        mViewRoot.setLayoutParams(attrs, false);
        mViewRoot.setLayoutParams(attrs, false);
        mViewRoot.setReportNextDraw(true /* syncBuffer */);
        mViewRoot.setReportNextDraw(true /* syncBuffer */, "scvh_relayout");
        mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback);
        mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback);
    }
    }


+60 −9
Original line number Original line Diff line number Diff line
@@ -586,8 +586,21 @@ public final class ViewRootImpl implements ViewParent,
    int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED;
    int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED;
    boolean mPerformContentCapture;
    boolean mPerformContentCapture;



    boolean mReportNextDraw;
    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
     * Set whether the draw should send the buffer to system server. When set to true, VRI will
@@ -1811,7 +1824,7 @@ public final class ViewRootImpl implements ViewParent,
        mSyncSeqId = args.argi4 > mSyncSeqId ? args.argi4 : mSyncSeqId;
        mSyncSeqId = args.argi4 > mSyncSeqId ? args.argi4 : mSyncSeqId;


        if (msg == MSG_RESIZED_REPORT) {
        if (msg == MSG_RESIZED_REPORT) {
            reportNextDraw();
            reportNextDraw("resized");
        }
        }


        if (mView != null && (frameChanged || configChanged)) {
        if (mView != null && (frameChanged || configChanged)) {
@@ -2716,6 +2729,8 @@ public final class ViewRootImpl implements ViewParent,
    }
    }


    private void performTraversals() {
    private void performTraversals() {
        mLastPerformTraversalsSkipDrawReason = null;

        // cache mView since it is used so much below...
        // cache mView since it is used so much below...
        final View host = mView;
        final View host = mView;
        if (DBG) {
        if (DBG) {
@@ -2725,12 +2740,14 @@ public final class ViewRootImpl implements ViewParent,
        }
        }


        if (host == null || !mAdded) {
        if (host == null || !mAdded) {
            mLastPerformTraversalsSkipDrawReason = host == null ? "no_host" : "not_added";
            return;
            return;
        }
        }


        mIsInTraversal = true;
        mIsInTraversal = true;
        mWillDrawSoon = true;
        mWillDrawSoon = true;
        boolean cancelDraw = false;
        boolean cancelDraw = false;
        String cancelReason = null;
        boolean isSyncRequest = false;
        boolean isSyncRequest = false;


        boolean windowSizeMayChange = false;
        boolean windowSizeMayChange = false;
@@ -3013,13 +3030,14 @@ public final class ViewRootImpl implements ViewParent,
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
                cancelDraw = (relayoutResult & RELAYOUT_RES_CANCEL_AND_REDRAW)
                cancelDraw = (relayoutResult & RELAYOUT_RES_CANCEL_AND_REDRAW)
                        == RELAYOUT_RES_CANCEL_AND_REDRAW;
                        == RELAYOUT_RES_CANCEL_AND_REDRAW;
                cancelReason = "relayout";
                final boolean dragResizing = mPendingDragResizing;
                final boolean dragResizing = mPendingDragResizing;
                if (mSyncSeqId > mLastSyncSeqId) {
                if (mSyncSeqId > mLastSyncSeqId) {
                    mLastSyncSeqId = mSyncSeqId;
                    mLastSyncSeqId = mSyncSeqId;
                    if (DEBUG_BLAST) {
                    if (DEBUG_BLAST) {
                        Log.d(mTag, "Relayout called with blastSync");
                        Log.d(mTag, "Relayout called with blastSync");
                    }
                    }
                    reportNextDraw();
                    reportNextDraw("relayout");
                    mSyncBuffer = true;
                    mSyncBuffer = true;
                    isSyncRequest = true;
                    isSyncRequest = true;
                    if (!cancelDraw) {
                    if (!cancelDraw) {
@@ -3117,6 +3135,7 @@ public final class ViewRootImpl implements ViewParent,
                            }
                            }
                        } catch (OutOfResourcesException e) {
                        } catch (OutOfResourcesException e) {
                            handleOutOfResourcesException(e);
                            handleOutOfResourcesException(e);
                            mLastPerformTraversalsSkipDrawReason = "oom_initialize_renderer";
                            return;
                            return;
                        }
                        }
                    }
                    }
@@ -3154,6 +3173,7 @@ public final class ViewRootImpl implements ViewParent,
                        mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
                        mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
                    } catch (OutOfResourcesException e) {
                    } catch (OutOfResourcesException e) {
                        handleOutOfResourcesException(e);
                        handleOutOfResourcesException(e);
                        mLastPerformTraversalsSkipDrawReason = "oom_update_surface";
                        return;
                        return;
                    }
                    }
                }
                }
@@ -3319,6 +3339,7 @@ public final class ViewRootImpl implements ViewParent,
            if (mCheckIfCanDraw) {
            if (mCheckIfCanDraw) {
                try {
                try {
                    cancelDraw = mWindowSession.cancelDraw(mWindow);
                    cancelDraw = mWindowSession.cancelDraw(mWindow);
                    cancelReason = "wm_sync";
                    if (DEBUG_BLAST) {
                    if (DEBUG_BLAST) {
                        Log.d(mTag, "cancelDraw returned " + cancelDraw);
                        Log.d(mTag, "cancelDraw returned " + cancelDraw);
                    }
                    }
@@ -3541,19 +3562,21 @@ public final class ViewRootImpl implements ViewParent,
        mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
        mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);


        if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
        if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
            reportNextDraw();
            reportNextDraw("first_relayout");
        }
        }


        mCheckIfCanDraw = isSyncRequest || cancelDraw;
        mCheckIfCanDraw = isSyncRequest || cancelDraw;


        boolean cancelAndRedraw =
        boolean cancelDueToPreDrawListener = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
                mAttachInfo.mTreeObserver.dispatchOnPreDraw() || (cancelDraw && mDrewOnceForSync);
        boolean cancelAndRedraw = cancelDueToPreDrawListener
                 || (cancelDraw && mDrewOnceForSync);
        if (!cancelAndRedraw) {
        if (!cancelAndRedraw) {
            createSyncIfNeeded();
            createSyncIfNeeded();
            mDrewOnceForSync = true;
            mDrewOnceForSync = true;
        }
        }


        if (!isViewVisible) {
        if (!isViewVisible) {
            mLastPerformTraversalsSkipDrawReason = "view_not_visible";
            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).endChangingAnimations();
                    mPendingTransitions.get(i).endChangingAnimations();
@@ -3565,6 +3588,9 @@ public final class ViewRootImpl implements ViewParent,
                mSyncBufferCallback.onBufferReady(null);
                mSyncBufferCallback.onBufferReady(null);
            }
            }
        } else if (cancelAndRedraw) {
        } else if (cancelAndRedraw) {
            mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
                ? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason()
                : "cancel_" + cancelReason;
            // Try again
            // Try again
            scheduleTraversals();
            scheduleTraversals();
        } else {
        } else {
@@ -3588,11 +3614,13 @@ public final class ViewRootImpl implements ViewParent,


        if (!cancelAndRedraw) {
        if (!cancelAndRedraw) {
            mReportNextDraw = false;
            mReportNextDraw = false;
            mLastReportNextDrawReason = null;
            mSyncBufferCallback = null;
            mSyncBufferCallback = null;
            mSyncBuffer = false;
            mSyncBuffer = false;
            if (isInLocalSync()) {
            if (isInLocalSync()) {
                mSurfaceSyncer.markSyncReady(mSyncId);
                mSurfaceSyncer.markSyncReady(mSyncId);
                mSyncId = UNSET_SYNC_ID;
                mSyncId = UNSET_SYNC_ID;
                mLocalSyncState = LOCAL_SYNC_NONE;
            }
            }
        }
        }
    }
    }
@@ -3604,9 +3632,12 @@ public final class ViewRootImpl implements ViewParent,
        }
        }


        final int seqId = mSyncSeqId;
        final int seqId = mSyncSeqId;
        mLocalSyncState = LOCAL_SYNC_PENDING;
        mSyncId = mSurfaceSyncer.setupSync(transaction -> {
        mSyncId = mSurfaceSyncer.setupSync(transaction -> {
            mLocalSyncState = LOCAL_SYNC_RETURNED;
            // Callback will be invoked on executor thread so post to main thread.
            // Callback will be invoked on executor thread so post to main thread.
            mHandler.postAtFrontOfQueue(() -> {
            mHandler.postAtFrontOfQueue(() -> {
                mLocalSyncState = LOCAL_SYNC_MERGED;
                mSurfaceChangedTransaction.merge(transaction);
                mSurfaceChangedTransaction.merge(transaction);
                reportDrawFinished(seqId);
                reportDrawFinished(seqId);
            });
            });
@@ -4321,9 +4352,12 @@ public final class ViewRootImpl implements ViewParent,
    }
    }


    private boolean performDraw() {
    private boolean performDraw() {
        mLastPerformDrawSkippedReason = null;
        if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
        if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
            mLastPerformDrawSkippedReason = "screen_off";
            return false;
            return false;
        } else if (mView == null) {
        } else if (mView == null) {
            mLastPerformDrawSkippedReason = "no_root_view";
            return false;
            return false;
        }
        }


@@ -8390,6 +8424,21 @@ public final class ViewRootImpl implements ViewParent,
        if (mTraversalScheduled) {
        if (mTraversalScheduled) {
            writer.println(innerPrefix + " (barrier=" + mTraversalBarrier + ")");
            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 + "mIsAmbientMode="  + mIsAmbientMode);
        writer.println(innerPrefix + "mUnbufferedInputSource="
        writer.println(innerPrefix + "mUnbufferedInputSource="
                + Integer.toHexString(mUnbufferedInputSource));
                + Integer.toHexString(mUnbufferedInputSource));
@@ -9890,11 +9939,12 @@ public final class ViewRootImpl implements ViewParent,
        }
        }
    }
    }


    private void reportNextDraw() {
    private void reportNextDraw(String reason) {
        if (DEBUG_BLAST) {
        if (DEBUG_BLAST) {
            Log.d(mTag, "reportNextDraw " + Debug.getCallers(5));
            Log.d(mTag, "reportNextDraw " + Debug.getCallers(5));
        }
        }
        mReportNextDraw = true;
        mReportNextDraw = true;
        mLastReportNextDrawReason = reason;
    }
    }


    /**
    /**
@@ -9907,11 +9957,12 @@ public final class ViewRootImpl implements ViewParent,
     * @param syncBuffer If true, the transaction that contains the buffer from the draw should be
     * @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,
     *                   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.
     *                   but only report back that a buffer was drawn.
     * @param reason A debug string indicating the reason for reporting the next draw
     * @hide
     * @hide
     */
     */
    public void setReportNextDraw(boolean syncBuffer) {
    public void setReportNextDraw(boolean syncBuffer, String reason) {
        mSyncBuffer = syncBuffer;
        mSyncBuffer = syncBuffer;
        reportNextDraw();
        reportNextDraw(reason);
        invalidate();
        invalidate();
    }
    }


+18 −1
Original line number Original line Diff line number Diff line
@@ -74,6 +74,9 @@ public final class ViewTreeObserver {
     * that the listener will be immediately called. */
     * that the listener will be immediately called. */
    private boolean mWindowShown;
    private boolean mWindowShown;


    // The reason that the last call to dispatchOnPreDraw() returned true to cancel and redraw
    private String mLastDispatchOnPreDrawCanceledReason;

    private boolean mAlive = true;
    private boolean mAlive = true;


    /**
    /**
@@ -1167,6 +1170,7 @@ public final class ViewTreeObserver {
     */
     */
    @SuppressWarnings("unchecked")
    @SuppressWarnings("unchecked")
    public final boolean dispatchOnPreDraw() {
    public final boolean dispatchOnPreDraw() {
        mLastDispatchOnPreDrawCanceledReason = null;
        boolean cancelDraw = false;
        boolean cancelDraw = false;
        final CopyOnWriteArray<OnPreDrawListener> listeners = mOnPreDrawListeners;
        final CopyOnWriteArray<OnPreDrawListener> listeners = mOnPreDrawListeners;
        if (listeners != null && listeners.size() > 0) {
        if (listeners != null && listeners.size() > 0) {
@@ -1174,7 +1178,11 @@ public final class ViewTreeObserver {
            try {
            try {
                int count = access.size();
                int count = access.size();
                for (int i = 0; i < count; i++) {
                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 {
            } finally {
                listeners.end();
                listeners.end();
@@ -1183,6 +1191,15 @@ public final class ViewTreeObserver {
        return cancelDraw;
        return cancelDraw;
    }
    }


    /**
     * @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
     * Notifies registered listeners that the window is now shown
     * @hide
     * @hide