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

Commit ec60764d authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

Store time in nanoseconds in KeyEvent

KeyEvent today stores time in milliseconds. That means that data is lost
when it gets sent from native to Java layers. The subsequent return
route, going from Java to native, cannot recover this data.

This causes the KeyEvents to have truncated event times when they are
inspected by InputDispatcher (for example, for injectInputEvent and
verifyInputEvent apis).

In the injectInputEvent, this is fine, because the public api to create
a KeyEvent does not allow the caller to provide nanoseconds.

For the verifyInputEvent, however, this is a problem. When the HMAC of
the provided KeyEvent is computed, it no longer matches the HMAC of the
original KeyEvent. That means that verification for KeyEvents is broken.

To fix this, we pass nanosecond values to Java layer. The fields are
already stored as 'long', so there's enough room for that. To maintain
the existing api behaviour, though, we need to convert to/from
milliseconds at the public api bondary. This specifically applies to
KeyEvent constructors, some of the 'obtain' apis, and
'getDownTime'/'getEventTime' apis.

Test: atest VerifyHardwareKeyEventTest
Bug: 194264616
Change-Id: I0c82a2f065bc947a0e48a26ae3ea5f4ef77f464f
parent 9967c7a2
Loading
Loading
Loading
Loading
+37 −24
Original line number Original line Diff line number Diff line
@@ -31,6 +31,8 @@ import android.util.Log;
import android.util.SparseIntArray;
import android.util.SparseIntArray;
import android.view.KeyCharacterMap.KeyData;
import android.view.KeyCharacterMap.KeyData;


import java.util.concurrent.TimeUnit;

/**
/**
 * Object used to report key and button events.
 * Object used to report key and button events.
 * <p>
 * <p>
@@ -1298,9 +1300,16 @@ public class KeyEvent extends InputEvent implements Parcelable {
    private int mRepeatCount;
    private int mRepeatCount;
    @UnsupportedAppUsage
    @UnsupportedAppUsage
    private int mFlags;
    private int mFlags;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    /**
     * The time when the key initially was pressed, in nanoseconds. Only millisecond precision is
     * exposed as public api, so this must always be converted to / from milliseconds when used.
     */
    private long mDownTime;
    private long mDownTime;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    /**
     * The time when the current key event occurred. If mAction is ACTION_DOWN, then this is equal
     * to mDownTime. Only millisecond precision is exposed as public api, so this must always be
     * converted to / from milliseconds when used.
     */
    private long mEventTime;
    private long mEventTime;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private String mCharacters;
    private String mCharacters;
@@ -1400,8 +1409,8 @@ public class KeyEvent extends InputEvent implements Parcelable {
    public KeyEvent(long downTime, long eventTime, int action,
    public KeyEvent(long downTime, long eventTime, int action,
                    int code, int repeat) {
                    int code, int repeat) {
        mId = nativeNextId();
        mId = nativeNextId();
        mDownTime = downTime;
        mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
        mEventTime = eventTime;
        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
        mAction = action;
        mAction = action;
        mKeyCode = code;
        mKeyCode = code;
        mRepeatCount = repeat;
        mRepeatCount = repeat;
@@ -1425,8 +1434,8 @@ public class KeyEvent extends InputEvent implements Parcelable {
    public KeyEvent(long downTime, long eventTime, int action,
    public KeyEvent(long downTime, long eventTime, int action,
                    int code, int repeat, int metaState) {
                    int code, int repeat, int metaState) {
        mId = nativeNextId();
        mId = nativeNextId();
        mDownTime = downTime;
        mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
        mEventTime = eventTime;
        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
        mAction = action;
        mAction = action;
        mKeyCode = code;
        mKeyCode = code;
        mRepeatCount = repeat;
        mRepeatCount = repeat;
@@ -1454,8 +1463,8 @@ public class KeyEvent extends InputEvent implements Parcelable {
                    int code, int repeat, int metaState,
                    int code, int repeat, int metaState,
                    int deviceId, int scancode) {
                    int deviceId, int scancode) {
        mId = nativeNextId();
        mId = nativeNextId();
        mDownTime = downTime;
        mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
        mEventTime = eventTime;
        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
        mAction = action;
        mAction = action;
        mKeyCode = code;
        mKeyCode = code;
        mRepeatCount = repeat;
        mRepeatCount = repeat;
@@ -1485,8 +1494,8 @@ public class KeyEvent extends InputEvent implements Parcelable {
                    int code, int repeat, int metaState,
                    int code, int repeat, int metaState,
                    int deviceId, int scancode, int flags) {
                    int deviceId, int scancode, int flags) {
        mId = nativeNextId();
        mId = nativeNextId();
        mDownTime = downTime;
        mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
        mEventTime = eventTime;
        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
        mAction = action;
        mAction = action;
        mKeyCode = code;
        mKeyCode = code;
        mRepeatCount = repeat;
        mRepeatCount = repeat;
@@ -1518,8 +1527,8 @@ public class KeyEvent extends InputEvent implements Parcelable {
                    int code, int repeat, int metaState,
                    int code, int repeat, int metaState,
                    int deviceId, int scancode, int flags, int source) {
                    int deviceId, int scancode, int flags, int source) {
        mId = nativeNextId();
        mId = nativeNextId();
        mDownTime = downTime;
        mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
        mEventTime = eventTime;
        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
        mAction = action;
        mAction = action;
        mKeyCode = code;
        mKeyCode = code;
        mRepeatCount = repeat;
        mRepeatCount = repeat;
@@ -1545,8 +1554,8 @@ public class KeyEvent extends InputEvent implements Parcelable {
     */
     */
    public KeyEvent(long time, String characters, int deviceId, int flags) {
    public KeyEvent(long time, String characters, int deviceId, int flags) {
        mId = nativeNextId();
        mId = nativeNextId();
        mDownTime = time;
        mDownTime = TimeUnit.NANOSECONDS.convert(time, TimeUnit.MILLISECONDS);
        mEventTime = time;
        mEventTime = TimeUnit.NANOSECONDS.convert(time, TimeUnit.MILLISECONDS);
        mCharacters = characters;
        mCharacters = characters;
        mAction = ACTION_MULTIPLE;
        mAction = ACTION_MULTIPLE;
        mKeyCode = KEYCODE_UNKNOWN;
        mKeyCode = KEYCODE_UNKNOWN;
@@ -1592,7 +1601,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
    public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) {
    public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) {
        mId = nativeNextId();  // Not an exact copy so assign a new ID.
        mId = nativeNextId();  // Not an exact copy so assign a new ID.
        mDownTime = origEvent.mDownTime;
        mDownTime = origEvent.mDownTime;
        mEventTime = eventTime;
        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
        mAction = origEvent.mAction;
        mAction = origEvent.mAction;
        mKeyCode = origEvent.mKeyCode;
        mKeyCode = origEvent.mKeyCode;
        mRepeatCount = newRepeat;
        mRepeatCount = newRepeat;
@@ -1626,14 +1635,14 @@ public class KeyEvent extends InputEvent implements Parcelable {
     *
     *
     * @hide
     * @hide
     */
     */
    public static KeyEvent obtain(int id, long downTime, long eventTime, int action,
    private static KeyEvent obtain(int id, long downTimeNanos, long eventTimeNanos, int action,
            int code, int repeat, int metaState,
            int code, int repeat, int metaState,
            int deviceId, int scancode, int flags, int source, int displayId, @Nullable byte[] hmac,
            int deviceId, int scancode, int flags, int source, int displayId, @Nullable byte[] hmac,
            String characters) {
            String characters) {
        KeyEvent ev = obtain();
        KeyEvent ev = obtain();
        ev.mId = id;
        ev.mId = id;
        ev.mDownTime = downTime;
        ev.mDownTime = downTimeNanos;
        ev.mEventTime = eventTime;
        ev.mEventTime = eventTimeNanos;
        ev.mAction = action;
        ev.mAction = action;
        ev.mKeyCode = code;
        ev.mKeyCode = code;
        ev.mRepeatCount = repeat;
        ev.mRepeatCount = repeat;
@@ -1656,6 +1665,8 @@ public class KeyEvent extends InputEvent implements Parcelable {
    public static KeyEvent obtain(long downTime, long eventTime, int action,
    public static KeyEvent obtain(long downTime, long eventTime, int action,
            int code, int repeat, int metaState,
            int code, int repeat, int metaState,
            int deviceId, int scanCode, int flags, int source, int displayId, String characters) {
            int deviceId, int scanCode, int flags, int source, int displayId, String characters) {
        downTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
        eventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
        return obtain(nativeNextId(), downTime, eventTime, action, code, repeat, metaState,
        return obtain(nativeNextId(), downTime, eventTime, action, code, repeat, metaState,
                deviceId, scanCode, flags, source, displayId, null /* hmac */, characters);
                deviceId, scanCode, flags, source, displayId, null /* hmac */, characters);
    }
    }
@@ -1669,6 +1680,8 @@ public class KeyEvent extends InputEvent implements Parcelable {
    public static KeyEvent obtain(long downTime, long eventTime, int action,
    public static KeyEvent obtain(long downTime, long eventTime, int action,
            int code, int repeat, int metaState,
            int code, int repeat, int metaState,
            int deviceId, int scancode, int flags, int source, String characters) {
            int deviceId, int scancode, int flags, int source, String characters) {
        // Do not convert downTime and eventTime here. We are calling the obtain method above,
        // which will do the conversion. Just specify INVALID_DISPLAY and forward the request.
        return obtain(downTime, eventTime, action, code, repeat, metaState, deviceId, scancode,
        return obtain(downTime, eventTime, action, code, repeat, metaState, deviceId, scancode,
                flags, source, INVALID_DISPLAY, characters);
                flags, source, INVALID_DISPLAY, characters);
    }
    }
@@ -1768,7 +1781,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
            int newRepeat, int newFlags) {
            int newRepeat, int newFlags) {
        KeyEvent ret = new KeyEvent(event);
        KeyEvent ret = new KeyEvent(event);
        ret.mId = nativeNextId();  // Not an exact copy so assign a new ID.
        ret.mId = nativeNextId();  // Not an exact copy so assign a new ID.
        ret.mEventTime = eventTime;
        ret.mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
        ret.mRepeatCount = newRepeat;
        ret.mRepeatCount = newRepeat;
        ret.mFlags = newFlags;
        ret.mFlags = newFlags;
        return ret;
        return ret;
@@ -2617,8 +2630,8 @@ public class KeyEvent extends InputEvent implements Parcelable {
     * @hide
     * @hide
     */
     */
    public final void setTime(long downTime, long eventTime) {
    public final void setTime(long downTime, long eventTime) {
        mDownTime = downTime;
        mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS);
        mEventTime = eventTime;
        mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS);
    }
    }


    /**
    /**
@@ -2633,7 +2646,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
     * {@link android.os.SystemClock#uptimeMillis} time base
     * {@link android.os.SystemClock#uptimeMillis} time base
     */
     */
    public final long getDownTime() {
    public final long getDownTime() {
        return mDownTime;
        return TimeUnit.MILLISECONDS.convert(mDownTime, TimeUnit.NANOSECONDS);
    }
    }


    /**
    /**
@@ -2645,7 +2658,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
     */
     */
    @Override
    @Override
    public final long getEventTime() {
    public final long getEventTime() {
        return mEventTime;
        return TimeUnit.MILLISECONDS.convert(mEventTime, TimeUnit.NANOSECONDS);
    }
    }


    /**
    /**
@@ -2664,7 +2677,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
     */
     */
    @Override
    @Override
    public final long getEventTimeNano() {
    public final long getEventTimeNano() {
        return mEventTime * 1000000L;
        return mEventTime;
    }
    }


    /**
    /**
+2 −5
Original line number Original line Diff line number Diff line
@@ -98,9 +98,7 @@ jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) {
    ScopedLocalRef<jbyteArray> hmac = toJbyteArray(env, event->getHmac());
    ScopedLocalRef<jbyteArray> hmac = toJbyteArray(env, event->getHmac());
    jobject eventObj =
    jobject eventObj =
            env->CallStaticObjectMethod(gKeyEventClassInfo.clazz, gKeyEventClassInfo.obtain,
            env->CallStaticObjectMethod(gKeyEventClassInfo.clazz, gKeyEventClassInfo.obtain,
                                        event->getId(),
                                        event->getId(), event->getDownTime(), event->getEventTime(),
                                        nanoseconds_to_milliseconds(event->getDownTime()),
                                        nanoseconds_to_milliseconds(event->getEventTime()),
                                        event->getAction(), event->getKeyCode(),
                                        event->getAction(), event->getKeyCode(),
                                        event->getRepeatCount(), event->getMetaState(),
                                        event->getRepeatCount(), event->getMetaState(),
                                        event->getDeviceId(), event->getScanCode(),
                                        event->getDeviceId(), event->getScanCode(),
@@ -136,8 +134,7 @@ status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
    jlong eventTime = env->GetLongField(eventObj, gKeyEventClassInfo.mEventTime);
    jlong eventTime = env->GetLongField(eventObj, gKeyEventClassInfo.mEventTime);


    event->initialize(id, deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode,
    event->initialize(id, deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode,
                      metaState, repeatCount, milliseconds_to_nanoseconds(downTime),
                      metaState, repeatCount, downTime, eventTime);
                      milliseconds_to_nanoseconds(eventTime));
    return OK;
    return OK;
}
}


+2 −4
Original line number Original line Diff line number Diff line
@@ -36,7 +36,6 @@ import java.util.Set;
@RunWith(AndroidJUnit4.class)
@RunWith(AndroidJUnit4.class)
public class KeyEventTest {
public class KeyEventTest {


    private static final int ID = 0xabcdef;
    private static final int DOWN_TIME = 50;
    private static final int DOWN_TIME = 50;
    private static final long EVENT_TIME = 100;
    private static final long EVENT_TIME = 100;
    private static final int ACTION = KeyEvent.ACTION_DOWN;
    private static final int ACTION = KeyEvent.ACTION_DOWN;
@@ -47,7 +46,6 @@ public class KeyEventTest {
    private static final int SCAN_CODE = 0;
    private static final int SCAN_CODE = 0;
    private static final int FLAGS = 0;
    private static final int FLAGS = 0;
    private static final int SOURCE = InputDevice.SOURCE_KEYBOARD;
    private static final int SOURCE = InputDevice.SOURCE_KEYBOARD;
    private static final byte[] HMAC = null;
    private static final String CHARACTERS = null;
    private static final String CHARACTERS = null;


    private static final int ID_SOURCE_MASK = 0x3 << 30;
    private static final int ID_SOURCE_MASK = 0x3 << 30;
@@ -164,8 +162,8 @@ public class KeyEventTest {
    }
    }


    private static KeyEvent createKey() {
    private static KeyEvent createKey() {
        return KeyEvent.obtain(ID, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
        return KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
                DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, HMAC, CHARACTERS);
                DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, CHARACTERS);
    }
    }


    private static void compareKeys(KeyEvent key1, KeyEvent key2) {
    private static void compareKeys(KeyEvent key1, KeyEvent key2) {