From d9ea032b739df157d9229ee214bb562cbb88508b Mon Sep 17 00:00:00 2001 From: Charles Chen Date: Fri, 16 Apr 2021 16:09:44 +0800 Subject: [PATCH] Fix WindowContext is removed unexpectedly Previously WindowContext is removed if the associated WindowContainer is removed. However, it causes an issue that WindowContext is removed unexpectedly after the last window is removed by WM#removeView(). When the last view is removed, WMS will remove the WindowToken in postWindowRemoveCleanupLocked(), and if the WindowToken is created by WindowContext, the associated WindowContext is also removed unexpectedly. This CL makes WindowContext switch back to listen to the previous DisplayArea if the last window is removed. Test: atest WindowContextListenerControllerTests Bug: 185460076 Change-Id: I9c1d0c15c77bbfb3662355f8c72f0d8c70ed6748 --- .../wm/WindowContextListenerController.java | 15 ++++++++++++ .../WindowContextListenerControllerTests.java | 23 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/services/core/java/com/android/server/wm/WindowContextListenerController.java b/services/core/java/com/android/server/wm/WindowContextListenerController.java index 5e75996b00120..a127611b2cce7 100644 --- a/services/core/java/com/android/server/wm/WindowContextListenerController.java +++ b/services/core/java/com/android/server/wm/WindowContextListenerController.java @@ -271,6 +271,21 @@ class WindowContextListenerController { if (mDeathRecipient == null) { throw new IllegalStateException("Invalid client token: " + mClientToken); } + final WindowToken windowToken = mContainer.asWindowToken(); + if (windowToken != null && windowToken.isFromClient()) { + // If the WindowContext created WindowToken is removed by + // WMS#postWindowRemoveCleanupLocked, the WindowContext should switch back to + // listen to previous associated DisplayArea. + final DisplayContent dc = windowToken.mWmService.mRoot + .getDisplayContent(mLastReportedDisplay); + // If we cannot obtain the DisplayContent, the DisplayContent may also be removed. + // We should proceed the removal process. + if (dc != null) { + final DisplayArea da = dc.findAreaForToken(windowToken); + updateContainer(da); + return; + } + } mDeathRecipient.unlinkToDeath(); IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(mClientToken); try { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java index 73b9173ba1438..5d0fe170885a2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java @@ -17,8 +17,11 @@ package com.android.server.wm; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -162,6 +165,26 @@ public class WindowContextListenerControllerTests extends WindowTestsBase { false /* callerCanManagerAppTokens */, ANOTHER_UID); } + @Test + public void testWindowContextCreatedWindowTokenRemoved_SwitchToListenToDA() { + WindowToken windowContextCreatedToken = new WindowToken.Builder(mWm, mClientToken, + TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) + .setDisplayContent(mDefaultDisplay) + .setFromClientToken(true) + .build(); + final DisplayArea da = windowContextCreatedToken.getDisplayArea(); + + mController.registerWindowContainerListener(mClientToken, windowContextCreatedToken, + TEST_UID, TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, null /* options */); + + assertThat(mController.getContainer(mClientToken)).isEqualTo(windowContextCreatedToken); + + // Remove WindowToken + windowContextCreatedToken.removeImmediately(); + + assertThat(mController.getContainer(mClientToken)).isEqualTo(da); + } + private class TestWindowTokenClient extends IWindowToken.Stub { private Configuration mConfiguration; private int mDisplayId;