From: yj81.kwon Date: Wed, 24 Apr 2019 01:53:57 +0000 (-0700) Subject: [wm]: Fixed TaskPositioner leak X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=19585ffabf9f8804378ab6b0cf957b50b793c574;p=android-x86%2Fframeworks-base.git [wm]: Fixed TaskPositioner leak If application process handles motion events late, it requests to start moving task after MotionEvent.ACTION_UP is already fired. In that case, system will wait for event that is not comming and cannot end drag state. It's expected that the system finishes moving task when system receives ACTION_UP by transfering touch focus. In a problem case, ACTION_UP event is already sent to the application process before transfering touch focus. If application receives ACTION_UP event after requesting moving task, notify the system of finishing previous request. Test: Quickly try to resize freeform windowing app repeatedly. Test: atest WmTests:TaskPositioningControllerTests Bug: 129507487 Change-Id: Ifa457ddc55524cae6da455e770472781a7805282 (cherry picked from commit 9a1cd7b5063229da536a1281916ae15ec9246d1a) --- diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index d269323d50a4..caab00c3863e 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -254,6 +254,8 @@ interface IWindowSession { */ boolean startMovingTask(IWindow window, float startX, float startY); + void finishMovingTask(IWindow window); + void updatePointerIcon(IWindow window); /** diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 921294a78e5e..85580aad7b4e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -25520,6 +25520,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Finish a window move task. + * @hide + */ + public void finishMovingTask() { + if (ViewDebug.DEBUG_POSITIONING) { + Log.d(VIEW_LOG_TAG, "finishMovingTask"); + } + try { + mAttachInfo.mSession.finishMovingTask(mAttachInfo.mWindow); + } catch (RemoteException e) { + Log.e(VIEW_LOG_TAG, "Unable to finish moving", e); + } + } + + /** * Handles drag events sent by the system following a call to * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) * startDragAndDrop()}. diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java index 19b68e5c467f..4014c454f6a8 100644 --- a/core/java/com/android/internal/widget/DecorCaptionView.java +++ b/core/java/com/android/internal/widget/DecorCaptionView.java @@ -188,7 +188,8 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, final int y = (int) e.getY(); final boolean fromMouse = e.getToolType(e.getActionIndex()) == MotionEvent.TOOL_TYPE_MOUSE; final boolean primaryButton = (e.getButtonState() & MotionEvent.BUTTON_PRIMARY) != 0; - switch (e.getActionMasked()) { + final int actionMasked = e.getActionMasked(); + switch (actionMasked) { case MotionEvent.ACTION_DOWN: if (!mShow) { // When there is no caption we should not react to anything. @@ -220,6 +221,12 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, break; } // Abort the ongoing dragging. + if (actionMasked == MotionEvent.ACTION_UP) { + // If it receives ACTION_UP event, the dragging is already finished and also + // the system can not end drag on ACTION_UP event. So request to finish + // dragging. + finishMovingTask(); + } mDragging = false; return !mCheckForDragging; } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 34273f3f23a5..ecb0941b4bd0 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -316,6 +316,18 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } @Override + public void finishMovingTask(IWindow window) { + if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishMovingTask"); + + long ident = Binder.clearCallingIdentity(); + try { + mService.mTaskPositioningController.finishTaskPositioning(window); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override public void reportSystemGestureExclusionChanged(IWindow window, List exclusionRects) { long ident = Binder.clearCallingIdentity(); try { diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index efd3e1cbf770..2fc64eaf8c97 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -119,7 +119,7 @@ class TaskPositioner implements IBinder.DeathRecipient { private int mCtrlType = CTRL_NONE; @VisibleForTesting boolean mDragEnded; - private IBinder mClientCallback; + IBinder mClientCallback; InputChannel mServerChannel; InputChannel mClientChannel; diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index 3929a122b673..2441954012e5 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -185,6 +185,12 @@ class TaskPositioningController { return true; } + public void finishTaskPositioning(IWindow window) { + if (mTaskPositioner != null && mTaskPositioner.mClientCallback == window.asBinder()) { + finishTaskPositioning(); + } + } + void finishTaskPositioning() { mHandler.post(() -> { if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishPositioning"); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java index c9263eb80592..714d2f2f94a1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java @@ -32,6 +32,7 @@ import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; import android.view.InputChannel; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; @@ -41,7 +42,7 @@ import org.junit.Test; * Tests for the {@link TaskPositioningController} class. * * Build/Install/Run: - * atest FrameworksServicesTests:TaskPositioningControllerTests + * atest WmTests:TaskPositioningControllerTests */ @SmallTest @Presubmit @@ -87,6 +88,29 @@ public class TaskPositioningControllerTests extends WindowTestsBase { assertNull(mTarget.getDragWindowHandleLocked()); } + @FlakyTest(bugId = 129507487) + @Test + public void testFinishPositioningWhenAppRequested() { + synchronized (mWm.mGlobalLock) { + assertFalse(mTarget.isPositioningLocked()); + assertNull(mTarget.getDragWindowHandleLocked()); + } + + assertTrue(mTarget.startMovingTask(mWindow.mClient, 0, 0)); + + synchronized (mWm.mGlobalLock) { + assertTrue(mTarget.isPositioningLocked()); + assertNotNull(mTarget.getDragWindowHandleLocked()); + } + + mTarget.finishTaskPositioning(mWindow.mClient); + // Wait until the looper processes finishTaskPositioning. + assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS)); + + assertFalse(mTarget.isPositioningLocked()); + assertNull(mTarget.getDragWindowHandleLocked()); + } + @Test public void testHandleTapOutsideTask() { synchronized (mWm.mGlobalLock) {