Merge "Ensure handwriting session can only be started from inside app bounds" into tm-dev am: a4f617f451

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17071330

Change-Id: I1c1c6d919286fb01648e0167993c4e5cb1b8ce37
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Prabir Pradhan
2022-03-28 19:46:07 +00:00
committed by Automerger Merge Worker
6 changed files with 116 additions and 14 deletions

View File

@@ -164,6 +164,38 @@ public final class InputWindowHandle {
this.displayId = displayId;
}
public InputWindowHandle(InputWindowHandle other) {
// Do not copy ptr to prevent this copy from sharing the same native object.
ptr = 0;
inputApplicationHandle = new InputApplicationHandle(other.inputApplicationHandle);
token = other.token;
windowToken = other.windowToken;
window = other.window;
name = other.name;
layoutParamsFlags = other.layoutParamsFlags;
layoutParamsType = other.layoutParamsType;
dispatchingTimeoutMillis = other.dispatchingTimeoutMillis;
frameLeft = other.frameLeft;
frameTop = other.frameTop;
frameRight = other.frameRight;
frameBottom = other.frameBottom;
surfaceInset = other.surfaceInset;
scaleFactor = other.scaleFactor;
touchableRegion.set(other.touchableRegion);
inputConfig = other.inputConfig;
touchOcclusionMode = other.touchOcclusionMode;
ownerPid = other.ownerPid;
ownerUid = other.ownerUid;
packageName = other.packageName;
displayId = other.displayId;
touchableRegionSurfaceControl = other.touchableRegionSurfaceControl;
replaceTouchableRegionWithCrop = other.replaceTouchableRegionWithCrop;
if (other.transform != null) {
transform = new Matrix();
transform.set(other.transform);
}
}
@Override
public String toString() {
return new StringBuilder(name != null ? name : "")

View File

@@ -27,7 +27,6 @@ import android.view.InputWindowHandle;
import android.view.SurfaceControl;
import android.view.WindowManager;
final class HandwritingEventReceiverSurface {
public static final String TAG = HandwritingEventReceiverSurface.class.getSimpleName();
@@ -39,7 +38,6 @@ final class HandwritingEventReceiverSurface {
// TODO(b/217538817): Specify the ordering in WM by usage.
private static final int HANDWRITING_SURFACE_LAYER = Integer.MAX_VALUE - 1;
private final InputApplicationHandle mApplicationHandle;
private final InputWindowHandle mWindowHandle;
private final InputChannel mClientChannel;
private final SurfaceControl mInputSurface;
@@ -47,13 +45,11 @@ final class HandwritingEventReceiverSurface {
HandwritingEventReceiverSurface(String name, int displayId, @NonNull SurfaceControl sc,
@NonNull InputChannel inputChannel) {
mApplicationHandle = new InputApplicationHandle(null, name,
DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
mClientChannel = inputChannel;
mInputSurface = sc;
mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
mWindowHandle = new InputWindowHandle(new InputApplicationHandle(null, name,
DEFAULT_DISPATCHING_TIMEOUT_MILLIS), displayId);
mWindowHandle.name = name;
mWindowHandle.token = mClientChannel.getToken();
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
@@ -61,7 +57,6 @@ final class HandwritingEventReceiverSurface {
mWindowHandle.ownerPid = Process.myPid();
mWindowHandle.ownerUid = Process.myUid();
mWindowHandle.scaleFactor = 1.0f;
mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
mWindowHandle.inputConfig =
InputConfig.NOT_FOCUSABLE
| InputConfig.NOT_TOUCHABLE
@@ -69,6 +64,7 @@ final class HandwritingEventReceiverSurface {
| InputConfig.INTERCEPTS_STYLUS
| InputConfig.TRUSTED_OVERLAY;
// The touchable region of this input surface is not initially configured.
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.setInputWindowInfo(mInputSurface, mWindowHandle);
t.setLayer(mInputSurface, HANDWRITING_SURFACE_LAYER);
@@ -85,6 +81,10 @@ final class HandwritingEventReceiverSurface {
mWindowHandle.ownerUid = imeUid;
mWindowHandle.inputConfig &= ~InputConfig.SPY;
// Update the touchable region so that the IME can intercept stylus events
// across the entire display.
mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
new SurfaceControl.Transaction()
.setInputWindowInfo(mInputSurface, mWindowHandle)
.apply();
@@ -108,4 +108,8 @@ final class HandwritingEventReceiverSurface {
SurfaceControl getSurface() {
return mInputSurface;
}
InputWindowHandle getInputWindowHandle() {
return mWindowHandle;
}
}

View File

@@ -22,6 +22,7 @@ import android.annotation.AnyThread;
import android.annotation.Nullable;
import android.annotation.UiThread;
import android.hardware.input.InputManagerInternal;
import android.os.IBinder;
import android.os.Looper;
import android.util.Slog;
import android.view.BatchedInputEventReceiver;
@@ -90,7 +91,7 @@ final class HandwritingModeController {
* InputEventReceiver that batches events according to the current thread's Choreographer.
*/
@UiThread
void initializeHandwritingSpy(int displayId) {
void initializeHandwritingSpy(int displayId, IBinder focusedWindowToken) {
// When resetting, reuse resources if we are reinitializing on the same display.
reset(displayId == mCurrentDisplayId);
mCurrentDisplayId = displayId;
@@ -110,8 +111,16 @@ final class HandwritingModeController {
Slog.e(TAG, "Failed to create input surface");
return;
}
mHandwritingSurface =
new HandwritingEventReceiverSurface(name, displayId, surface, channel);
mHandwritingSurface = new HandwritingEventReceiverSurface(
name, displayId, surface, channel);
// Configure the handwriting window to receive events over the focused window's bounds.
mWindowManagerInternal.replaceInputSurfaceTouchableRegionWithWindowCrop(
mHandwritingSurface.getSurface(),
mHandwritingSurface.getInputWindowHandle(),
focusedWindowToken);
// Use a dup of the input channel so that event processing can be paused by disposing the
// event receiver without causing a fd hangup.
mHandwritingEventReceiver = new BatchedInputEventReceiver.SimpleBatchedInputEventReceiver(
@@ -127,6 +136,10 @@ final class HandwritingModeController {
return OptionalInt.of(mCurrentRequestId);
}
boolean isStylusGestureOngoing() {
return mRecordingGesture;
}
/**
* Starts a {@link HandwritingSession} to transfer to the IME.
*
@@ -145,6 +158,10 @@ final class HandwritingModeController {
Slog.e(TAG, "Cannot start handwriting session: Invalid request id: " + requestId);
return null;
}
if (!mRecordingGesture) {
Slog.e(TAG, "Cannot start handwriting session: No stylus gesture is being recorded.");
return null;
}
Objects.requireNonNull(mHandwritingEventReceiver,
"Handwriting session was already transferred to IME.");
if (DEBUG) Slog.d(TAG, "Starting handwriting session in display: " + mCurrentDisplayId);
@@ -231,7 +248,7 @@ final class HandwritingModeController {
mInkWindowInitRunnable = null;
}
if (action == MotionEvent.ACTION_UP) {
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
mRecordingGesture = false;
mHandwritingBuffer.clear();
return;

View File

@@ -3439,6 +3439,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
Slog.e(TAG, "Stylus handwriting was not initialized.");
return;
}
if (!mHwController.isStylusGestureOngoing()) {
Slog.e(TAG, "There is no ongoing stylus gesture to start stylus handwriting.");
return;
}
if (DEBUG) Slog.v(TAG, "Client requesting Stylus Handwriting to be started");
final IInputMethodInvoker curMethod = getCurMethodLocked();
if (curMethod != null) {
@@ -4829,8 +4833,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
case MSG_RESET_HANDWRITING: {
synchronized (ImfLock.class) {
if (mBindingController.supportsStylusHandwriting()
&& getCurMethodLocked() != null) {
mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
&& getCurMethodLocked() != null && mCurFocusedWindow != null) {
mHwController.initializeHandwritingSpy(
mCurTokenDisplayId, mCurFocusedWindow);
} else {
mHwController.reset();
}
@@ -4858,7 +4863,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
session.getHandwritingChannel(), session.getRecordedEvents())) {
// When failed to issue IPCs, re-initialize handwriting state.
Slog.w(TAG, "Resetting handwriting mode.");
mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
scheduleResetStylusHandwriting();
}
}
return true;

View File

@@ -33,6 +33,7 @@ import android.view.IInputFilter;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IWindow;
import android.view.InputChannel;
import android.view.InputWindowHandle;
import android.view.MagnificationSpec;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
@@ -853,4 +854,26 @@ public abstract class WindowManagerInternal {
* support handwriting (Scribe) by the IME.
*/
public abstract SurfaceControl getHandwritingSurfaceForDisplay(int displayId);
/**
* Replaces the touchable region of the provided input surface with the crop of the window with
* the provided token. This method will associate the inputSurface with a copy of
* the given inputWindowHandle, where the copy is configured using
* {@link InputWindowHandle#replaceTouchableRegionWithCrop(SurfaceControl)} with the surface
* of the provided windowToken.
*
* This is a no-op if windowToken is not valid or the window is not found.
*
* This does not change any other properties of the inputSurface.
*
* This method exists to avoid leaking the window's SurfaceControl outside WindowManagerService.
*
* @param inputSurface The surface for which the touchable region should be set.
* @param inputWindowHandle The {@link InputWindowHandle} for the input surface.
* @param windowToken The window whose bounds should be used as the touchable region for the
* inputSurface.
*/
public abstract void replaceInputSurfaceTouchableRegionWithWindowCrop(
@NonNull SurfaceControl inputSurface, @NonNull InputWindowHandle inputWindowHandle,
@NonNull IBinder windowToken);
}

View File

@@ -8162,6 +8162,27 @@ public class WindowManagerService extends IWindowManager.Stub
.build();
}
}
@Override
public void replaceInputSurfaceTouchableRegionWithWindowCrop(
@NonNull SurfaceControl inputSurface,
@NonNull InputWindowHandle inputWindowHandle,
@NonNull IBinder windowToken) {
synchronized (mGlobalLock) {
final WindowState w = mWindowMap.get(windowToken);
if (w == null) {
return;
}
// Make a copy of the InputWindowHandle to avoid leaking the window's
// SurfaceControl.
final InputWindowHandle localHandle = new InputWindowHandle(inputWindowHandle);
localHandle.replaceTouchableRegionWithCrop(w.getSurfaceControl());
final SurfaceControl.Transaction t = mTransactionFactory.get();
t.setInputWindowInfo(inputSurface, localHandle);
t.apply();
t.close();
}
}
}
void registerAppFreezeListener(AppFreezeListener listener) {