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

Commit d1ada44d authored by chaviw's avatar chaviw Committed by Evan Rosky
Browse files

Prevent windows from drawing if they're in an active sync set

If a window is in a sync, but it already drew it's sync buffer, it
normally would be allowed to continue processing draws and just block
when it runs out of buffers. It would unblock once the sync is complete
at the sync buffer was sent to SF. However, this has a few issues

1. In some cases, WMS wants to retry the draw again due to configuration
   changes. This could cause deadlocks because the client may already be
   blocked since there are no more buffers. Instead, the client will
   block and WMS would be responsible for dropping the last buffer and
   notifying the client that it can draw for a sync again

2. If there are multiple UI threads, each can block each other due to
   the shared Render Thread. If one of the windows in the sync continues
   to draw and then blocks RT due to no more buffers, all other UI
   threads are unable to draw. If the behavior in 1 is desired, we'd
   need to make sure no one in the same sync continues to draw until
   everyone is complete. This is to ensure dropping will actually allow
   another render to occur. If other windows are blocking the RT, then
   even with dropping, the requested sync window cannot get another buffer
   and will cause a deadlock.

Test: Current sync requests work
Bug: 233625646
Change-Id: I3a0a4f36bf61a6677507672578e447060b806651
parent c4ede8e6
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -384,4 +384,9 @@ interface IWindowSession {
     * Clears a touchable region set by {@link #setInsets}.
     * Clears a touchable region set by {@link #setInsets}.
     */
     */
    void clearTouchableRegion(IWindow window);
    void clearTouchableRegion(IWindow window);

    /**
     * Returns whether this window needs to cancel draw and retry later.
     */
    boolean cancelDraw(IWindow window);
}
}
+31 −1
Original line number Original line Diff line number Diff line
@@ -84,6 +84,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
@@ -601,6 +602,14 @@ public final class ViewRootImpl implements ViewParent,
     */
     */
    private boolean mSyncBuffer = false;
    private boolean mSyncBuffer = false;


    /**
     * Flag to determine whether the client needs to check with WMS if it can draw. WMS will notify
     * the client that it can't draw if we're still in the middle of a sync set that includes this
     * window. Once the sync is complete, the window can resume drawing. This is to ensure we don't
     * deadlock the client by trying to request draws when there may not be any buffers available.
     */
    private boolean mCheckIfCanDraw = false;

    int mSyncSeqId = 0;
    int mSyncSeqId = 0;
    int mLastSyncSeqId = 0;
    int mLastSyncSeqId = 0;


@@ -2694,6 +2703,9 @@ public final class ViewRootImpl implements ViewParent,


        mIsInTraversal = true;
        mIsInTraversal = true;
        mWillDrawSoon = true;
        mWillDrawSoon = true;
        boolean cancelDraw = false;
        boolean isSyncRequest = false;

        boolean windowSizeMayChange = false;
        boolean windowSizeMayChange = false;
        WindowManager.LayoutParams lp = mWindowAttributes;
        WindowManager.LayoutParams lp = mWindowAttributes;


@@ -2963,6 +2975,8 @@ public final class ViewRootImpl implements ViewParent,
                    mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
                    mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
                }
                }
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
                cancelDraw = (relayoutResult & RELAYOUT_RES_CANCEL_AND_REDRAW)
                        == RELAYOUT_RES_CANCEL_AND_REDRAW;
                final boolean dragResizing = mPendingDragResizing;
                final boolean dragResizing = mPendingDragResizing;
                if (mSyncSeqId > mLastSyncSeqId) {
                if (mSyncSeqId > mLastSyncSeqId) {
                    mLastSyncSeqId = mSyncSeqId;
                    mLastSyncSeqId = mSyncSeqId;
@@ -2971,6 +2985,7 @@ public final class ViewRootImpl implements ViewParent,
                    }
                    }
                    reportNextDraw();
                    reportNextDraw();
                    mSyncBuffer = true;
                    mSyncBuffer = true;
                    isSyncRequest = true;
                }
                }


                final boolean surfaceControlChanged =
                final boolean surfaceControlChanged =
@@ -3259,6 +3274,19 @@ public final class ViewRootImpl implements ViewParent,
                }
                }
            }
            }
        } else {
        } else {
            // If a relayout isn't going to happen, we still need to check if this window can draw
            // when mCheckIfCanDraw is set. This is because it means we had a sync in the past, but
            // have not been told by WMS that the sync is complete and that we can continue to draw
            if (mCheckIfCanDraw) {
                try {
                    cancelDraw = mWindowSession.cancelDraw(mWindow);
                    if (DEBUG_BLAST) {
                        Log.d(mTag, "cancelDraw returned " + cancelDraw);
                    }
                } catch (RemoteException e) {
                }
            }

            // Not the first pass and no window/insets/visibility change but the window
            // Not the first pass and no window/insets/visibility change but the window
            // may have moved and we need check that and if so to update the left and right
            // may have moved and we need check that and if so to update the left and right
            // in the attach info. We translate only the window frame since on window move
            // in the attach info. We translate only the window frame since on window move
@@ -3477,7 +3505,9 @@ public final class ViewRootImpl implements ViewParent,
            reportNextDraw();
            reportNextDraw();
        }
        }


        boolean cancelAndRedraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
        mCheckIfCanDraw = isSyncRequest || cancelDraw;

        boolean cancelAndRedraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || cancelDraw;
        if (!cancelAndRedraw) {
        if (!cancelAndRedraw) {
            createSyncIfNeeded();
            createSyncIfNeeded();
        }
        }
+5 −0
Original line number Original line Diff line number Diff line
@@ -82,6 +82,11 @@ public final class WindowManagerGlobal {
     */
     */
    public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 1 << 3;
    public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 1 << 3;


    /**
     * The window manager has told the window it cannot draw this frame and should retry again.
     */
    public static final int RELAYOUT_RES_CANCEL_AND_REDRAW = 1 << 4;

    /**
    /**
     * Flag for relayout: the client will be later giving
     * Flag for relayout: the client will be later giving
     * internal insets; as a result, the window will not impact other window
     * internal insets; as a result, the window will not impact other window
+5 −0
Original line number Original line Diff line number Diff line
@@ -552,4 +552,9 @@ public class WindowlessWindowManager implements IWindowSession {
            }
            }
        }
        }
    }
    }

    @Override
    public boolean cancelDraw(IWindow window) {
        return false;
    }
}
}
+5 −0
Original line number Original line Diff line number Diff line
@@ -249,6 +249,11 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
        mService.setWillReplaceWindows(appToken, childrenOnly);
        mService.setWillReplaceWindows(appToken, childrenOnly);
    }
    }


    @Override
    public boolean cancelDraw(IWindow window) {
        return mService.cancelDraw(this, window);
    }

    @Override
    @Override
    public int relayout(IWindow window, WindowManager.LayoutParams attrs,
    public int relayout(IWindow window, WindowManager.LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewFlags, int flags,
            int requestedWidth, int requestedHeight, int viewFlags, int flags,
Loading