From 4ca1b87fdbf2c4161d691f80017010c0f9739e4b Mon Sep 17 00:00:00 2001 From: Charles Chen Date: Tue, 6 Apr 2021 18:05:27 +0800 Subject: [PATCH] Fix WindowContext cannot add window with sub window type Bug: 184717383 Test: atest WindowManagerServiceTests Test: atest WindowContextTest Change-Id: Ie523902a8ec1a1de96b961da1204bf7c923052be --- .../src/android/window/WindowContextTest.java | 45 +++++++++++++++++++ .../server/wm/WindowManagerService.java | 7 ++- .../server/wm/WindowManagerServiceTests.java | 34 ++++++++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) diff --git a/core/tests/coretests/src/android/window/WindowContextTest.java b/core/tests/coretests/src/android/window/WindowContextTest.java index 614e7c1d6fa45..83280f18c8890 100644 --- a/core/tests/coretests/src/android/window/WindowContextTest.java +++ b/core/tests/coretests/src/android/window/WindowContextTest.java @@ -17,6 +17,7 @@ package android.window; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; @@ -209,6 +210,38 @@ public class WindowContextTest { mWms.removeWindowToken(existingToken, DEFAULT_DISPLAY); } + @Test + public void testWindowContextAddViewWithSubWindowType_NotCrash() throws Throwable { + final WindowContext windowContext = createWindowContext(TYPE_INPUT_METHOD); + final WindowManager wm = windowContext.getSystemService(WindowManager.class); + + // Create a WindowToken with system window type. + final IBinder existingToken = new Binder(); + mWms.addWindowToken(existingToken, TYPE_INPUT_METHOD, windowContext.getDisplayId(), + null /* options */); + + final WindowManager.LayoutParams params = + new WindowManager.LayoutParams(TYPE_INPUT_METHOD); + params.token = existingToken; + final View parentWindow = new View(windowContext); + + final AttachStateListener listener = new AttachStateListener(); + parentWindow.addOnAttachStateChangeListener(listener); + + // Add the parent window + mInstrumentation.runOnMainSync(() -> wm.addView(parentWindow, params)); + + assertTrue(listener.mLatch.await(4, TimeUnit.SECONDS)); + + final WindowManager.LayoutParams subWindowAttrs = + new WindowManager.LayoutParams(TYPE_APPLICATION_ATTACHED_DIALOG); + subWindowAttrs.token = parentWindow.getWindowToken(); + final View subWindow = new View(windowContext); + + // Add a window with sub-window type. + mInstrumentation.runOnMainSync(() -> wm.addView(subWindow, subWindowAttrs)); + } + private WindowContext createWindowContext() { return createWindowContext(TYPE_APPLICATION_OVERLAY); } @@ -219,4 +252,16 @@ public class WindowContextTest { .getDisplay(DEFAULT_DISPLAY); return (WindowContext) instContext.createWindowContext(display, type, null /* options */); } + + private static class AttachStateListener implements View.OnAttachStateChangeListener { + final CountDownLatch mLatch = new CountDownLatch(1); + + @Override + public void onViewAttachedToWindow(View v) { + mLatch.countDown(); + } + + @Override + public void onViewDetachedFromWindow(View v) {} + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 7650fa1f3f5e4..67edde140c048 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1740,8 +1740,11 @@ public class WindowManagerService extends IWindowManager.Stub } // Switch to listen to the {@link WindowToken token}'s configuration changes when - // adding a window to the window context. - if (mWindowContextListenerController.hasListener(windowContextToken)) { + // adding a window to the window context. Filter sub window type here because the sub + // window must be attached to the parent window, which is attached to the window context + // created window token. + if (!win.isChildWindow() + && mWindowContextListenerController.hasListener(windowContextToken)) { final int windowContextType = mWindowContextListenerController .getWindowType(windowContextToken); if (type != windowContextType) { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java index dd0c9e6d390ec..d9aa871447be5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -23,6 +23,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; @@ -50,7 +51,13 @@ import android.content.pm.PackageManager; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.os.UserHandle; import android.platform.test.annotations.Presubmit; +import android.view.IWindowSessionCallback; +import android.view.InsetsSourceControl; +import android.view.InsetsState; +import android.view.View; +import android.view.WindowManager; import androidx.test.filters.SmallTest; @@ -250,4 +257,31 @@ public class WindowManagerServiceTests extends WindowTestsBase { eq(clientToken), eq(windowToken), anyInt(), eq(TYPE_INPUT_METHOD), eq(windowToken.mOptions)); } + + @Test + public void testAddWindowWithSubWindowTypeByWindowContext() { + spyOn(mWm.mWindowContextListenerController); + + final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD, mDefaultDisplay); + final Session session = new Session(mWm, new IWindowSessionCallback.Stub() { + @Override + public void onAnimatorScaleChanged(float v) throws RemoteException {} + }); + final WindowManager.LayoutParams params = new WindowManager.LayoutParams( + TYPE_APPLICATION_ATTACHED_DIALOG); + params.token = windowToken.token; + final IBinder windowContextToken = new Binder(); + params.setWindowContextToken(windowContextToken); + doReturn(true).when(mWm.mWindowContextListenerController) + .hasListener(eq(windowContextToken)); + doReturn(TYPE_INPUT_METHOD).when(mWm.mWindowContextListenerController) + .getWindowType(eq(windowContextToken)); + + mWm.addWindow(session, new TestIWindow(), params, View.VISIBLE, DEFAULT_DISPLAY, + UserHandle.USER_SYSTEM, new InsetsState(), null, new InsetsState(), + new InsetsSourceControl[0]); + + verify(mWm.mWindowContextListenerController, never()).registerWindowContainerListener(any(), + any(), anyInt(), anyInt(), any()); + } }