OSDN Git Service

[wm]: Fixed TaskPositioner leak
authoryj81.kwon <yj81.kwon@samsung.com>
Wed, 24 Apr 2019 01:53:57 +0000 (18:53 -0700)
committerVishnu Nair <vishnun@google.com>
Thu, 16 May 2019 23:42:10 +0000 (16:42 -0700)
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)

core/java/android/view/IWindowSession.aidl
core/java/android/view/View.java
core/java/com/android/internal/widget/DecorCaptionView.java
services/core/java/com/android/server/wm/Session.java
services/core/java/com/android/server/wm/TaskPositioner.java
services/core/java/com/android/server/wm/TaskPositioningController.java
services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java

index d269323..caab00c 100644 (file)
@@ -254,6 +254,8 @@ interface IWindowSession {
      */
     boolean startMovingTask(IWindow window, float startX, float startY);
 
+    void finishMovingTask(IWindow window);
+
     void updatePointerIcon(IWindow window);
 
     /**
index 921294a..85580aa 100644 (file)
@@ -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()}.
index 19b68e5..4014c45 100644 (file)
@@ -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;
         }
index 34273f3..ecb0941 100644 (file)
@@ -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<Rect> exclusionRects) {
         long ident = Binder.clearCallingIdentity();
         try {
index efd3e1c..2fc64ea 100644 (file)
@@ -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;
index 3929a12..2441954 100644 (file)
@@ -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");
index c9263eb..714d2f2 100644 (file)
@@ -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) {