From c8362b24f672710a96b12c004577c91da587f0f8 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Fri, 24 Jan 2020 11:32:14 -0800 Subject: [PATCH] Add ID to InputEvent. The interaction between Java and native code for KeyEvent and MotionEvent is different, so I used different arrangement to pass sequence number across JNI that keeps the consistency with other metadata. Unfortunately this new ID doesn't have absolute uniqueness guarantee so it can't replace InputEvent#getSequenceNumber() which is used with a strict in-process uniqueness assumption. Therefore only convert systrace related use to ID. Also expose ID generator through a static function in InputEvent so that everyone can use it. InputReader and InputDispatcher will use different instances. Bug: 144889238 Test: Build and run. Test: atest FrameworksCoreTests:KeyEventTest Test: atest FrameworksCoreTests:MotionEventTest Change-Id: Icbdcaee1d98948c05484865a4e15e55161ecfa69 Merged-In: Icbdcaee1d98948c05484865a4e15e55161ecfa69 (cherry picked from 29d21d4062f90a1c79971e5380426fc54b307807) --- core/java/android/view/InputEvent.java | 15 +++++ core/java/android/view/KeyEvent.java | 45 ++++++++++++-- core/java/android/view/MotionEvent.java | 8 +++ core/java/android/view/ViewRootImpl.java | 10 +-- core/jni/android_view_KeyEvent.cpp | 20 ++++-- core/jni/android_view_MotionEvent.cpp | 13 +++- .../src/android/view/KeyEventTest.java | 61 +++++++++++++++++-- .../src/android/view/MotionEventTest.java | 31 ++++++++++ .../server/policy/PhoneWindowManager.java | 2 +- 9 files changed, 182 insertions(+), 23 deletions(-) diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java index 5f9c4801ee66..cb9e746543f6 100644 --- a/core/java/android/view/InputEvent.java +++ b/core/java/android/view/InputEvent.java @@ -233,6 +233,21 @@ public abstract class InputEvent implements Parcelable { return mSeq; } + /** + * Gets the ID of this event. This is generated when an event is created and preserved until its + * last stage. It won't change just because the event crosses process boundary, but should + * change when making a copy with modifications. + *

+ * To avoid exposing app usage to other processes this ID is generated from a CSPRNG. Therefore + * there isn't 100% guarantee on the uniqueness of this ID, though the chance of ID collisions + * is considerably low. The rule of thumb is not to rely on the uniqueness for production logic, + * but a good source for tracking an event (e.g. logging and profiling). + * + * @return The ID of this event. + * @hide + */ + public abstract int getId(); + public int describeContents() { return 0; } diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index c91096e5aa25..9e344e8d2f75 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -1265,6 +1265,7 @@ public class KeyEvent extends InputEvent implements Parcelable { private KeyEvent mNext; + private int mId; @UnsupportedAppUsage private int mDeviceId; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) @@ -1350,9 +1351,9 @@ public class KeyEvent extends InputEvent implements Parcelable { private static native String nativeKeyCodeToString(int keyCode); private static native int nativeKeyCodeFromString(String keyCode); + private static native int nativeNextId(); - private KeyEvent() { - } + private KeyEvent() {} /** * Create a new key event. @@ -1362,6 +1363,7 @@ public class KeyEvent extends InputEvent implements Parcelable { * @param code The key code. */ public KeyEvent(int action, int code) { + mId = nativeNextId(); mAction = action; mKeyCode = code; mRepeatCount = 0; @@ -1383,6 +1385,7 @@ 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; mAction = action; @@ -1407,6 +1410,7 @@ 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; mAction = action; @@ -1435,6 +1439,7 @@ public class KeyEvent extends InputEvent implements Parcelable { public KeyEvent(long downTime, long eventTime, int action, int code, int repeat, int metaState, int deviceId, int scancode) { + mId = nativeNextId(); mDownTime = downTime; mEventTime = eventTime; mAction = action; @@ -1465,6 +1470,7 @@ public class KeyEvent extends InputEvent implements Parcelable { public KeyEvent(long downTime, long eventTime, int action, int code, int repeat, int metaState, int deviceId, int scancode, int flags) { + mId = nativeNextId(); mDownTime = downTime; mEventTime = eventTime; mAction = action; @@ -1497,6 +1503,7 @@ public class KeyEvent extends InputEvent implements Parcelable { public KeyEvent(long downTime, long eventTime, int action, int code, int repeat, int metaState, int deviceId, int scancode, int flags, int source) { + mId = nativeNextId(); mDownTime = downTime; mEventTime = eventTime; mAction = action; @@ -1523,6 +1530,7 @@ public class KeyEvent extends InputEvent implements Parcelable { * @param flags The flags for this key event */ public KeyEvent(long time, String characters, int deviceId, int flags) { + mId = nativeNextId(); mDownTime = time; mEventTime = time; mCharacters = characters; @@ -1539,6 +1547,7 @@ public class KeyEvent extends InputEvent implements Parcelable { * Make an exact copy of an existing key event. */ public KeyEvent(KeyEvent origEvent) { + mId = origEvent.mId; mDownTime = origEvent.mDownTime; mEventTime = origEvent.mEventTime; mAction = origEvent.mAction; @@ -1567,6 +1576,7 @@ public class KeyEvent extends InputEvent implements Parcelable { */ @Deprecated public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) { + mId = nativeNextId(); // Not an exact copy so assign a new ID. mDownTime = origEvent.mDownTime; mEventTime = eventTime; mAction = origEvent.mAction; @@ -1598,15 +1608,16 @@ public class KeyEvent extends InputEvent implements Parcelable { } /** - * Obtains a (potentially recycled) key event. + * Obtains a (potentially recycled) key event. Used by native code to create a Java object. * * @hide */ - public static KeyEvent obtain(long downTime, long eventTime, int action, + public static KeyEvent obtain(int id, long downTime, long eventTime, 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.mAction = action; @@ -1623,6 +1634,18 @@ public class KeyEvent extends InputEvent implements Parcelable { return ev; } + /** + * Obtains a (potentially recycled) key event. + * + * @hide + */ + 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) { + return obtain(nativeNextId(), downTime, eventTime, action, code, repeat, metaState, + deviceId, scanCode, flags, source, displayId, null /* hmac */, characters); + } + /** * Obtains a (potentially recycled) key event. * @@ -1633,7 +1656,7 @@ public class KeyEvent extends InputEvent implements Parcelable { int code, int repeat, int metaState, int deviceId, int scancode, int flags, int source, String characters) { return obtain(downTime, eventTime, action, code, repeat, metaState, deviceId, scancode, - flags, source, INVALID_DISPLAY, null /* hmac */, characters); + flags, source, INVALID_DISPLAY, characters); } /** @@ -1645,6 +1668,7 @@ public class KeyEvent extends InputEvent implements Parcelable { */ public static KeyEvent obtain(KeyEvent other) { KeyEvent ev = obtain(); + ev.mId = other.mId; ev.mDownTime = other.mDownTime; ev.mEventTime = other.mEventTime; ev.mAction = other.mAction; @@ -1695,6 +1719,12 @@ public class KeyEvent extends InputEvent implements Parcelable { // Do nothing. } + /** @hide */ + @Override + public int getId() { + return mId; + } + /** * Create a new key event that is the same as the given one, but whose * event time and repeat count are replaced with the given value. @@ -1723,6 +1753,7 @@ public class KeyEvent extends InputEvent implements Parcelable { public static KeyEvent changeTimeRepeat(KeyEvent event, long eventTime, 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.mRepeatCount = newRepeat; ret.mFlags = newFlags; @@ -1736,6 +1767,7 @@ public class KeyEvent extends InputEvent implements Parcelable { * @param action The new action code of the event. */ private KeyEvent(KeyEvent origEvent, int action) { + mId = nativeNextId(); // Not an exact copy so assign a new ID. mDownTime = origEvent.mDownTime; mEventTime = origEvent.mEventTime; mAction = action; @@ -1772,6 +1804,7 @@ public class KeyEvent extends InputEvent implements Parcelable { */ public static KeyEvent changeFlags(KeyEvent event, int flags) { event = new KeyEvent(event); + event.mId = nativeNextId(); // Not an exact copy so assign a new ID. event.mFlags = flags; return event; } @@ -3096,6 +3129,7 @@ public class KeyEvent extends InputEvent implements Parcelable { } private KeyEvent(Parcel in) { + mId = in.readInt(); mDeviceId = in.readInt(); mSource = in.readInt(); mDisplayId = in.readInt(); @@ -3115,6 +3149,7 @@ public class KeyEvent extends InputEvent implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(PARCEL_TOKEN_KEY_EVENT); + out.writeInt(mId); out.writeInt(mDeviceId); out.writeInt(mSource); out.writeInt(mDisplayId); diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 006847656cac..19eff72ca814 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -1550,6 +1550,8 @@ public final class MotionEvent extends InputEvent implements Parcelable { private static native long nativeCopy(long destNativePtr, long sourceNativePtr, boolean keepHistory); @CriticalNative + private static native int nativeGetId(long nativePtr); + @CriticalNative private static native int nativeGetDeviceId(long nativePtr); @CriticalNative private static native int nativeGetSource(long nativePtr); @@ -2024,6 +2026,12 @@ public final class MotionEvent extends InputEvent implements Parcelable { } } + /** @hide */ + @Override + public int getId() { + return nativeGetId(mNativePtr); + } + /** {@inheritDoc} */ @Override public final int getDeviceId() { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 4a093e6038b8..918b5a35d4db 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -5379,7 +5379,8 @@ public final class ViewRootImpl implements ViewParent, if (mTracePrefix == null) { mTracePrefix = getClass().getSimpleName(); } - Trace.traceBegin(traceTag, mTracePrefix + " seq#=" + q.mEvent.getSequenceNumber()); + Trace.traceBegin(traceTag, mTracePrefix + " id=0x" + + Integer.toHexString(q.mEvent.getId())); } } @@ -7986,12 +7987,13 @@ public final class ViewRootImpl implements ViewParent, private void deliverInputEvent(QueuedInputEvent q) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent", - q.mEvent.getSequenceNumber()); + q.mEvent.getId()); if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x" + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano=" - + q.mEvent.getEventTimeNano() + " seq#=" + q.mEvent.getSequenceNumber()); + + q.mEvent.getEventTimeNano() + " id=0x" + + Integer.toHexString(q.mEvent.getId())); } try { if (mInputEventConsistencyVerifier != null) { @@ -8032,7 +8034,7 @@ public final class ViewRootImpl implements ViewParent, private void finishInputEvent(QueuedInputEvent q) { Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent", - q.mEvent.getSequenceNumber()); + q.mEvent.getId()); if (q.mReceiver != null) { boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0; diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp index bbe563e12a4c..54567e5010c5 100644 --- a/core/jni/android_view_KeyEvent.cpp +++ b/core/jni/android_view_KeyEvent.cpp @@ -75,6 +75,7 @@ static struct { jmethodID obtain; jmethodID recycle; + jfieldID mId; jfieldID mDeviceId; jfieldID mSource; jfieldID mDisplayId; @@ -96,6 +97,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->getAction(), event->getKeyCode(), @@ -114,6 +116,7 @@ jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) { status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, KeyEvent* event) { + jint id = env->GetIntField(eventObj, gKeyEventClassInfo.mId); jint deviceId = env->GetIntField(eventObj, gKeyEventClassInfo.mDeviceId); jint source = env->GetIntField(eventObj, gKeyEventClassInfo.mSource); jint displayId = env->GetIntField(eventObj, gKeyEventClassInfo.mDisplayId); @@ -131,7 +134,7 @@ status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, jlong downTime = env->GetLongField(eventObj, gKeyEventClassInfo.mDownTime); jlong eventTime = env->GetLongField(eventObj, gKeyEventClassInfo.mEventTime); - event->initialize(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), milliseconds_to_nanoseconds(eventTime)); return OK; @@ -159,14 +162,18 @@ static jint android_view_KeyEvent_nativeKeyCodeFromString(JNIEnv* env, jobject c return KeyEvent::getKeyCodeFromLabel(keyLabel.c_str()); } +static jint android_view_KeyEvent_nativeNextId() { + return static_cast(InputEvent::nextId()); +} // ---------------------------------------------------------------------------- static const JNINativeMethod g_methods[] = { - { "nativeKeyCodeToString", "(I)Ljava/lang/String;", - (void*)android_view_KeyEvent_nativeKeyCodeToString}, - { "nativeKeyCodeFromString", "(Ljava/lang/String;)I", - (void*)android_view_KeyEvent_nativeKeyCodeFromString}, + {"nativeKeyCodeToString", "(I)Ljava/lang/String;", + (void*)android_view_KeyEvent_nativeKeyCodeToString}, + {"nativeKeyCodeFromString", "(Ljava/lang/String;)I", + (void*)android_view_KeyEvent_nativeKeyCodeFromString}, + {"nativeNextId", "()I", (void*)android_view_KeyEvent_nativeNextId}, }; int register_android_view_KeyEvent(JNIEnv* env) { @@ -175,10 +182,11 @@ int register_android_view_KeyEvent(JNIEnv* env) { gKeyEventClassInfo.obtain = GetStaticMethodIDOrDie(env, gKeyEventClassInfo.clazz, "obtain", - "(JJIIIIIIIII[BLjava/lang/String;)Landroid/view/KeyEvent;"); + "(IJJIIIIIIIII[BLjava/lang/String;)Landroid/view/KeyEvent;"); gKeyEventClassInfo.recycle = GetMethodIDOrDie(env, gKeyEventClassInfo.clazz, "recycle", "()V"); + gKeyEventClassInfo.mId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mId", "I"); gKeyEventClassInfo.mDeviceId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDeviceId", "I"); gKeyEventClassInfo.mSource = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mSource", "I"); gKeyEventClassInfo.mDisplayId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDisplayId", diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 3335fb23cfb7..9816d713c6dc 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -369,9 +369,10 @@ static jlong android_view_MotionEvent_nativeInitialize( env->DeleteLocalRef(pointerCoordsObj); } - event->initialize(deviceId, source, displayId, INVALID_HMAC, action, 0, flags, edgeFlags, - metaState, buttonState, static_cast(classification), - 1 /*xScale*/, 1 /*yScale*/, xOffset, yOffset, xPrecision, yPrecision, + event->initialize(InputEvent::nextId(), deviceId, source, displayId, INVALID_HMAC, action, 0, + flags, edgeFlags, metaState, buttonState, + static_cast(classification), 1 /*xScale*/, 1 /*yScale*/, + xOffset, yOffset, xPrecision, yPrecision, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, downTimeNanos, eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords); @@ -592,6 +593,11 @@ static jlong android_view_MotionEvent_nativeCopy(jlong destNativePtr, jlong sour return reinterpret_cast(destEvent); } +static jint android_view_MotionEvent_nativeGetId(jlong nativePtr) { + MotionEvent* event = reinterpret_cast(nativePtr); + return event->getId(); +} + static jint android_view_MotionEvent_nativeGetDeviceId(jlong nativePtr) { MotionEvent* event = reinterpret_cast(nativePtr); return event->getDeviceId(); @@ -790,6 +796,7 @@ static const JNINativeMethod gMotionEventMethods[] = { // --------------- @CriticalNative ------------------ {"nativeCopy", "(JJZ)J", (void*)android_view_MotionEvent_nativeCopy}, + {"nativeGetId", "(J)I", (void*)android_view_MotionEvent_nativeGetId}, {"nativeGetDeviceId", "(J)I", (void*)android_view_MotionEvent_nativeGetDeviceId}, {"nativeGetSource", "(J)I", (void*)android_view_MotionEvent_nativeGetSource}, {"nativeSetSource", "(JI)V", (void*)android_view_MotionEvent_nativeSetSource}, diff --git a/core/tests/coretests/src/android/view/KeyEventTest.java b/core/tests/coretests/src/android/view/KeyEventTest.java index 14999c7f5642..623008eafe10 100644 --- a/core/tests/coretests/src/android/view/KeyEventTest.java +++ b/core/tests/coretests/src/android/view/KeyEventTest.java @@ -19,6 +19,7 @@ package android.view; import static android.view.Display.INVALID_DISPLAY; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import android.os.Parcel; @@ -28,10 +29,14 @@ import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.HashSet; +import java.util.Set; + @SmallTest @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; @@ -45,6 +50,8 @@ public class KeyEventTest { private static final byte[] HMAC = null; private static final String CHARACTERS = null; + private static final int ID_SOURCE_MASK = 0x3 << 30; + @Test public void testObtain() { KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, @@ -75,8 +82,7 @@ public class KeyEventTest { public void testObtainWithDisplayId() { final int displayId = 5; KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, - METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, displayId, null /* hmac*/, - CHARACTERS); + METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, displayId, CHARACTERS); assertEquals(DOWN_TIME, keyEvent.getDownTime()); assertEquals(EVENT_TIME, keyEvent.getEventTime()); assertEquals(ACTION, keyEvent.getAction()); @@ -91,6 +97,52 @@ public class KeyEventTest { assertEquals(CHARACTERS, keyEvent.getCharacters()); } + /** + * Tests that it can generate 500 consecutive distinct numbers. This is a non-deterministic test + * but with 30 bits randomness the failure rate is roughly 4.52e-5, which is negligible enough. + * Probability formula: N * (N - 1) * ... * (N - n + 1) / N^n, where N = 2^30 and n = 500 for + * this test. + */ + @Test + public void testObtainGeneratesUniqueId() { + Set set = new HashSet<>(); + for (int i = 0; i < 500; ++i) { + KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, + METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS); + assertFalse("Found duplicate ID in round " + i, + set.contains(keyEvent.getId())); + set.add(keyEvent.getSequenceNumber()); + } + } + + @Test + public void testConstructorGeneratesUniqueId() { + Set set = new HashSet<>(); + for (int i = 0; i < 500; ++i) { + KeyEvent keyEvent = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT); + assertFalse("Found duplicate sequence number in round " + i, + set.contains(keyEvent.getId())); + set.add(keyEvent.getSequenceNumber()); + } + } + + @Test + public void testObtainGeneratesIdWithRightSource() { + for (int i = 0; i < 500; ++i) { + KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, + METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS); + assertEquals(0x3 << 30, ID_SOURCE_MASK & keyEvent.getId()); + } + } + + @Test + public void testConstructorGeneratesIdWithRightSource() { + for (int i = 0; i < 500; ++i) { + KeyEvent keyEvent = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT); + assertEquals(0x3 << 30, ID_SOURCE_MASK & keyEvent.getId()); + } + } + @Test public void testParcelUnparcel() { KeyEvent key1 = createKey(); @@ -112,11 +164,12 @@ public class KeyEventTest { } private static KeyEvent createKey() { - return KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, - METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, HMAC, CHARACTERS); + return KeyEvent.obtain(ID, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE, + DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, HMAC, CHARACTERS); } private static void compareKeys(KeyEvent key1, KeyEvent key2) { + assertEquals(key1.getId(), key2.getId()); assertEquals(key1.getDownTime(), key2.getDownTime()); assertEquals(key1.getEventTime(), key2.getEventTime()); assertEquals(key1.getAction(), key2.getAction()); diff --git a/core/tests/coretests/src/android/view/MotionEventTest.java b/core/tests/coretests/src/android/view/MotionEventTest.java index 9d09830c585b..786ae89ac2ae 100644 --- a/core/tests/coretests/src/android/view/MotionEventTest.java +++ b/core/tests/coretests/src/android/view/MotionEventTest.java @@ -23,6 +23,7 @@ import static android.view.MotionEvent.TOOL_TYPE_FINGER; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import android.view.MotionEvent.PointerCoords; @@ -34,9 +35,13 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.HashSet; +import java.util.Set; + @RunWith(AndroidJUnit4.class) @SmallTest public class MotionEventTest { + private static final int ID_SOURCE_MASK = 0x3 << 30; @Test public void testObtainWithDisplayId() { @@ -138,4 +143,30 @@ public class MotionEventTest { assertEquals(30, event.getXCursorPosition(), 0.1); assertEquals(50, event.getYCursorPosition(), 0.1); } + + /** + * Tests that it can generate 500 consecutive distinct numbers. This is a non-deterministic test + * but with 30 bits randomness the failure rate is roughly 4.52e-5, which is negligible enough. + * Probability formula: N * (N - 1) * ... * (N - n + 1) / N^n, where N = 2^30 and n = 500 for + * this test. + */ + @Test + public void testObtainGeneratesUniqueId() { + Set set = new HashSet<>(); + for (int i = 0; i < 500; ++i) { + final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */, + ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */); + assertFalse("Found duplicate ID in round " + i, set.contains(event.getId())); + set.add(event.getSequenceNumber()); + } + } + + @Test + public void testObtainGeneratesIdWithRightSource() { + for (int i = 0; i < 500; ++i) { + final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */, + ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */); + assertEquals(0x3 << 30, ID_SOURCE_MASK & event.getId()); + } + } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 19e6062401c0..96bd3afa1d13 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3085,7 +3085,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { event.getAction(), fallbackAction.keyCode, event.getRepeatCount(), fallbackAction.metaState, event.getDeviceId(), event.getScanCode(), - flags, event.getSource(), event.getDisplayId(), null /* hmac */, null); + flags, event.getSource(), event.getDisplayId(), null); if (!interceptFallback(focusedToken, fallbackEvent, policyFlags)) { fallbackEvent.recycle(); -- GitLab