From de7672538dde8d9e8c225c54911cad97b56824a9 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Mon, 3 Feb 2020 19:22:16 +0800 Subject: [PATCH] Fix CTS flakes caused by creating duplicated inputconsumer The nav InputConsumer would be used while nav bar is hidden and would pending to be dismissed when nav bar isn't visible. That ensure the application doesn't see the event when nav bar is coming back. Some CTS flakes from window manager crashing that caused by creating duplicated inputconsumer exception. The reason is the previous one hadn't been disposed yet. - Seperate dismiss and dispose that could make sure that the previous nav consumer is removed from InputMonitor when creating the new one, and its input receiver will be disposed on the attached thread. Test: atest com.android.server.wm Test: atest CtsUiRenderingTestCases Bug: 148395441 Change-Id: I03c2f3aaece4f3f000651b18709e0732d5965604 --- .../server/policy/WindowManagerPolicy.java | 12 ++-- .../com/android/server/wm/DisplayPolicy.java | 9 +-- .../com/android/server/wm/InputMonitor.java | 72 ++++++++++--------- .../server/wm/WindowManagerService.java | 15 ---- 4 files changed, 49 insertions(+), 59 deletions(-) diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index e81214e44aff2..67a22d3e477c8 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -75,7 +75,6 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; -import android.os.Looper; import android.os.RemoteException; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -83,7 +82,6 @@ import android.view.Display; import android.view.IApplicationToken; import android.view.IDisplayFoldListener; import android.view.IWindowManager; -import android.view.InputEventReceiver; import android.view.KeyEvent; import android.view.WindowManager; import android.view.WindowManagerGlobal; @@ -471,6 +469,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * Remove the input consumer from the window manager. */ void dismiss(); + /** + * Dispose the input consumer and input receiver from UI thread. + */ + void dispose(); } /** @@ -504,12 +506,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { public static final int CAMERA_LENS_UNCOVERED = 0; public static final int CAMERA_LENS_COVERED = 1; - /** - * Add a input consumer which will consume all input events going to any window below it. - */ - public InputConsumer createInputConsumer(Looper looper, String name, - InputEventReceiver.Factory inputEventReceiverFactory, int displayId); - /** * Returns a code that describes the current state of the lid switch. */ diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index c78707a2204e5..27a8ee4846928 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1511,15 +1511,16 @@ public class DisplayPolicy { // nav bar and ensure the application doesn't see the event. if (navVisible || navAllowedHidden) { if (mInputConsumer != null) { + mInputConsumer.dismiss(); mHandler.sendMessage( mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer)); mInputConsumer = null; } } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) { - mInputConsumer = mService.createInputConsumer(mHandler.getLooper(), + mInputConsumer = mDisplayContent.getInputMonitor().createInputConsumer( + mHandler.getLooper(), INPUT_CONSUMER_NAVIGATION, - HideNavInputEventReceiver::new, - displayFrames.mDisplayId); + HideNavInputEventReceiver::new); // As long as mInputConsumer is active, hover events are not dispatched to the app // and the pointer icon is likely to become stale. Hide it to avoid confusion. InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL); @@ -3173,7 +3174,7 @@ public class DisplayPolicy { private void disposeInputConsumer(InputConsumer inputConsumer) { if (inputConsumer != null) { - inputConsumer.dismiss(); + inputConsumer.dispose(); } } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index faa6e52da8bc8..b638e4937b34a 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -103,9 +103,17 @@ final class InputMonitor { @Override public void dismiss() { synchronized (mService.mGlobalLock) { - if (mInputMonitor.destroyInputConsumer(mWindowHandle.name)) { - mInputEventReceiver.dispose(); - } + mInputMonitor.mInputConsumers.remove(mName); + hide(mInputMonitor.mInputTransaction); + mInputMonitor.updateInputWindowsLw(true /* force */); + } + } + + @Override + public void dispose() { + synchronized (mService.mGlobalLock) { + disposeChannelsLw(); + mInputEventReceiver.dispose(); } } } @@ -415,18 +423,18 @@ final class InputMonitor { } private final class UpdateInputForAllWindowsConsumer implements Consumer { - InputConsumerImpl navInputConsumer; - InputConsumerImpl pipInputConsumer; - InputConsumerImpl wallpaperInputConsumer; - InputConsumerImpl recentsAnimationInputConsumer; + InputConsumerImpl mNavInputConsumer; + InputConsumerImpl mPipInputConsumer; + InputConsumerImpl mWallpaperInputConsumer; + InputConsumerImpl mRecentsAnimationInputConsumer; - private boolean mAddInputConsumerHandle; + private boolean mAddNavInputConsumerHandle; private boolean mAddPipInputConsumerHandle; private boolean mAddWallpaperInputConsumerHandle; private boolean mAddRecentsAnimationInputConsumerHandle; - boolean inDrag; - WallpaperController wallpaperController; + boolean mInDrag; + WallpaperController mWallpaperController; // An invalid window handle that tells SurfaceFlinger not update the input info. final InputWindowHandle mInvalidInputWindow = new InputWindowHandle(null, mDisplayId); @@ -434,20 +442,20 @@ final class InputMonitor { private void updateInputWindows(boolean inDrag) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows"); - navInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION); - pipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP); - wallpaperInputConsumer = getInputConsumer(INPUT_CONSUMER_WALLPAPER); - recentsAnimationInputConsumer = getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION); + mNavInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION); + mPipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP); + mWallpaperInputConsumer = getInputConsumer(INPUT_CONSUMER_WALLPAPER); + mRecentsAnimationInputConsumer = getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION); - mAddInputConsumerHandle = navInputConsumer != null; - mAddPipInputConsumerHandle = pipInputConsumer != null; - mAddWallpaperInputConsumerHandle = wallpaperInputConsumer != null; - mAddRecentsAnimationInputConsumerHandle = recentsAnimationInputConsumer != null; + mAddNavInputConsumerHandle = mNavInputConsumer != null; + mAddPipInputConsumerHandle = mPipInputConsumer != null; + mAddWallpaperInputConsumerHandle = mWallpaperInputConsumer != null; + mAddRecentsAnimationInputConsumerHandle = mRecentsAnimationInputConsumer != null; mTmpRect.setEmpty(); mDisableWallpaperTouchEvents = false; - this.inDrag = inDrag; - wallpaperController = mDisplayContent.mWallpaperController; + mInDrag = inDrag; + mWallpaperController = mDisplayContent.mWallpaperController; resetInputConsumers(mInputTransaction); @@ -455,7 +463,7 @@ final class InputMonitor { true /* traverseTopToBottom */); if (mAddWallpaperInputConsumerHandle) { - wallpaperInputConsumer.show(mInputTransaction, 0); + mWallpaperInputConsumer.show(mInputTransaction, 0); } if (mApplyImmediately) { @@ -494,8 +502,8 @@ final class InputMonitor { if (recentsAnimationController != null && recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord)) { if (recentsAnimationController.updateInputConsumerForApp( - recentsAnimationInputConsumer.mWindowHandle, hasFocus)) { - recentsAnimationInputConsumer.show(mInputTransaction, w); + mRecentsAnimationInputConsumer.mWindowHandle, hasFocus)) { + mRecentsAnimationInputConsumer.show(mInputTransaction, w); mAddRecentsAnimationInputConsumerHandle = false; } } @@ -505,25 +513,25 @@ final class InputMonitor { if (mAddPipInputConsumerHandle) { // Update the bounds of the Pip input consumer to match the window bounds. w.getBounds(mTmpRect); - pipInputConsumer.layout(mInputTransaction, mTmpRect); + mPipInputConsumer.layout(mInputTransaction, mTmpRect); // The touchable region is relative to the surface top-left mTmpRect.offsetTo(0, 0); - pipInputConsumer.mWindowHandle.touchableRegion.set(mTmpRect); - pipInputConsumer.show(mInputTransaction, w); + mPipInputConsumer.mWindowHandle.touchableRegion.set(mTmpRect); + mPipInputConsumer.show(mInputTransaction, w); mAddPipInputConsumerHandle = false; } } - if (mAddInputConsumerHandle) { - navInputConsumer.show(mInputTransaction, w); - mAddInputConsumerHandle = false; + if (mAddNavInputConsumerHandle) { + mNavInputConsumer.show(mInputTransaction, w); + mAddNavInputConsumerHandle = false; } if (mAddWallpaperInputConsumerHandle) { if (w.mAttrs.type == TYPE_WALLPAPER && w.isVisibleLw()) { // Add the wallpaper input consumer above the first visible wallpaper. - wallpaperInputConsumer.show(mInputTransaction, w); + mWallpaperInputConsumer.show(mInputTransaction, w); mAddWallpaperInputConsumerHandle = false; } } @@ -531,13 +539,13 @@ final class InputMonitor { if ((privateFlags & PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS) != 0) { mDisableWallpaperTouchEvents = true; } - final boolean hasWallpaper = wallpaperController.isWallpaperTarget(w) + final boolean hasWallpaper = mWallpaperController.isWallpaperTarget(w) && !mService.mPolicy.isKeyguardShowing() && !mDisableWallpaperTouchEvents; // If there's a drag in progress and 'child' is a potential drop target, // make sure it's been told about the drag - if (inDrag && isVisible && w.getDisplayContent().isDefaultDisplay) { + if (mInDrag && isVisible && w.getDisplayContent().isDefaultDisplay) { mService.mDragDropController.sendDragStartedIfNeededLocked(w); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 633098566b1b0..a1fd98ec4ab03 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -229,7 +229,6 @@ import android.view.InputApplicationHandle; import android.view.InputChannel; import android.view.InputDevice; import android.view.InputEvent; -import android.view.InputEventReceiver; import android.view.InputWindowHandle; import android.view.InsetsState; import android.view.KeyEvent; @@ -5741,20 +5740,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - @Override - public WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name, - InputEventReceiver.Factory inputEventReceiverFactory, int displayId) { - synchronized (mGlobalLock) { - DisplayContent displayContent = mRoot.getDisplayContent(displayId); - if (displayContent != null) { - return displayContent.getInputMonitor().createInputConsumer(looper, name, - inputEventReceiverFactory); - } else { - return null; - } - } - } - @Override public void createInputConsumer(IBinder token, String name, int displayId, InputChannel inputChannel) {