diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 5810642402a31..bc0bf8c41d3ce 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -304,7 +304,7 @@ interface IWindowSession { * an input channel where the client can receive input. */ void grantInputChannel(int displayId, in SurfaceControl surface, in IWindow window, - in IBinder hostInputToken, int flags, int privateFlags, int type, + in IBinder hostInputToken, int flags, int privateFlags, int inputFeatures, int type, in IBinder windowToken, in IBinder focusGrantToken, String inputHandleName, out InputChannel outInputChannel); @@ -312,7 +312,8 @@ interface IWindowSession { * Update the flags on an input channel associated with a particular surface. */ oneway void updateInputChannel(in IBinder channelToken, int displayId, - in SurfaceControl surface, int flags, int privateFlags, in Region region); + in SurfaceControl surface, int flags, int privateFlags, int inputFeatures, + in Region region); /** * Transfer window focus to an embedded window if the calling window has focus. diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index b157ea0c641fb..9e998cec2dbf9 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -139,7 +139,7 @@ public class WindowlessWindowManager implements IWindowSession { try { mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, state.mSurfaceControl, state.mParams.flags, state.mParams.privateFlags, - state.mInputRegion); + state.mParams.inputFeatures, state.mInputRegion); } catch (RemoteException e) { Log.e(TAG, "Failed to update surface input channel: ", e); } @@ -189,12 +189,13 @@ public class WindowlessWindowManager implements IWindowSession { mRealWm.grantInputChannel(displayId, new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"), window, mHostInputToken, - attrs.flags, attrs.privateFlags, attrs.type, attrs.token, - mFocusGrantToken, attrs.getTitle().toString(), outInputChannel); + attrs.flags, attrs.privateFlags, attrs.inputFeatures, attrs.type, + attrs.token, mFocusGrantToken, attrs.getTitle().toString(), + outInputChannel); } else { mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags, - attrs.privateFlags, attrs.type, attrs.token, mFocusGrantToken, - attrs.getTitle().toString(), outInputChannel); + attrs.privateFlags, attrs.inputFeatures, attrs.type, attrs.token, + mFocusGrantToken, attrs.getTitle().toString(), outInputChannel); } } catch (RemoteException e) { Log.e(TAG, "Failed to grant input to surface: ", e); @@ -381,16 +382,19 @@ public class WindowlessWindowManager implements IWindowSession { outMergedConfiguration.setConfiguration(mConfiguration, mConfiguration); } - if ((attrChanges & WindowManager.LayoutParams.FLAGS_CHANGED) != 0 - && state.mInputChannelToken != null) { + final int inputChangeMask = WindowManager.LayoutParams.FLAGS_CHANGED + | WindowManager.LayoutParams.INPUT_FEATURES_CHANGED; + if ((attrChanges & inputChangeMask) != 0 && state.mInputChannelToken != null) { try { - if(mRealWm instanceof IWindowSession.Stub) { + if (mRealWm instanceof IWindowSession.Stub) { mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, new SurfaceControl(sc, "WindowlessWindowManager.relayout"), - attrs.flags, attrs.privateFlags, state.mInputRegion); + attrs.flags, attrs.privateFlags, attrs.inputFeatures, + state.mInputRegion); } else { mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, sc, - attrs.flags, attrs.privateFlags, state.mInputRegion); + attrs.flags, attrs.privateFlags, attrs.inputFeatures, + state.mInputRegion); } } catch (RemoteException e) { Log.e(TAG, "Failed to update surface input channel: ", e); @@ -564,14 +568,14 @@ public class WindowlessWindowManager implements IWindowSession { @Override public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window, - IBinder hostInputToken, int flags, int privateFlags, int type, + IBinder hostInputToken, int flags, int privateFlags, int inputFeatures, int type, IBinder windowToken, IBinder focusGrantToken, String inputHandleName, InputChannel outInputChannel) { } @Override public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, - int flags, int privateFlags, Region region) { + int flags, int privateFlags, int inputFeatures, Region region) { } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java index 0a9c3310a883d..8cb575cc96e33 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java @@ -103,6 +103,7 @@ class DragResizeInputListener implements AutoCloseable { null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, + 0 /* inputFeatures */, TYPE_APPLICATION, null /* windowToken */, mFocusGrantToken, @@ -208,6 +209,7 @@ class DragResizeInputListener implements AutoCloseable { mDecorationSurface, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, + 0 /* inputFeatures */, touchRegion); } catch (RemoteException e) { e.rethrowFromSystemServer(); diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index ce9bff8521e63..75961f74a3c46 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -862,7 +862,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type, - IBinder windowToken, IBinder focusGrantToken, String inputHandleName, + int inputFeatures, IBinder windowToken, IBinder focusGrantToken, String inputHandleName, InputChannel outInputChannel) { if (hostInputToken == null && !mCanAddInternalSystemWindow) { // Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to @@ -874,7 +874,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { try { mService.grantInputChannel(this, mUid, mPid, displayId, surface, window, hostInputToken, flags, mCanAddInternalSystemWindow ? privateFlags : 0, - type, windowToken, focusGrantToken, inputHandleName, + type, inputFeatures, windowToken, focusGrantToken, inputHandleName, outInputChannel); } finally { Binder.restoreCallingIdentity(identity); @@ -883,11 +883,11 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, - int flags, int privateFlags, Region region) { + int flags, int privateFlags, int inputFeatures, Region region) { final long identity = Binder.clearCallingIdentity(); try { mService.updateInputChannel(channelToken, displayId, surface, flags, - mCanAddInternalSystemWindow ? privateFlags : 0, region); + mCanAddInternalSystemWindow ? privateFlags : 0, inputFeatures, region); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 98563f6e73fca..05aed30b1f080 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -8753,8 +8753,8 @@ public class WindowManagerService extends IWindowManager.Stub */ void grantInputChannel(Session session, int callingUid, int callingPid, int displayId, SurfaceControl surface, IWindow window, IBinder hostInputToken, - int flags, int privateFlags, int type, IBinder windowToken, IBinder focusGrantToken, - String inputHandleName, InputChannel outInputChannel) { + int flags, int privateFlags, int inputFeatures, int type, IBinder windowToken, + IBinder focusGrantToken, String inputHandleName, InputChannel outInputChannel) { final int sanitizedType = sanitizeWindowType(session, displayId, windowToken, type); final InputApplicationHandle applicationHandle; final String name; @@ -8771,7 +8771,7 @@ public class WindowManagerService extends IWindowManager.Stub } updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface, - name, applicationHandle, flags, privateFlags, sanitizedType, + name, applicationHandle, flags, privateFlags, inputFeatures, sanitizedType, null /* region */, window); clientChannel.copyTo(outInputChannel); @@ -8812,13 +8812,14 @@ public class WindowManagerService extends IWindowManager.Stub private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid, int displayId, SurfaceControl surface, String name, InputApplicationHandle applicationHandle, int flags, - int privateFlags, int type, Region region, IWindow window) { + int privateFlags, int inputFeatures, int type, Region region, IWindow window) { final InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId); h.token = channelToken; h.setWindowToken(window); h.name = name; flags = sanitizeFlagSlippery(flags, name, callingUid, callingPid); + inputFeatures = sanitizeSpyWindow(inputFeatures, name, callingUid, callingPid); final int sanitizedLpFlags = (flags & (FLAG_NOT_TOUCHABLE | FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE)) @@ -8828,7 +8829,7 @@ public class WindowManagerService extends IWindowManager.Stub // Do not allow any input features to be set without sanitizing them first. h.inputConfig = InputConfigAdapter.getInputConfigFromWindowParams( - type, sanitizedLpFlags, 0 /*inputFeatures*/); + type, sanitizedLpFlags, inputFeatures); if ((flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0) { @@ -8865,7 +8866,7 @@ public class WindowManagerService extends IWindowManager.Stub * is undefined. */ void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, - int flags, int privateFlags, Region region) { + int flags, int privateFlags, int inputFeatures, Region region) { final InputApplicationHandle applicationHandle; final String name; final EmbeddedWindowController.EmbeddedWindow win; @@ -8880,7 +8881,8 @@ public class WindowManagerService extends IWindowManager.Stub } updateInputChannel(channelToken, win.mOwnerUid, win.mOwnerPid, displayId, surface, name, - applicationHandle, flags, privateFlags, win.mWindowType, region, win.mClient); + applicationHandle, flags, privateFlags, inputFeatures, win.mWindowType, region, + win.mClient); } /** Return whether layer tracing is enabled */ 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 7d6cf4a63c43d..677ec46007ff1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -26,7 +26,10 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLI import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.FLAG_OWN_FOCUS; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; +import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; 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_BASE_APPLICATION; @@ -49,11 +52,13 @@ 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.assertNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -67,12 +72,16 @@ import android.hardware.display.VirtualDisplay; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; +import android.os.InputConfig; +import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; import android.util.MergedConfiguration; +import android.view.IWindow; import android.view.IWindowSessionCallback; +import android.view.InputChannel; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.Surface; @@ -690,6 +699,102 @@ public class WindowManagerServiceTests extends WindowTestsBase { assertEquals(validRect, resultingArgs.mSourceCrop); } + @Test + public void testGrantInputChannel_sanitizeSpyWindowForApplications() { + final Session session = mock(Session.class); + final int callingUid = Process.FIRST_APPLICATION_UID; + final int callingPid = 1234; + final SurfaceControl surfaceControl = mock(SurfaceControl.class); + final IWindow window = mock(IWindow.class); + final IBinder windowToken = mock(IBinder.class); + when(window.asBinder()).thenReturn(windowToken); + final IBinder focusGrantToken = mock(IBinder.class); + + final InputChannel inputChannel = new InputChannel(); + assertThrows(IllegalArgumentException.class, () -> + mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, + surfaceControl, window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, + PRIVATE_FLAG_TRUSTED_OVERLAY, INPUT_FEATURE_SPY, TYPE_APPLICATION, + null /* windowToken */, focusGrantToken, "TestInputChannel", + inputChannel)); + } + + @Test + public void testGrantInputChannel_allowSpyWindowForInputMonitorPermission() { + final Session session = mock(Session.class); + final int callingUid = Process.SYSTEM_UID; + final int callingPid = 1234; + final SurfaceControl surfaceControl = mock(SurfaceControl.class); + final IWindow window = mock(IWindow.class); + final IBinder windowToken = mock(IBinder.class); + when(window.asBinder()).thenReturn(windowToken); + final IBinder focusGrantToken = mock(IBinder.class); + + final InputChannel inputChannel = new InputChannel(); + mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl, + window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, + INPUT_FEATURE_SPY, TYPE_APPLICATION, null /* windowToken */, focusGrantToken, + "TestInputChannel", inputChannel); + + verify(mTransaction).setInputWindowInfo( + eq(surfaceControl), + argThat(h -> (h.inputConfig & InputConfig.SPY) == InputConfig.SPY)); + } + + @Test + public void testUpdateInputChannel_sanitizeSpyWindowForApplications() { + final Session session = mock(Session.class); + final int callingUid = Process.FIRST_APPLICATION_UID; + final int callingPid = 1234; + final SurfaceControl surfaceControl = mock(SurfaceControl.class); + final IWindow window = mock(IWindow.class); + final IBinder windowToken = mock(IBinder.class); + when(window.asBinder()).thenReturn(windowToken); + final IBinder focusGrantToken = mock(IBinder.class); + + final InputChannel inputChannel = new InputChannel(); + mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl, + window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, + 0 /* inputFeatures */, TYPE_APPLICATION, null /* windowToken */, focusGrantToken, + "TestInputChannel", inputChannel); + verify(mTransaction).setInputWindowInfo( + eq(surfaceControl), + argThat(h -> (h.inputConfig & InputConfig.SPY) == 0)); + + assertThrows(IllegalArgumentException.class, () -> + mWm.updateInputChannel(inputChannel.getToken(), DEFAULT_DISPLAY, surfaceControl, + FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, INPUT_FEATURE_SPY, + null /* region */)); + } + + @Test + public void testUpdateInputChannel_allowSpyWindowForInputMonitorPermission() { + final Session session = mock(Session.class); + final int callingUid = Process.SYSTEM_UID; + final int callingPid = 1234; + final SurfaceControl surfaceControl = mock(SurfaceControl.class); + final IWindow window = mock(IWindow.class); + final IBinder windowToken = mock(IBinder.class); + when(window.asBinder()).thenReturn(windowToken); + final IBinder focusGrantToken = mock(IBinder.class); + + final InputChannel inputChannel = new InputChannel(); + mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl, + window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, + 0 /* inputFeatures */, TYPE_APPLICATION, null /* windowToken */, focusGrantToken, + "TestInputChannel", inputChannel); + verify(mTransaction).setInputWindowInfo( + eq(surfaceControl), + argThat(h -> (h.inputConfig & InputConfig.SPY) == 0)); + + mWm.updateInputChannel(inputChannel.getToken(), DEFAULT_DISPLAY, surfaceControl, + FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, INPUT_FEATURE_SPY, + null /* region */); + verify(mTransaction).setInputWindowInfo( + eq(surfaceControl), + argThat(h -> (h.inputConfig & InputConfig.SPY) == InputConfig.SPY)); + } + private void setupActivityWithLaunchCookie(IBinder launchCookie, WindowContainerToken wct) { final WindowContainer.RemoteToken remoteToken = mock(WindowContainer.RemoteToken.class); when(remoteToken.toWindowContainerToken()).thenReturn(wct);