Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3181d745 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Verify KeyEvents in IME" into main

parents d6e830bb 1a0e562b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -21049,6 +21049,7 @@ package android.inputmethodservice {
    method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface();
    method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
    method public boolean onGenericMotionEvent(android.view.MotionEvent);
    method @FlaggedApi("android.view.inputmethod.verify_key_event") public boolean onShouldVerifyKeyEvent(@NonNull android.view.KeyEvent);
    method public boolean onTrackballEvent(android.view.MotionEvent);
  }
@@ -21066,6 +21067,7 @@ package android.inputmethodservice {
    method public void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
    method public boolean isEnabled();
    method public boolean isRevoked();
    method @FlaggedApi("android.view.inputmethod.verify_key_event") public boolean onShouldVerifyKeyEvent(@NonNull android.view.KeyEvent);
    method public void revokeSelf();
    method public void setEnabled(boolean);
  }
+17 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package android.inputmethodservice;

import static android.view.inputmethod.Flags.FLAG_VERIFY_KEY_EVENT;

import android.annotation.FlaggedApi;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -193,6 +196,12 @@ public abstract class AbstractInputMethodService extends WindowProviderService
            }
        }

        @FlaggedApi(FLAG_VERIFY_KEY_EVENT)
        @Override
        public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) {
            return AbstractInputMethodService.this.onShouldVerifyKeyEvent(event);
        }

        /**
         * Take care of dispatching incoming trackball events to the appropriate
         * callbacks on the service, and tell the client when this is done.
@@ -308,6 +317,14 @@ public abstract class AbstractInputMethodService extends WindowProviderService
        return false;
    }

    /**
     * @see InputMethodService#onShouldVerifyKeyEvent(KeyEvent)
     */
    @FlaggedApi(FLAG_VERIFY_KEY_EVENT)
    public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) {
        return false;
    }

    /** @hide */
    @Override
    public final int getWindowType() {
+41 −2
Original line number Diff line number Diff line
@@ -16,12 +16,16 @@

package android.inputmethodservice;

import static android.view.inputmethod.Flags.verifyKeyEvent;

import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
import android.view.InputChannel;
@@ -41,6 +45,8 @@ import com.android.internal.inputmethod.IRemoteInputConnection;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;

import java.util.Objects;

class IInputMethodSessionWrapper extends IInputMethodSession.Stub
        implements HandlerCaller.Callback {
    private static final String TAG = "InputMethodWrapper";
@@ -56,6 +62,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
    private static final int DO_REMOVE_IME_SURFACE = 130;
    private static final int DO_FINISH_INPUT = 140;
    private static final int DO_INVALIDATE_INPUT = 150;
    private final Context mContext;


    @UnsupportedAppUsage
@@ -66,6 +73,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub

    public IInputMethodSessionWrapper(Context context,
            InputMethodSession inputMethodSession, InputChannel channel) {
        mContext = context;
        mCaller = new HandlerCaller(context, null,
                this, true /*asyncHandler*/);
        mInputMethodSession = inputMethodSession;
@@ -233,6 +241,8 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
    }
    private final class ImeInputEventReceiver extends InputEventReceiver
            implements InputMethodSession.EventCallback {
        // Time after which a KeyEvent is invalid
        private static final long KEY_EVENT_ALLOW_PERIOD_MS = 100L;
        private final SparseArray<InputEvent> mPendingEvents = new SparseArray<InputEvent>();

        public ImeInputEventReceiver(InputChannel inputChannel, Looper looper) {
@@ -247,10 +257,23 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
                return;
            }

            if (event instanceof KeyEvent keyEvent && needsVerification(keyEvent)) {
                // any KeyEvent with modifiers (e.g. Ctrl/Alt/Fn) must be verified that
                // they originated from system.
                InputManager im = mContext.getSystemService(InputManager.class);
                Objects.requireNonNull(im);
                final long age = SystemClock.uptimeMillis() - keyEvent.getEventTime();
                if (age >= KEY_EVENT_ALLOW_PERIOD_MS && im.verifyInputEvent(keyEvent) == null) {
                    Log.w(TAG, "Unverified or Invalid KeyEvent injected into IME. Dropping "
                            + keyEvent);
                    finishInputEvent(event, false /* handled */);
                    return;
                }
            }

            final int seq = event.getSequenceNumber();
            mPendingEvents.put(seq, event);
            if (event instanceof KeyEvent) {
                KeyEvent keyEvent = (KeyEvent)event;
            if (event instanceof KeyEvent keyEvent) {
                mInputMethodSession.dispatchKeyEvent(seq, keyEvent, this);
            } else {
                MotionEvent motionEvent = (MotionEvent)event;
@@ -271,5 +294,21 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
                finishInputEvent(event, handled);
            }
        }

        private boolean hasKeyModifiers(KeyEvent event) {
            if (event.hasNoModifiers()) {
                return false;
            }
            return event.hasModifiers(KeyEvent.META_CTRL_ON)
                    || event.hasModifiers(KeyEvent.META_ALT_ON)
                    || event.hasModifiers(KeyEvent.KEYCODE_FUNCTION);
        }

        private boolean needsVerification(KeyEvent event) {
            //TODO(b/331730488): Handle a11y events as well.
            return verifyKeyEvent()
                    && (hasKeyModifiers(event)
                            || mInputMethodSession.onShouldVerifyKeyEvent(event));
        }
    }
}
+18 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECT
import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED;
import static android.view.inputmethod.Flags.FLAG_CONNECTIONLESS_HANDWRITING;
import static android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP_API;
import static android.view.inputmethod.Flags.FLAG_VERIFY_KEY_EVENT;
import static android.view.inputmethod.Flags.ctrlShiftShortcut;
import static android.view.inputmethod.Flags.predictiveBackIme;

@@ -3734,6 +3735,23 @@ public class InputMethodService extends AbstractInputMethodService {
        return doMovementKey(keyCode, event, MOVEMENT_DOWN);
    }

    /**
     * Received by the IME before dispatch to {@link #onKeyDown(int, KeyEvent)} to let the system
     * know if the {@link KeyEvent} needs to be verified that it originated from the system.
     * {@link KeyEvent}s may originate from outside of the system and any sensitive keys should be
     * marked for verification. One example of this could be using key shortcuts for switching to
     * another IME.
     *
     * @param keyEvent the event that may need verification.
     * @return {@code true} if {@link KeyEvent} should have its HMAC verified before dispatch,
     * {@code false} otherwise.
     */
    @FlaggedApi(FLAG_VERIFY_KEY_EVENT)
    @Override
    public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent keyEvent) {
        return false;
    }

    /**
     * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
     * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
+6 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.view.inputmethod;

import android.annotation.NonNull;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
import android.os.Bundle;
@@ -124,6 +125,11 @@ public interface InputMethodSession {
     */
    public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback);

    /**
     * @hide
     */
    boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event);

    /**
     * This method is called when there is a track ball event.
     *
Loading