Add verifyInputEvent api to InputDispatcher

Now InputDispatcher will be able to check whether a certain InputEvent
is legitimate.
Use the 'verifyInputEvent' api to determine if a given 'InputEvent'
actually came from InputDispatcher.

Bug: 134977432
Test: atest VerifiedKeyEventTest VerifiedMotionEventTest libinput_tests
inputflinger_tests
Change-Id: I8e7fa9bfa3c14b0b0d949fb5e28b43ff7583398f
diff --git a/include/input/Input.h b/include/input/Input.h
index cf0814c..14a7288 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -73,6 +73,19 @@
     AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
 };
 
+/**
+ * Allowed VerifiedKeyEvent flags. All other flags from KeyEvent do not get verified.
+ * These values must be kept in sync with VerifiedKeyEvent.java
+ */
+constexpr int32_t VERIFIED_KEY_EVENT_FLAGS = AKEY_EVENT_FLAG_CANCELED;
+
+/**
+ * Allowed VerifiedMotionEventFlags. All other flags from MotionEvent do not get verified.
+ * These values must be kept in sync with VerifiedMotionEvent.java
+ */
+constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS =
+        AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+
 enum {
     /* Used when a motion event is not associated with any display.
      * Typically used for non-pointer events. */
@@ -718,6 +731,55 @@
     bool mInTouchMode;
 };
 
+/**
+ * Base class for verified events.
+ * Do not create a VerifiedInputEvent explicitly.
+ * Use helper functions to create them from InputEvents.
+ */
+struct __attribute__((__packed__)) VerifiedInputEvent {
+    enum class Type : int32_t {
+        KEY = AINPUT_EVENT_TYPE_KEY,
+        MOTION = AINPUT_EVENT_TYPE_MOTION,
+    };
+
+    Type type;
+    int32_t deviceId;
+    nsecs_t eventTimeNanos;
+    uint32_t source;
+    int32_t displayId;
+};
+
+/**
+ * Same as KeyEvent, but only contains the data that can be verified.
+ * If you update this class, you must also update VerifiedKeyEvent.java
+ */
+struct __attribute__((__packed__)) VerifiedKeyEvent : public VerifiedInputEvent {
+    int32_t action;
+    nsecs_t downTimeNanos;
+    int32_t flags;
+    int32_t keyCode;
+    int32_t scanCode;
+    int32_t metaState;
+    int32_t repeatCount;
+};
+
+/**
+ * Same as MotionEvent, but only contains the data that can be verified.
+ * If you update this class, you must also update VerifiedMotionEvent.java
+ */
+struct __attribute__((__packed__)) VerifiedMotionEvent : public VerifiedInputEvent {
+    float rawX;
+    float rawY;
+    int32_t actionMasked;
+    nsecs_t downTimeNanos;
+    int32_t flags;
+    int32_t metaState;
+    int32_t buttonState;
+};
+
+VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event);
+VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event);
+
 /*
  * Input event factory.
  */
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 85b0fd0..2a73dc0 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -57,6 +57,30 @@
     return "UNKNOWN";
 }
 
+VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) {
+    return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(),
+             event.getSource(), event.getDisplayId()},
+            event.getAction(),
+            event.getDownTime(),
+            event.getFlags() & VERIFIED_KEY_EVENT_FLAGS,
+            event.getKeyCode(),
+            event.getScanCode(),
+            event.getMetaState(),
+            event.getRepeatCount()};
+}
+
+VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event) {
+    return {{VerifiedInputEvent::Type::MOTION, event.getDeviceId(), event.getEventTime(),
+             event.getSource(), event.getDisplayId()},
+            event.getRawX(0),
+            event.getRawY(0),
+            event.getActionMasked(),
+            event.getDownTime(),
+            event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS,
+            event.getMetaState(),
+            event.getButtonState()};
+}
+
 void InputEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId,
                             std::array<uint8_t, 32> hmac) {
     mDeviceId = deviceId;
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index c1c35e1..fb21d5e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -10,12 +10,12 @@
         "LatencyStatistics_test.cpp",
         "TouchVideoFrame_test.cpp",
         "VelocityTracker_test.cpp",
+        "VerifiedInputEvent_test.cpp",
     ],
     cflags: [
         "-Wall",
         "-Wextra",
         "-Werror",
-        "-Wno-unused-variable",
     ],
     shared_libs: [
         "libinput",
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index dce1f29..d0f7618 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -46,7 +46,6 @@
 }
 
 TEST_F(PointerCoordsTest, AxisValues) {
-    float* valuePtr;
     PointerCoords coords;
     coords.clear();
 
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index d4bbf6c..885196f 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -38,6 +38,7 @@
     virtual void SetUp() {
         status_t result = InputChannel::openInputChannelPair("channel name",
                 serverChannel, clientChannel);
+        ASSERT_EQ(OK, result);
 
         mPublisher = new InputPublisher(serverChannel);
         mConsumer = new InputConsumer(clientChannel);
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index aa8a2d4..dd127fc 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -98,4 +98,34 @@
     static_assert(sizeof(InputMessage::Body::Focus) == 8);
 }
 
+// --- VerifiedInputEvent ---
+// Ensure that VerifiedInputEvent, VerifiedKeyEvent, VerifiedMotionEvent are packed.
+// We will treat them as byte collections when signing them. There should not be any uninitialized
+// data in-between fields. Otherwise, the padded data will affect the hmac value and verifications
+// will fail.
+
+void TestVerifiedEventSize() {
+    // VerifiedInputEvent
+    constexpr size_t VERIFIED_INPUT_EVENT_SIZE = sizeof(VerifiedInputEvent::type) +
+            sizeof(VerifiedInputEvent::deviceId) + sizeof(VerifiedInputEvent::eventTimeNanos) +
+            sizeof(VerifiedInputEvent::source) + sizeof(VerifiedInputEvent::displayId);
+    static_assert(sizeof(VerifiedInputEvent) == VERIFIED_INPUT_EVENT_SIZE);
+
+    // VerifiedKeyEvent
+    constexpr size_t VERIFIED_KEY_EVENT_SIZE = VERIFIED_INPUT_EVENT_SIZE +
+            sizeof(VerifiedKeyEvent::action) + sizeof(VerifiedKeyEvent::downTimeNanos) +
+            sizeof(VerifiedKeyEvent::flags) + sizeof(VerifiedKeyEvent::keyCode) +
+            sizeof(VerifiedKeyEvent::scanCode) + sizeof(VerifiedKeyEvent::metaState) +
+            sizeof(VerifiedKeyEvent::repeatCount);
+    static_assert(sizeof(VerifiedKeyEvent) == VERIFIED_KEY_EVENT_SIZE);
+
+    // VerifiedMotionEvent
+    constexpr size_t VERIFIED_MOTION_EVENT_SIZE = VERIFIED_INPUT_EVENT_SIZE +
+            sizeof(VerifiedMotionEvent::rawX) + sizeof(VerifiedMotionEvent::rawY) +
+            sizeof(VerifiedMotionEvent::actionMasked) + sizeof(VerifiedMotionEvent::downTimeNanos) +
+            sizeof(VerifiedMotionEvent::flags) + sizeof(VerifiedMotionEvent::metaState) +
+            sizeof(VerifiedMotionEvent::buttonState);
+    static_assert(sizeof(VerifiedMotionEvent) == VERIFIED_MOTION_EVENT_SIZE);
+}
+
 } // namespace android
diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp
new file mode 100644
index 0000000..a59dbe5
--- /dev/null
+++ b/libs/input/tests/VerifiedInputEvent_test.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <input/Input.h>
+
+namespace android {
+
+static KeyEvent getKeyEventWithFlags(int32_t flags) {
+    KeyEvent event;
+    event.initialize(2 /*deviceId*/, AINPUT_SOURCE_GAMEPAD, ADISPLAY_ID_DEFAULT, INVALID_HMAC,
+                     AKEY_EVENT_ACTION_DOWN, flags, AKEYCODE_BUTTON_X, 121 /*scanCode*/,
+                     AMETA_ALT_ON, 1 /*repeatCount*/, 1000 /*downTime*/, 2000 /*eventTime*/);
+    return event;
+}
+
+static MotionEvent getMotionEventWithFlags(int32_t flags) {
+    MotionEvent event;
+    constexpr size_t pointerCount = 1;
+    PointerProperties pointerProperties[pointerCount];
+    PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerProperties[i].id = i;
+        pointerCoords[i].clear();
+    }
+
+    event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, INVALID_HMAC,
+                     AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags,
+                     AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
+                     MotionClassification::NONE, 2 /*xScale*/, 3 /*yScale*/, 4 /*xOffset*/,
+                     5 /*yOffset*/, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/, 280 /*xCursorPosition*/,
+                     540 /*yCursorPosition*/, 100 /*downTime*/, 200 /*eventTime*/, pointerCount,
+                     pointerProperties, pointerCoords);
+    return event;
+}
+
+TEST(VerifiedKeyEventTest, ConvertKeyEventToVerifiedKeyEvent) {
+    KeyEvent event = getKeyEventWithFlags(0);
+    VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event);
+
+    ASSERT_EQ(VerifiedInputEvent::Type::KEY, verified.type);
+
+    ASSERT_EQ(event.getDeviceId(), verified.deviceId);
+    ASSERT_EQ(event.getEventTime(), verified.eventTimeNanos);
+    ASSERT_EQ(event.getSource(), verified.source);
+    ASSERT_EQ(event.getDisplayId(), verified.displayId);
+
+    ASSERT_EQ(event.getAction(), verified.action);
+    ASSERT_EQ(event.getDownTime(), verified.downTimeNanos);
+    ASSERT_EQ(event.getFlags() & VERIFIED_KEY_EVENT_FLAGS, verified.flags);
+    ASSERT_EQ(event.getKeyCode(), verified.keyCode);
+    ASSERT_EQ(event.getScanCode(), verified.scanCode);
+    ASSERT_EQ(event.getMetaState(), verified.metaState);
+    ASSERT_EQ(event.getRepeatCount(), verified.repeatCount);
+}
+
+TEST(VerifiedKeyEventTest, VerifiedKeyEventContainsOnlyVerifiedFlags) {
+    KeyEvent event = getKeyEventWithFlags(AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_FALLBACK);
+    VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event);
+    ASSERT_EQ(AKEY_EVENT_FLAG_CANCELED, verified.flags);
+}
+
+TEST(VerifiedKeyEventTest, VerifiedKeyEventDoesNotContainUnverifiedFlags) {
+    KeyEvent event = getKeyEventWithFlags(AKEY_EVENT_FLAG_EDITOR_ACTION);
+    VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event);
+    ASSERT_EQ(0, verified.flags);
+}
+
+TEST(VerifiedMotionEventTest, ConvertMotionEventToVerifiedMotionEvent) {
+    MotionEvent event = getMotionEventWithFlags(0);
+    VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event);
+
+    ASSERT_EQ(VerifiedInputEvent::Type::MOTION, verified.type);
+
+    ASSERT_EQ(event.getDeviceId(), verified.deviceId);
+    ASSERT_EQ(event.getEventTime(), verified.eventTimeNanos);
+    ASSERT_EQ(event.getSource(), verified.source);
+    ASSERT_EQ(event.getDisplayId(), verified.displayId);
+
+    ASSERT_EQ(event.getRawX(0), verified.rawX);
+    ASSERT_EQ(event.getRawY(0), verified.rawY);
+    ASSERT_EQ(event.getAction(), verified.actionMasked);
+    ASSERT_EQ(event.getDownTime(), verified.downTimeNanos);
+    ASSERT_EQ(event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS, verified.flags);
+    ASSERT_EQ(event.getMetaState(), verified.metaState);
+    ASSERT_EQ(event.getButtonState(), verified.buttonState);
+}
+
+TEST(VerifiedMotionEventTest, VerifiedMotionEventContainsOnlyVerifiedFlags) {
+    MotionEvent event = getMotionEventWithFlags(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED |
+                                                AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE);
+    VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event);
+    ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, verified.flags);
+}
+
+TEST(VerifiedMotionEventTest, VerifiedMotionEventDoesNotContainUnverifiedFlags) {
+    MotionEvent event = getMotionEventWithFlags(AMOTION_EVENT_FLAG_TAINTED);
+    VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event);
+    ASSERT_EQ(0, verified.flags);
+}
+
+} // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index f2b95e7..a8158ba 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3340,6 +3340,10 @@
     return injectionResult;
 }
 
+std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const InputEvent& event) {
+    return nullptr;
+}
+
 bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
     return injectorUid == 0 ||
             mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index d2aea80..72511e9 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -96,6 +96,8 @@
                                      int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
                                      uint32_t policyFlags) override;
 
+    virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override;
+
     virtual void setInputWindows(
             const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId,
             const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) override;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 3424f4c..6e98676 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -92,6 +92,13 @@
                                      int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
                                      uint32_t policyFlags) = 0;
 
+    /*
+     * Check whether InputEvent actually happened by checking the signature of the event.
+     *
+     * Return nullptr if the event cannot be verified.
+     */
+    virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) = 0;
+
     /* Sets the list of input windows.
      *
      * This method may be called on any thread (usually by the input manager).