From ec60764ddddc9df9e795926e6760f15993a95558 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 3 Aug 2021 17:53:49 -0700 Subject: [PATCH] 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 --- core/java/android/view/KeyEvent.java | 61 +++++++++++-------- core/jni/android_view_KeyEvent.cpp | 7 +-- .../src/android/view/KeyEventTest.java | 6 +- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index cda9b233576c..d12ed8f1595e 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -31,6 +31,8 @@ import android.util.Log; import android.util.SparseIntArray; import android.view.KeyCharacterMap.KeyData; +import java.util.concurrent.TimeUnit; + /** * Object used to report key and button events. *

@@ -1298,9 +1300,16 @@ public class KeyEvent extends InputEvent implements Parcelable { private int mRepeatCount; @UnsupportedAppUsage 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; - @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; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private String mCharacters; @@ -1400,8 +1409,8 @@ public class KeyEvent extends InputEvent implements Parcelable { public KeyEvent(long downTime, long eventTime, int action, int code, int repeat) { mId = nativeNextId(); - mDownTime = downTime; - mEventTime = eventTime; + mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS); + mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS); mAction = action; mKeyCode = code; mRepeatCount = repeat; @@ -1425,8 +1434,8 @@ public class KeyEvent extends InputEvent implements Parcelable { public KeyEvent(long downTime, long eventTime, int action, int code, int repeat, int metaState) { mId = nativeNextId(); - mDownTime = downTime; - mEventTime = eventTime; + mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS); + mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS); mAction = action; mKeyCode = code; mRepeatCount = repeat; @@ -1454,8 +1463,8 @@ public class KeyEvent extends InputEvent implements Parcelable { int code, int repeat, int metaState, int deviceId, int scancode) { mId = nativeNextId(); - mDownTime = downTime; - mEventTime = eventTime; + mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS); + mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS); mAction = action; mKeyCode = code; mRepeatCount = repeat; @@ -1485,8 +1494,8 @@ public class KeyEvent extends InputEvent implements Parcelable { int code, int repeat, int metaState, int deviceId, int scancode, int flags) { mId = nativeNextId(); - mDownTime = downTime; - mEventTime = eventTime; + mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS); + mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS); mAction = action; mKeyCode = code; mRepeatCount = repeat; @@ -1518,8 +1527,8 @@ public class KeyEvent extends InputEvent implements Parcelable { int code, int repeat, int metaState, int deviceId, int scancode, int flags, int source) { mId = nativeNextId(); - mDownTime = downTime; - mEventTime = eventTime; + mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS); + mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS); mAction = action; mKeyCode = code; mRepeatCount = repeat; @@ -1545,8 +1554,8 @@ public class KeyEvent extends InputEvent implements Parcelable { */ public KeyEvent(long time, String characters, int deviceId, int flags) { mId = nativeNextId(); - mDownTime = time; - mEventTime = time; + mDownTime = TimeUnit.NANOSECONDS.convert(time, TimeUnit.MILLISECONDS); + mEventTime = TimeUnit.NANOSECONDS.convert(time, TimeUnit.MILLISECONDS); mCharacters = characters; mAction = ACTION_MULTIPLE; mKeyCode = KEYCODE_UNKNOWN; @@ -1592,7 +1601,7 @@ public class KeyEvent extends InputEvent implements Parcelable { public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) { mId = nativeNextId(); // Not an exact copy so assign a new ID. mDownTime = origEvent.mDownTime; - mEventTime = eventTime; + mEventTime = TimeUnit.NANOSECONDS.convert(eventTime, TimeUnit.MILLISECONDS); mAction = origEvent.mAction; mKeyCode = origEvent.mKeyCode; mRepeatCount = newRepeat; @@ -1626,14 +1635,14 @@ public class KeyEvent extends InputEvent implements Parcelable { * * @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 deviceId, int scancode, int flags, int source, int displayId, @Nullable byte[] hmac, String characters) { KeyEvent ev = obtain(); ev.mId = id; - ev.mDownTime = downTime; - ev.mEventTime = eventTime; + ev.mDownTime = downTimeNanos; + ev.mEventTime = eventTimeNanos; ev.mAction = action; ev.mKeyCode = code; ev.mRepeatCount = repeat; @@ -1656,6 +1665,8 @@ public class KeyEvent extends InputEvent implements Parcelable { public static KeyEvent obtain(long downTime, long eventTime, int action, int code, int repeat, int metaState, 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, 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, int code, int repeat, int metaState, 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, flags, source, INVALID_DISPLAY, characters); } @@ -1768,7 +1781,7 @@ public class KeyEvent extends InputEvent implements Parcelable { int newRepeat, int newFlags) { KeyEvent ret = new KeyEvent(event); 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.mFlags = newFlags; return ret; @@ -2617,8 +2630,8 @@ public class KeyEvent extends InputEvent implements Parcelable { * @hide */ public final void setTime(long downTime, long eventTime) { - mDownTime = downTime; - mEventTime = eventTime; + mDownTime = TimeUnit.NANOSECONDS.convert(downTime, TimeUnit.MILLISECONDS); + 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 */ 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 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 public final long getEventTimeNano() { - return mEventTime * 1000000L; + return mEventTime; } /** diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp index 8177ec6df803..2ef9632f0e31 100644 --- a/core/jni/android_view_KeyEvent.cpp +++ b/core/jni/android_view_KeyEvent.cpp @@ -98,9 +98,7 @@ jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) { ScopedLocalRef hmac = toJbyteArray(env, event->getHmac()); jobject eventObj = env->CallStaticObjectMethod(gKeyEventClassInfo.clazz, gKeyEventClassInfo.obtain, - event->getId(), - nanoseconds_to_milliseconds(event->getDownTime()), - nanoseconds_to_milliseconds(event->getEventTime()), + event->getId(), event->getDownTime(), event->getEventTime(), event->getAction(), event->getKeyCode(), event->getRepeatCount(), event->getMetaState(), 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); event->initialize(id, deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode, - metaState, repeatCount, milliseconds_to_nanoseconds(downTime), - milliseconds_to_nanoseconds(eventTime)); + metaState, repeatCount, downTime, eventTime); return OK; } diff --git a/core/tests/coretests/src/android/view/KeyEventTest.java b/core/tests/coretests/src/android/view/KeyEventTest.java index 623008eafe10..98ab592e344f 100644 --- a/core/tests/coretests/src/android/view/KeyEventTest.java +++ b/core/tests/coretests/src/android/view/KeyEventTest.java @@ -36,7 +36,6 @@ import java.util.Set; @RunWith(AndroidJUnit4.class) public class KeyEventTest { - private static final int ID = 0xabcdef; private static final int DOWN_TIME = 50; private static final long EVENT_TIME = 100; 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 FLAGS = 0; private static final int SOURCE = InputDevice.SOURCE_KEYBOARD; - private static final byte[] HMAC = null; private static final String CHARACTERS = null; private static final int ID_SOURCE_MASK = 0x3 << 30; @@ -164,8 +162,8 @@ public class KeyEventTest { } private static KeyEvent createKey() { - return KeyEvent.obtain(ID, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE, - DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, HMAC, CHARACTERS); + return KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE, + DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, CHARACTERS); } private static void compareKeys(KeyEvent key1, KeyEvent key2) {