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
This commit is contained in:
parent
9967c7a23a
commit
ec60764ddd
@ -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.
|
||||
* <p>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,9 +98,7 @@ jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) {
|
||||
ScopedLocalRef<jbyteArray> 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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user