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

Commit f450f6df authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Introduce write lock for mDragState"

parents aab90770 7a5d007a
Loading
Loading
Loading
Loading
+214 −165
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ class DragDropController {

    /**
     * Drag state per operation.
     * Needs a lock of {@code WindowManagerService#mWindowMap} to read this. Needs both locks of
     * {@code mWriteLock} and {@code WindowManagerService#mWindowMap} to update this.
     * The variable is cleared by {@code #onDragStateClosedLocked} which is invoked by DragState
     * itself, thus the variable can be null after calling DragState's methods.
     */
@@ -59,6 +61,38 @@ class DragDropController {

    private WindowManagerService mService;
    private final Handler mHandler;
    /**
     * Lock to preserve the order of state updates.
     * The lock is used to process drag and drop state updates in order without having the window
     * manager lock.
     *
     * Suppose DragDropController invokes a callback method A, then processes the following update
     * A'. Same for a callback method B and the following update B'. The callback wants
     * DragDropController to processes the updates in the order of  A' then B'.
     *
     * Without mWriteLock: the following race can happen.
     *
     * 1. Thread a calls A.
     * 2. Thread b calls B.
     * 3. Thread b acquires the window manager lock
     * 4. thread b processes the update B'
     * 5. Thread a acquires the window manager lock
     * 6. thread a processes the update A'
     *
     * With mWriteLock we can ensure the order of A' and B'
     *
     * 1. Thread a acquire mWriteLock
     * 2. Thread a calls A
     * 3. Thread a acquire the window manager lock
     * 4. Thread a processes A'
     * 5. Thread b acquire mWriteLock
     * 6. Thread b calls B
     * 7. Thread b acquire the window manager lock
     * 8. Thread b processes B'
     *
     * Don't acquire the lock while holding the window manager lock, otherwise it causes a deadlock.
     */
    private final Object mWriteLock = new Object();

    boolean dragDropActiveLocked() {
        return mDragState != null;
@@ -85,8 +119,7 @@ class DragDropController {
                    + " asbinder=" + window.asBinder());
        }

        IBinder token = null;

        synchronized (mWriteLock) {
            synchronized (mService.mWindowMap) {
                if (dragDropActiveLocked()) {
                    Slog.w(TAG_WM, "Drag already in progress");
@@ -110,10 +143,11 @@ class DragDropController {
                }
                surface.setAlpha(alpha);

            if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  DRAG " + surface + ": CREATE");
                if (SHOW_TRANSACTIONS)
                    Slog.i(TAG_WM, "  DRAG " + surface + ": CREATE");
                outSurface.copyFrom(surface);
                final IBinder winBinder = window.asBinder();
            token = new Binder();
                IBinder token = new Binder();
                mDragState = new DragState(mService, token, surface, flags, winBinder);
                mDragState.mPid = callerPid;
                mDragState.mUid = callerUid;
@@ -122,10 +156,10 @@ class DragDropController {

                // 5 second timeout for this window to actually begin the drag
                sendTimeoutMessage(MSG_DRAG_START_TIMEOUT, winBinder);
        }

                return token;
            }
        }
    }

    boolean performDrag(IWindow window, IBinder dragToken,
            int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
@@ -134,6 +168,7 @@ class DragDropController {
            Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data);
        }

        synchronized (mWriteLock) {
            synchronized (mService.mWindowMap) {
                if (mDragState == null) {
                    Slog.w(TAG_WM, "No drag prepared");
@@ -187,8 +222,7 @@ class DragDropController {

                // Make the surface visible at the proper location
                final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
                    TAG_WM, ">>> OPEN TRANSACTION performDrag");
                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag");
                mService.openSurfaceTransaction();
                try {
                    surfaceControl.setPosition(touchX - thumbCenterX,
@@ -198,12 +232,14 @@ class DragDropController {
                    surfaceControl.show();
                } finally {
                    mService.closeSurfaceTransaction("performDrag");
                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
                        TAG_WM, "<<< CLOSE TRANSACTION performDrag");
                    if (SHOW_LIGHT_TRANSACTIONS) {
                        Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
                    }
                }

                mDragState.notifyLocationLocked(touchX, touchY);
            }
        }

        return true;    // success!
    }
@@ -214,6 +250,7 @@ class DragDropController {
            Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token);
        }

        synchronized (mWriteLock) {
            synchronized (mService.mWindowMap) {
                if (mDragState == null) {
                    // Most likely the drop recipient ANRed and we ended the drag
@@ -238,16 +275,19 @@ class DragDropController {
                    return;  // !!! TODO: throw here?
                }


                mDragState.mDragResult = consumed;
                mDragState.endDragLocked();
            }
        }
    }

    void cancelDragAndDrop(IBinder dragToken) {
        if (DEBUG_DRAG) {
            Slog.d(TAG_WM, "cancelDragAndDrop");
        }

        synchronized (mWriteLock) {
            synchronized (mService.mWindowMap) {
                if (mDragState == null) {
                    Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()");
@@ -265,6 +305,7 @@ class DragDropController {
                mDragState.cancelDragLocked();
            }
        }
    }

    /**
     * Handles motion events.
@@ -274,6 +315,7 @@ class DragDropController {
     * @param newY Y coordinate value in dp in the screen coordinate
     */
    void handleMotionEvent(boolean keepHandling, float newX, float newY) {
        synchronized (mWriteLock) {
            synchronized (mService.mWindowMap) {
                if (!dragDropActiveLocked()) {
                    // The drag has ended but the clean-up message has not been processed by
@@ -289,6 +331,7 @@ class DragDropController {
                }
            }
        }
    }

    void dragRecipientEntered(IWindow window) {
        if (DEBUG_DRAG) {
@@ -348,20 +391,23 @@ class DragDropController {
                    if (DEBUG_DRAG) {
                        Slog.w(TAG_WM, "Timeout starting drag by win " + win);
                    }
                    synchronized (mWriteLock) {
                        synchronized (mService.mWindowMap) {
                            // !!! TODO: ANR the app that has failed to start the drag in time
                            if (mDragState != null) {
                                mDragState.closeLocked();
                            }
                        }
                    }
                    break;
                }

                case MSG_DRAG_END_TIMEOUT: {
                    IBinder win = (IBinder) msg.obj;
                    final IBinder win = (IBinder) msg.obj;
                    if (DEBUG_DRAG) {
                        Slog.w(TAG_WM, "Timeout ending drag to win " + win);
                    }
                    synchronized (mWriteLock) {
                        synchronized (mService.mWindowMap) {
                            // !!! TODO: ANR the drag-receiving app
                            if (mDragState != null) {
@@ -369,22 +415,24 @@ class DragDropController {
                                mDragState.endDragLocked();
                            }
                        }
                    }
                    break;
                }

                case MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT: {
                    if (DEBUG_DRAG)
                        Slog.d(TAG_WM, "Drag ending; tearing down input channel");
                    DragState.InputInterceptor interceptor = (DragState.InputInterceptor) msg.obj;
                    if (interceptor != null) {
                    final DragState.InputInterceptor interceptor =
                            (DragState.InputInterceptor) msg.obj;
                    if (interceptor == null) return;
                    synchronized (mService.mWindowMap) {
                        interceptor.tearDown();
                    }
                    }
                    break;
                }

                case MSG_ANIMATION_END: {
                    synchronized (mWriteLock) {
                        synchronized (mService.mWindowMap) {
                            if (mDragState == null) {
                                Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " +
@@ -393,6 +441,7 @@ class DragDropController {
                            }
                            mDragState.closeLocked();
                        }
                    }
                    break;
                }
            }