From 88f9f15233ef1c1debcdea6124496ab32b3968f6 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 22 Nov 2021 14:05:17 -0800 Subject: [PATCH 1/2] Implement gesture monitors using spy windows Bug: 162194035 Test: manual, presubmit Change-Id: I9673b49d50dc163150ffb5bb10a378e66a7d3bfb --- .../server/input/GestureMonitorSpyWindow.java | 92 ++++++++++++ .../server/input/InputManagerService.java | 141 +++++++++++++++--- .../server/wm/InputManagerCallback.java | 20 +++ 3 files changed, 232 insertions(+), 21 deletions(-) create mode 100644 services/core/java/com/android/server/input/GestureMonitorSpyWindow.java diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java new file mode 100644 index 0000000000000..9d6764eb9cdf1 --- /dev/null +++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.input; + +import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; + +import android.view.InputApplicationHandle; +import android.view.InputChannel; +import android.view.InputMonitor; +import android.view.InputWindowHandle; +import android.view.SurfaceControl; +import android.view.WindowManager; + +/** + * An internal implementation of an {@link InputMonitor} that uses a spy window. + * + * This spy window is a layer container in the SurfaceFlinger hierarchy that does not have any + * graphical buffer, but can still receive input. It is parented to the DisplayContent so + * that it can spy on any pointer events that start in the DisplayContent bounds. When the + * object is constructed, it will add itself to SurfaceFlinger. + */ +class GestureMonitorSpyWindow { + final InputApplicationHandle mApplicationHandle; + final InputWindowHandle mWindowHandle; + + // The InputChannel and SurfaceControl are owned by this object. + final InputChannel mClientChannel; + final SurfaceControl mInputSurface; + + GestureMonitorSpyWindow(String name, int displayId, int pid, int uid, SurfaceControl sc, + InputChannel inputChannel) { + mClientChannel = inputChannel; + mInputSurface = sc; + + mApplicationHandle = new InputApplicationHandle(null, name, + DEFAULT_DISPATCHING_TIMEOUT_MILLIS); + mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId); + + mWindowHandle.name = name; + mWindowHandle.token = mClientChannel.getToken(); + mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; + mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; + mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; + mWindowHandle.visible = true; + mWindowHandle.focusable = false; + mWindowHandle.hasWallpaper = false; + mWindowHandle.paused = false; + mWindowHandle.ownerPid = pid; + mWindowHandle.ownerUid = uid; + mWindowHandle.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_SPY; + mWindowHandle.scaleFactor = 1.0f; + mWindowHandle.trustedOverlay = true; + mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */); + + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + t.setInputWindowInfo(mInputSurface, mWindowHandle); + t.setLayer(mInputSurface, Integer.MAX_VALUE); + t.setPosition(mInputSurface, 0, 0); + t.setCrop(mInputSurface, null /* crop to parent surface */); + t.show(mInputSurface); + + t.apply(); + } + + void remove() { + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + t.hide(mInputSurface); + t.remove(mInputSurface); + t.apply(); + + mClientChannel.dispose(); + } + + String dump() { + return "name='" + mWindowHandle.name + "', inputChannelToken=" + + mClientChannel.getToken() + " displayId=" + mWindowHandle.displayId; + } +} diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 783a88ca29bf7..98c4e9db04e69 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -150,6 +150,8 @@ public class InputManagerService extends IInputManager.Stub static final String TAG = "InputManager"; static final boolean DEBUG = false; + private static final boolean USE_SPY_WINDOW_GESTURE_MONITORS = false; + private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml"; @@ -277,6 +279,12 @@ public class InputManagerService extends IInputManager.Stub @GuardedBy("mPointerDisplayIdLock") private int mOverriddenPointerDisplayId = Display.INVALID_DISPLAY; + + // Holds all the registered gesture monitors that are implemented as spy windows. The spy + // windows are mapped by their InputChannel tokens. + @GuardedBy("mInputMonitors") + final Map mInputMonitors = new HashMap<>(); + private static native long nativeInit(InputManagerService service, Context context, MessageQueue messageQueue); private static native void nativeStart(long ptr); @@ -716,33 +724,68 @@ public class InputManagerService extends IInputManager.Stub inputChannelName, Binder.getCallingPid()); } + @NonNull + private InputChannel createSpyWindowGestureMonitor(String name, int displayId, int pid, + int uid) { + final SurfaceControl sc = mWindowManagerCallbacks.createSurfaceForGestureMonitor(name, + displayId); + if (sc == null) { + throw new IllegalArgumentException( + "Could not create gesture monitor surface on display: " + displayId); + } + final InputChannel channel = createInputChannel(name); + + synchronized (mInputMonitors) { + mInputMonitors.put(channel.getToken(), + new GestureMonitorSpyWindow(name, displayId, pid, uid, sc, channel)); + } + + final InputChannel outInputChannel = new InputChannel(); + channel.copyTo(outInputChannel); + return outInputChannel; + } + + private void removeSpyWindowGestureMonitor(IBinder inputChannelToken) { + final GestureMonitorSpyWindow monitor; + synchronized (mInputMonitors) { + monitor = mInputMonitors.remove(inputChannelToken); + } + removeInputChannel(inputChannelToken); + if (monitor == null) return; + monitor.remove(); + } + /** * Creates an input monitor that will receive pointer events for the purposes of system-wide * gesture interpretation. * - * @param inputChannelName The input channel name. + * @param requestedName The input channel name. * @param displayId Target display id. * @return The input channel. */ @Override // Binder call - public InputMonitor monitorGestureInput(String inputChannelName, int displayId) { + public InputMonitor monitorGestureInput(@NonNull String requestedName, int displayId) { if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT, - "monitorInputRegion()")) { + "monitorGestureInput()")) { throw new SecurityException("Requires MONITOR_INPUT permission"); } - Objects.requireNonNull(inputChannelName, "inputChannelName must not be null."); + Objects.requireNonNull(requestedName, "name must not be null."); if (displayId < Display.DEFAULT_DISPLAY) { throw new IllegalArgumentException("displayId must >= 0."); } + final String name = "[Gesture Monitor] " + requestedName; final int pid = Binder.getCallingPid(); + final int uid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { - InputChannel inputChannel = nativeCreateInputMonitor( - mPtr, displayId, true /*isGestureMonitor*/, inputChannelName, pid); - InputMonitorHost host = new InputMonitorHost(inputChannel.getToken()); - return new InputMonitor(inputChannel, host); + final InputChannel inputChannel = + USE_SPY_WINDOW_GESTURE_MONITORS + ? createSpyWindowGestureMonitor(name, displayId, pid, uid) + : nativeCreateInputMonitor(mPtr, displayId, true /*isGestureMonitor*/, + requestedName, pid); + return new InputMonitor(inputChannel, new InputMonitorHost(inputChannel.getToken())); } finally { Binder.restoreCallingIdentity(ident); } @@ -2563,37 +2606,51 @@ public class InputManagerService extends IInputManager.Stub String dumpStr = nativeDump(mPtr); if (dumpStr != null) { pw.println(dumpStr); - dumpAssociations(pw); } + + pw.println("Input Manager Service (Java) State:"); + dumpAssociations(pw, " " /*prefix*/); + dumpSpyWindowGestureMonitors(pw, " " /*prefix*/); } - private void dumpAssociations(PrintWriter pw) { + private void dumpAssociations(PrintWriter pw, String prefix) { if (!mStaticAssociations.isEmpty()) { - pw.println("Static Associations:"); + pw.println(prefix + "Static Associations:"); mStaticAssociations.forEach((k, v) -> { - pw.print(" port: " + k); + pw.print(prefix + " port: " + k); pw.println(" display: " + v); }); } synchronized (mAssociationsLock) { if (!mRuntimeAssociations.isEmpty()) { - pw.println("Runtime Associations:"); + pw.println(prefix + "Runtime Associations:"); mRuntimeAssociations.forEach((k, v) -> { - pw.print(" port: " + k); + pw.print(prefix + " port: " + k); pw.println(" display: " + v); }); } if (!mUniqueIdAssociations.isEmpty()) { - pw.println("Unique Id Associations:"); + pw.println(prefix + "Unique Id Associations:"); mUniqueIdAssociations.forEach((k, v) -> { - pw.print(" port: " + k); + pw.print(prefix + " port: " + k); pw.println(" uniqueId: " + v); }); } } } + private void dumpSpyWindowGestureMonitors(PrintWriter pw, String prefix) { + synchronized (mInputMonitors) { + if (mInputMonitors.isEmpty()) return; + pw.println(prefix + "Gesture Monitors (implemented as spy windows):"); + int i = 0; + for (final GestureMonitorSpyWindow monitor : mInputMonitors.values()) { + pw.append(prefix + " " + i++ + ": ").println(monitor.dump()); + } + } + } + private boolean checkCallingPermission(String permission, String func) { // Quick check: if the calling permission is me, it's all okay. if (Binder.getCallingPid() == Process.myPid()) { @@ -2618,6 +2675,7 @@ public class InputManagerService extends IInputManager.Stub synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */} synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ } synchronized (mPointerDisplayIdLock) { /* Test if blocked by pointer display id lock */ } + synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ } nativeMonitor(mPtr); } @@ -2686,6 +2744,11 @@ public class InputManagerService extends IInputManager.Stub // Native callback. private void notifyInputChannelBroken(IBinder token) { + synchronized (mInputMonitors) { + if (mInputMonitors.containsKey(token)) { + removeSpyWindowGestureMonitor(token); + } + } mWindowManagerCallbacks.notifyInputChannelBroken(token); } @@ -2721,6 +2784,17 @@ public class InputManagerService extends IInputManager.Stub // Native callback private void notifyWindowUnresponsive(IBinder token, String reason) { + int gestureMonitorPid = -1; + synchronized (mInputMonitors) { + final GestureMonitorSpyWindow gestureMonitor = mInputMonitors.get(token); + if (gestureMonitor != null) { + gestureMonitorPid = gestureMonitor.mWindowHandle.ownerPid; + } + } + if (gestureMonitorPid != -1) { + mWindowManagerCallbacks.notifyGestureMonitorUnresponsive(gestureMonitorPid, reason); + return; + } mWindowManagerCallbacks.notifyWindowUnresponsive(token, reason); } @@ -2731,6 +2805,17 @@ public class InputManagerService extends IInputManager.Stub // Native callback private void notifyWindowResponsive(IBinder token) { + int gestureMonitorPid = -1; + synchronized (mInputMonitors) { + final GestureMonitorSpyWindow gestureMonitor = mInputMonitors.get(token); + if (gestureMonitor != null) { + gestureMonitorPid = gestureMonitor.mWindowHandle.ownerPid; + } + } + if (gestureMonitorPid != -1) { + mWindowManagerCallbacks.notifyGestureMonitorResponsive(gestureMonitorPid); + return; + } mWindowManagerCallbacks.notifyWindowResponsive(token); } @@ -3184,6 +3269,16 @@ public class InputManagerService extends IInputManager.Stub * pointers such as the mouse cursor and touch spots for the given display. */ SurfaceControl getParentSurfaceForPointers(int displayId); + + /** + * Create a {@link SurfaceControl} that can be configured to receive input over the entire + * display to implement a gesture monitor. The surface will not have a graphical buffer. + * @param name the name of the gesture monitor + * @param displayId the display to create the window in + * @return the SurfaceControl of the new layer container surface + */ + @Nullable + SurfaceControl createSurfaceForGestureMonitor(String name, int displayId); } /** @@ -3258,20 +3353,24 @@ public class InputManagerService extends IInputManager.Stub * Interface for the system to handle request from InputMonitors. */ private final class InputMonitorHost extends IInputMonitorHost.Stub { - private final IBinder mToken; + private final IBinder mInputChannelToken; - InputMonitorHost(IBinder token) { - mToken = token; + InputMonitorHost(IBinder inputChannelToken) { + mInputChannelToken = inputChannelToken; } @Override public void pilferPointers() { - nativePilferPointers(mPtr, mToken); + nativePilferPointers(mPtr, mInputChannelToken); } @Override public void dispose() { - nativeRemoveInputChannel(mPtr, mToken); + if (USE_SPY_WINDOW_GESTURE_MONITORS) { + removeSpyWindowGestureMonitor(mInputChannelToken); + return; + } + nativeRemoveInputChannel(mPtr, mInputChannelToken); } } diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index f91969b2c5587..1f0fdcf0a8d2c 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -24,6 +24,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.ON_POINTER_DOWN_OUTSIDE_FOCUS; import android.annotation.NonNull; +import android.annotation.Nullable; import android.graphics.PointF; import android.os.Debug; import android.os.IBinder; @@ -254,6 +255,25 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal } } + @Override + @Nullable + public SurfaceControl createSurfaceForGestureMonitor(String name, int displayId) { + synchronized (mService.mGlobalLock) { + final DisplayContent dc = mService.mRoot.getDisplayContent(displayId); + if (dc == null) { + Slog.e(TAG, "Failed to create a gesture monitor on display: " + displayId + + " - DisplayContent not found."); + return null; + } + return mService.makeSurfaceBuilder(dc.getSession()) + .setContainerLayer() + .setName(name) + .setCallsite("createSurfaceForGestureMonitor") + .setParent(dc.getSurfaceControl()) + .build(); + } + } + /** Waits until the built-in input devices have been configured. */ public boolean waitForInputDevicesReady(long timeoutMillis) { synchronized (mInputDevicesReadyMonitor) { From c809658285896757e331c869c64d1f01eb129ef9 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 23 Nov 2021 10:26:38 -0800 Subject: [PATCH 2/2] Use binder tokens to remove its gesture monitors if a process dies Bug: 162194035 Test: manual: "adb shell am crash com.android.systemui" and observe its gesture monitors are removed through dumpsys input Change-Id: I02a480dd8e4b98a9911d976de2684d283c9e7d8b --- .../android/hardware/input/IInputManager.aidl | 2 +- .../android/hardware/input/InputManager.java | 3 ++- core/java/android/view/InputMonitor.java | 20 +++++++++++++------ .../server/input/GestureMonitorSpyWindow.java | 9 ++++++--- .../server/input/InputManagerService.java | 19 +++++++++++++----- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 27403ec4fe59f..e1ffd4a6761df 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -112,7 +112,7 @@ interface IInputManager { oneway void requestPointerCapture(IBinder inputChannelToken, boolean enabled); /** Create an input monitor for gestures. */ - InputMonitor monitorGestureInput(String name, int displayId); + InputMonitor monitorGestureInput(IBinder token, String name, int displayId); // Add a runtime association between the input port and the display port. This overrides any // static associations. diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 979e9dd6a1f64..2fd79cf980c70 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -35,6 +35,7 @@ import android.hardware.lights.Light; import android.hardware.lights.LightState; import android.hardware.lights.LightsManager; import android.hardware.lights.LightsRequest; +import android.os.Binder; import android.os.BlockUntrustedTouchesMode; import android.os.Build; import android.os.CombinedVibration; @@ -1211,7 +1212,7 @@ public final class InputManager { */ public InputMonitor monitorGestureInput(String name, int displayId) { try { - return mIm.monitorGestureInput(name, displayId); + return mIm.monitorGestureInput(new Binder(), name, displayId); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } diff --git a/core/java/android/view/InputMonitor.java b/core/java/android/view/InputMonitor.java index ad1f201ba3c1c..8801fe0b47c8d 100644 --- a/core/java/android/view/InputMonitor.java +++ b/core/java/android/view/InputMonitor.java @@ -79,13 +79,17 @@ public final class InputMonitor implements Parcelable { - // Code below generated by codegen v1.0.7. + // Code below generated by codegen v1.0.23. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code // // To regenerate run: // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/InputMonitor.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off @DataClass.Generated.Member @@ -126,7 +130,7 @@ public final class InputMonitor implements Parcelable { @Override @DataClass.Generated.Member - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { // You can override field parcelling by defining methods like: // void parcelFieldName(Parcel dest, int flags) { ... } @@ -141,7 +145,7 @@ public final class InputMonitor implements Parcelable { /** @hide */ @SuppressWarnings({"unchecked", "RedundantCast"}) @DataClass.Generated.Member - /* package-private */ InputMonitor(Parcel in) { + /* package-private */ InputMonitor(@NonNull Parcel in) { // You can override field unparcelling by defining methods like: // static FieldType unparcelFieldName(Parcel in) { ... } @@ -167,17 +171,21 @@ public final class InputMonitor implements Parcelable { } @Override - public InputMonitor createFromParcel(Parcel in) { + public InputMonitor createFromParcel(@NonNull Parcel in) { return new InputMonitor(in); } }; @DataClass.Generated( - time = 1571177265149L, - codegenVersion = "1.0.7", + time = 1637697281750L, + codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/view/InputMonitor.java", inputSignatures = "private static final java.lang.String TAG\nprivate static final boolean DEBUG\nprivate final @android.annotation.NonNull android.view.InputChannel mInputChannel\nprivate final @android.annotation.NonNull android.view.IInputMonitorHost mHost\npublic void pilferPointers()\npublic void dispose()\nclass InputMonitor extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true)") @Deprecated private void __metadata() {} + + //@formatter:on + // End of generated code + } diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java index 9d6764eb9cdf1..dbd3f3529208f 100644 --- a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java +++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java @@ -18,6 +18,7 @@ package com.android.server.input; import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; +import android.os.IBinder; import android.view.InputApplicationHandle; import android.view.InputChannel; import android.view.InputMonitor; @@ -37,12 +38,14 @@ class GestureMonitorSpyWindow { final InputApplicationHandle mApplicationHandle; final InputWindowHandle mWindowHandle; - // The InputChannel and SurfaceControl are owned by this object. + // The token, InputChannel, and SurfaceControl are owned by this object. + final IBinder mMonitorToken; final InputChannel mClientChannel; final SurfaceControl mInputSurface; - GestureMonitorSpyWindow(String name, int displayId, int pid, int uid, SurfaceControl sc, - InputChannel inputChannel) { + GestureMonitorSpyWindow(IBinder token, String name, int displayId, int pid, int uid, + SurfaceControl sc, InputChannel inputChannel) { + mMonitorToken = token; mClientChannel = inputChannel; mInputSurface = sc; diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 98c4e9db04e69..64b4da7c5bba2 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -725,8 +725,8 @@ public class InputManagerService extends IInputManager.Stub } @NonNull - private InputChannel createSpyWindowGestureMonitor(String name, int displayId, int pid, - int uid) { + private InputChannel createSpyWindowGestureMonitor(IBinder monitorToken, String name, + int displayId, int pid, int uid) { final SurfaceControl sc = mWindowManagerCallbacks.createSurfaceForGestureMonitor(name, displayId); if (sc == null) { @@ -735,9 +735,16 @@ public class InputManagerService extends IInputManager.Stub } final InputChannel channel = createInputChannel(name); + try { + monitorToken.linkToDeath(() -> removeSpyWindowGestureMonitor(channel.getToken()), 0); + } catch (RemoteException e) { + Slog.i(TAG, "Client died before '" + name + "' could be created."); + return null; + } synchronized (mInputMonitors) { mInputMonitors.put(channel.getToken(), - new GestureMonitorSpyWindow(name, displayId, pid, uid, sc, channel)); + new GestureMonitorSpyWindow(monitorToken, name, displayId, pid, uid, sc, + channel)); } final InputChannel outInputChannel = new InputChannel(); @@ -764,12 +771,14 @@ public class InputManagerService extends IInputManager.Stub * @return The input channel. */ @Override // Binder call - public InputMonitor monitorGestureInput(@NonNull String requestedName, int displayId) { + public InputMonitor monitorGestureInput(IBinder monitorToken, @NonNull String requestedName, + int displayId) { if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT, "monitorGestureInput()")) { throw new SecurityException("Requires MONITOR_INPUT permission"); } Objects.requireNonNull(requestedName, "name must not be null."); + Objects.requireNonNull(monitorToken, "token must not be null."); if (displayId < Display.DEFAULT_DISPLAY) { throw new IllegalArgumentException("displayId must >= 0."); @@ -782,7 +791,7 @@ public class InputManagerService extends IInputManager.Stub try { final InputChannel inputChannel = USE_SPY_WINDOW_GESTURE_MONITORS - ? createSpyWindowGestureMonitor(name, displayId, pid, uid) + ? createSpyWindowGestureMonitor(monitorToken, name, displayId, pid, uid) : nativeCreateInputMonitor(mPtr, displayId, true /*isGestureMonitor*/, requestedName, pid); return new InputMonitor(inputChannel, new InputMonitorHost(inputChannel.getToken()));