Loading services/core/java/com/android/server/wm/DragDropController.java +83 −120 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.view.View; import com.android.internal.util.Preconditions; import com.android.server.input.InputWindowHandle; import com.android.server.wm.WindowManagerInternal.IDragDropCallback; import java.util.concurrent.atomic.AtomicReference; /** * Managing drag and drop operations initiated by View#startDragAndDrop. Loading @@ -66,43 +67,11 @@ 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(); /** * Callback which is used to sync drag state with the vendor-specific code. */ @NonNull private IDragDropCallback mCallback = new IDragDropCallback() {}; @NonNull private AtomicReference<IDragDropCallback> mCallback = new AtomicReference<>( new IDragDropCallback() {}); boolean dragDropActiveLocked() { return mDragState != null; Loading @@ -114,9 +83,7 @@ class DragDropController { void registerCallback(IDragDropCallback callback) { Preconditions.checkNotNull(callback); synchronized (mWriteLock) { mCallback = callback; } mCallback.set(callback); } DragDropController(WindowManagerService service, Looper looper) { Loading @@ -136,7 +103,6 @@ class DragDropController { + " asbinder=" + window.asBinder()); } synchronized (mWriteLock) { synchronized (mService.mWindowMap) { if (dragDropActiveLocked()) { Slog.w(TAG_WM, "Drag already in progress"); Loading Loading @@ -176,7 +142,6 @@ class DragDropController { return token; } } } boolean performDrag(IWindow window, IBinder dragToken, int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY, Loading @@ -185,11 +150,11 @@ class DragDropController { Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data); } synchronized (mWriteLock) { if (!mCallback.performDrag(window, dragToken, touchSource, touchX, touchY, thumbCenterX, if (!mCallback.get().prePerformDrag(window, dragToken, touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data)) { return false; } try { synchronized (mService.mWindowMap) { if (mDragState == null) { Slog.w(TAG_WM, "No drag prepared"); Loading Loading @@ -260,9 +225,10 @@ class DragDropController { mDragState.notifyLocationLocked(touchX, touchY); } } return true; // success! } finally { mCallback.get().postPerformDrag(); } } void reportDropResult(IWindow window, boolean consumed) { Loading @@ -271,8 +237,8 @@ class DragDropController { Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token); } synchronized (mWriteLock) { mCallback.reportDropResult(window, consumed); mCallback.get().preReportDropResult(window, consumed); try { synchronized (mService.mWindowMap) { if (mDragState == null) { // Most likely the drop recipient ANRed and we ended the drag Loading @@ -297,10 +263,11 @@ class DragDropController { return; // !!! TODO: throw here? } mDragState.mDragResult = consumed; mDragState.endDragLocked(); } } finally { mCallback.get().postReportDropResult(); } } Loading @@ -309,8 +276,8 @@ class DragDropController { Slog.d(TAG_WM, "cancelDragAndDrop"); } synchronized (mWriteLock) { mCallback.cancelDragAndDrop(dragToken); mCallback.get().preCancelDragAndDrop(dragToken); try { synchronized (mService.mWindowMap) { if (mDragState == null) { Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()"); Loading @@ -327,6 +294,8 @@ class DragDropController { mDragState.mDragResult = false; mDragState.cancelDragLocked(); } } finally { mCallback.get().postCancelDragAndDrop(); } } Loading @@ -338,7 +307,6 @@ 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 Loading @@ -354,7 +322,6 @@ class DragDropController { } } } } void dragRecipientEntered(IWindow window) { if (DEBUG_DRAG) { Loading Loading @@ -414,14 +381,13 @@ 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; } Loading @@ -430,7 +396,7 @@ class DragDropController { 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) { Loading @@ -438,7 +404,6 @@ class DragDropController { mDragState.endDragLocked(); } } } break; } Loading @@ -455,7 +420,6 @@ class DragDropController { } case MSG_ANIMATION_END: { synchronized (mWriteLock) { synchronized (mService.mWindowMap) { if (mDragState == null) { Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " + Loading @@ -464,7 +428,6 @@ class DragDropController { } mDragState.closeLocked(); } } break; } } Loading services/core/java/com/android/server/wm/WindowManagerInternal.java +21 −6 Original line number Diff line number Diff line Loading @@ -151,23 +151,38 @@ public abstract class WindowManagerInternal { */ public interface IDragDropCallback { /** * Called when drag operation is started. * Called when drag operation is starting. */ default boolean performDrag(IWindow window, IBinder dragToken, default boolean prePerformDrag(IWindow window, IBinder dragToken, int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) { return true; } /** * Called when drop result is reported. * Called when drag operation is started. */ default void postPerformDrag() {} /** * Called when drop result is being reported. */ default void preReportDropResult(IWindow window, boolean consumed) {} /** * Called when drop result was reported. */ default void postReportDropResult() {} /** * Called when drag operation is being cancelled. */ default void reportDropResult(IWindow window, boolean consumed) {} default void preCancelDragAndDrop(IBinder dragToken) {} /** * Called when drag operation is cancelled. * Called when drag operation was cancelled. */ default void cancelDragAndDrop(IBinder dragToken) {} default void postCancelDragAndDrop() {} } /** Loading Loading
services/core/java/com/android/server/wm/DragDropController.java +83 −120 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.view.View; import com.android.internal.util.Preconditions; import com.android.server.input.InputWindowHandle; import com.android.server.wm.WindowManagerInternal.IDragDropCallback; import java.util.concurrent.atomic.AtomicReference; /** * Managing drag and drop operations initiated by View#startDragAndDrop. Loading @@ -66,43 +67,11 @@ 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(); /** * Callback which is used to sync drag state with the vendor-specific code. */ @NonNull private IDragDropCallback mCallback = new IDragDropCallback() {}; @NonNull private AtomicReference<IDragDropCallback> mCallback = new AtomicReference<>( new IDragDropCallback() {}); boolean dragDropActiveLocked() { return mDragState != null; Loading @@ -114,9 +83,7 @@ class DragDropController { void registerCallback(IDragDropCallback callback) { Preconditions.checkNotNull(callback); synchronized (mWriteLock) { mCallback = callback; } mCallback.set(callback); } DragDropController(WindowManagerService service, Looper looper) { Loading @@ -136,7 +103,6 @@ class DragDropController { + " asbinder=" + window.asBinder()); } synchronized (mWriteLock) { synchronized (mService.mWindowMap) { if (dragDropActiveLocked()) { Slog.w(TAG_WM, "Drag already in progress"); Loading Loading @@ -176,7 +142,6 @@ class DragDropController { return token; } } } boolean performDrag(IWindow window, IBinder dragToken, int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY, Loading @@ -185,11 +150,11 @@ class DragDropController { Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data); } synchronized (mWriteLock) { if (!mCallback.performDrag(window, dragToken, touchSource, touchX, touchY, thumbCenterX, if (!mCallback.get().prePerformDrag(window, dragToken, touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data)) { return false; } try { synchronized (mService.mWindowMap) { if (mDragState == null) { Slog.w(TAG_WM, "No drag prepared"); Loading Loading @@ -260,9 +225,10 @@ class DragDropController { mDragState.notifyLocationLocked(touchX, touchY); } } return true; // success! } finally { mCallback.get().postPerformDrag(); } } void reportDropResult(IWindow window, boolean consumed) { Loading @@ -271,8 +237,8 @@ class DragDropController { Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token); } synchronized (mWriteLock) { mCallback.reportDropResult(window, consumed); mCallback.get().preReportDropResult(window, consumed); try { synchronized (mService.mWindowMap) { if (mDragState == null) { // Most likely the drop recipient ANRed and we ended the drag Loading @@ -297,10 +263,11 @@ class DragDropController { return; // !!! TODO: throw here? } mDragState.mDragResult = consumed; mDragState.endDragLocked(); } } finally { mCallback.get().postReportDropResult(); } } Loading @@ -309,8 +276,8 @@ class DragDropController { Slog.d(TAG_WM, "cancelDragAndDrop"); } synchronized (mWriteLock) { mCallback.cancelDragAndDrop(dragToken); mCallback.get().preCancelDragAndDrop(dragToken); try { synchronized (mService.mWindowMap) { if (mDragState == null) { Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()"); Loading @@ -327,6 +294,8 @@ class DragDropController { mDragState.mDragResult = false; mDragState.cancelDragLocked(); } } finally { mCallback.get().postCancelDragAndDrop(); } } Loading @@ -338,7 +307,6 @@ 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 Loading @@ -354,7 +322,6 @@ class DragDropController { } } } } void dragRecipientEntered(IWindow window) { if (DEBUG_DRAG) { Loading Loading @@ -414,14 +381,13 @@ 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; } Loading @@ -430,7 +396,7 @@ class DragDropController { 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) { Loading @@ -438,7 +404,6 @@ class DragDropController { mDragState.endDragLocked(); } } } break; } Loading @@ -455,7 +420,6 @@ class DragDropController { } case MSG_ANIMATION_END: { synchronized (mWriteLock) { synchronized (mService.mWindowMap) { if (mDragState == null) { Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " + Loading @@ -464,7 +428,6 @@ class DragDropController { } mDragState.closeLocked(); } } break; } } Loading
services/core/java/com/android/server/wm/WindowManagerInternal.java +21 −6 Original line number Diff line number Diff line Loading @@ -151,23 +151,38 @@ public abstract class WindowManagerInternal { */ public interface IDragDropCallback { /** * Called when drag operation is started. * Called when drag operation is starting. */ default boolean performDrag(IWindow window, IBinder dragToken, default boolean prePerformDrag(IWindow window, IBinder dragToken, int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) { return true; } /** * Called when drop result is reported. * Called when drag operation is started. */ default void postPerformDrag() {} /** * Called when drop result is being reported. */ default void preReportDropResult(IWindow window, boolean consumed) {} /** * Called when drop result was reported. */ default void postReportDropResult() {} /** * Called when drag operation is being cancelled. */ default void reportDropResult(IWindow window, boolean consumed) {} default void preCancelDragAndDrop(IBinder dragToken) {} /** * Called when drag operation is cancelled. * Called when drag operation was cancelled. */ default void cancelDragAndDrop(IBinder dragToken) {} default void postCancelDragAndDrop() {} } /** Loading