Set FLAG_IS_ACCESSIBILITY_EVENT for events injected from accessibility

If an input event was modified or injected by accessibility, set the
appropriate flag. This helps applications distinguish the real hardware
events from synthesized events.

This also allows a11y services more flexibility in modifying the event
streams coming from real hardware.

Bug: 152399927
Bug: 175069843
Test: atest inputflinger_tests libinput_tests
Change-Id: I805cba4c84582fa4cd4e0892ec00428d4b255ec6
diff --git a/include/input/Input.h b/include/input/Input.h
index e8678d2..f3369e8 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -43,6 +43,13 @@
  * Additional private constants not defined in ndk/ui/input.h.
  */
 enum {
+#ifdef __linux__
+    /* This event was generated or modified by accessibility service. */
+    AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT =
+            android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT, // 0x800,
+#else
+    AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800;
+#endif
     /* Signifies that the key is being predispatched */
     AKEY_EVENT_FLAG_PREDISPATCH = 0x20000000,
 
@@ -81,6 +88,16 @@
      */
     AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40,
 
+#ifdef __linux__
+    /**
+     * This event was generated or modified by accessibility service.
+     */
+    AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT =
+            android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT, // 0x800,
+#else
+    AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800;
+#endif
+
     /* Motion event is inconsistent with previously sent motion events. */
     AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
 };
@@ -89,14 +106,15 @@
  * 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;
+constexpr int32_t VERIFIED_KEY_EVENT_FLAGS =
+        AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
 
 /**
  * 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;
+constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED |
+        AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED | AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
 
 /**
  * This flag indicates that the point up event has been canceled.
@@ -222,16 +240,14 @@
     POLICY_FLAG_GESTURE = 0x00000008,
 
     POLICY_FLAG_RAW_MASK = 0x0000ffff,
-#ifdef __linux__
-    POLICY_FLAG_INPUTFILTER_TRUSTED = android::os::IInputConstants::POLICY_FLAG_INPUTFILTER_TRUSTED,
 
+#ifdef __linux__
     POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY =
             android::os::IInputConstants::POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
 #else
-    POLICY_FLAG_INPUTFILTER_TRUSTED = 0x10000,
-
     POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000,
 #endif
+
     /* These flags are set by the input dispatcher. */
 
     // Indicates that the input event was injected.
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 1955104..7f0324a 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -318,8 +318,6 @@
         const std::string& name, InputDeviceConfigurationFileType type);
 
 enum ReservedInputDeviceId : int32_t {
-    // Device id assigned to input events generated inside accessibility service
-    ACCESSIBILITY_DEVICE_ID = -2,
     // Device id of a special "virtual" keyboard that is always present.
     VIRTUAL_KEYBOARD_ID = -1,
     // Device id of the "built-in" keyboard if there is one.
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index 3038d9d..474a1e4 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -42,16 +42,15 @@
     const int INVALID_INPUT_EVENT_ID = 0;
 
     /**
-     * The injected event was originally sent from InputDispatcher. Most likely, the journey of the
-     * event looked as follows:
-     * InputDispatcherPolicyInterface::filterInputEvent -> InputFilter.java::onInputEvent ->
-     * InputFilter.java::sendInputEvent -> InputDispatcher::injectInputEvent, without being modified
-     * along the way.
-     */
-    const int POLICY_FLAG_INPUTFILTER_TRUSTED = 0x10000;
-
-    /**
-     * The input event was injected from accessibility
+     * The input event was injected from accessibility. Used in policyFlags for input event
+     * injection.
      */
     const int POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000;
+
+    /**
+     * The input event was generated or modified by accessibility service.
+     * Shared by both KeyEvent and MotionEvent flags, so this value should not overlap with either
+     * set of flags, including in input/Input.h and in android/input.h.
+     */
+    const int INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800;
 }
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index dc0e60c..6fdb046 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -32,6 +32,15 @@
       ]
     },
     {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-filter": "android.view.VerifiedKeyEventTest",
+          "include-filter": "android.view.VerifiedMotionEventTest"
+        }
+      ]
+    },
+    {
       "name": "CtsSecurityTestCases",
       "options": [
         {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index c0010ab..1899c5f 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3787,7 +3787,7 @@
         if (shouldSendKeyToInputFilterLocked(args)) {
             mLock.unlock();
 
-            policyFlags |= POLICY_FLAG_FILTERED | POLICY_FLAG_INPUTFILTER_TRUSTED;
+            policyFlags |= POLICY_FLAG_FILTERED;
             if (!mPolicy->filterInputEvent(&event, policyFlags)) {
                 return; // event was consumed by the filter
             }
@@ -4010,16 +4010,14 @@
     }
 
     // For all injected events, set device id = VIRTUAL_KEYBOARD_ID. The only exception is events
-    // that have gone through the InputFilter. If the event passed through the InputFilter,
-    // but did not get modified, assign the provided device id. If the InputFilter modifies the
-    // events in any way, it is responsible for removing this flag.
-    // If the injected event originated from accessibility, assign the accessibility device id,
-    // so that it can be distinguished from regular injected events.
+    // that have gone through the InputFilter. If the event passed through the InputFilter, assign
+    // the provided device id. If the InputFilter is accessibility, and it modifies or synthesizes
+    // the injected event, it is responsible for setting POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY.
+    // For those events, we will set FLAG_IS_ACCESSIBILITY_EVENT to allow apps to distinguish them
+    // from events that originate from actual hardware.
     int32_t resolvedDeviceId = VIRTUAL_KEYBOARD_ID;
-    if (policyFlags & POLICY_FLAG_INPUTFILTER_TRUSTED) {
+    if (policyFlags & POLICY_FLAG_FILTERED) {
         resolvedDeviceId = event->getDeviceId();
-    } else if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) {
-        resolvedDeviceId = ACCESSIBILITY_DEVICE_ID;
     }
 
     std::queue<std::unique_ptr<EventEntry>> injectedEntries;
@@ -4032,6 +4030,9 @@
             }
 
             int32_t flags = incomingKey.getFlags();
+            if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) {
+                flags |= AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
+            }
             int32_t keyCode = incomingKey.getKeyCode();
             int32_t metaState = incomingKey.getMetaState();
             accelerateMetaShortcuts(resolvedDeviceId, action,
@@ -4073,6 +4074,7 @@
             size_t pointerCount = motionEvent.getPointerCount();
             const PointerProperties* pointerProperties = motionEvent.getPointerProperties();
             int32_t actionButton = motionEvent.getActionButton();
+            int32_t flags = motionEvent.getFlags();
             int32_t displayId = motionEvent.getDisplayId();
             if (!validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) {
                 return InputEventInjectionResult::FAILED;
@@ -4088,6 +4090,10 @@
                 }
             }
 
+            if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) {
+                flags |= AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
+            }
+
             mLock.lock();
             const nsecs_t* sampleEventTimes = motionEvent.getSampleEventTimes();
             const PointerCoords* samplePointerCoords = motionEvent.getSamplePointerCoords();
@@ -4095,8 +4101,7 @@
                     std::make_unique<MotionEntry>(motionEvent.getId(), *sampleEventTimes,
                                                   resolvedDeviceId, motionEvent.getSource(),
                                                   motionEvent.getDisplayId(), policyFlags, action,
-                                                  actionButton, motionEvent.getFlags(),
-                                                  motionEvent.getMetaState(),
+                                                  actionButton, flags, motionEvent.getMetaState(),
                                                   motionEvent.getButtonState(),
                                                   motionEvent.getClassification(),
                                                   motionEvent.getEdgeFlags(),
@@ -4116,7 +4121,7 @@
                         std::make_unique<MotionEntry>(motionEvent.getId(), *sampleEventTimes,
                                                       resolvedDeviceId, motionEvent.getSource(),
                                                       motionEvent.getDisplayId(), policyFlags,
-                                                      action, actionButton, motionEvent.getFlags(),
+                                                      action, actionButton, flags,
                                                       motionEvent.getMetaState(),
                                                       motionEvent.getButtonState(),
                                                       motionEvent.getClassification(),
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 77ca12c..3a9dede 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -3171,7 +3171,8 @@
         mWindow->consumeFocusEvent(true);
     }
 
-    void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId) {
+    void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
+                         int32_t flags) {
         KeyEvent event;
 
         const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -3188,6 +3189,45 @@
         InputEvent* received = mWindow->consume();
         ASSERT_NE(nullptr, received);
         ASSERT_EQ(resolvedDeviceId, received->getDeviceId());
+        ASSERT_EQ(received->getType(), AINPUT_EVENT_TYPE_KEY);
+        KeyEvent& keyEvent = static_cast<KeyEvent&>(*received);
+        ASSERT_EQ(flags, keyEvent.getFlags());
+    }
+
+    void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
+                            int32_t flags) {
+        MotionEvent event;
+        PointerProperties pointerProperties[1];
+        PointerCoords pointerCoords[1];
+        pointerProperties[0].clear();
+        pointerProperties[0].id = 0;
+        pointerCoords[0].clear();
+        pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
+        pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
+
+        ui::Transform identityTransform;
+        const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
+        event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
+                         DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
+                         AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
+                         identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                         0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/,
+                         0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/, eventTime, eventTime,
+                         /*pointerCount*/ 1, pointerProperties, pointerCoords);
+
+        const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
+        ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+                  mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+                                                InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
+                                                policyFlags | additionalPolicyFlags));
+
+        InputEvent* received = mWindow->consume();
+        ASSERT_NE(nullptr, received);
+        ASSERT_EQ(resolvedDeviceId, received->getDeviceId());
+        ASSERT_EQ(received->getType(), AINPUT_EVENT_TYPE_MOTION);
+        MotionEvent& motionEvent = static_cast<MotionEvent&>(*received);
+        ASSERT_EQ(flags, motionEvent.getFlags());
     }
 
 private:
@@ -3195,20 +3235,29 @@
 };
 
 TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
-    // We don't need POLICY_FLAG_FILTERED here, but it will be set in practice, so keep it to make
-    // the test more closely resemble the real usage
-    testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INPUTFILTER_TRUSTED, 3 /*injectedDeviceId*/,
-                    3 /*resolvedDeviceId*/);
+    // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
+    // filter. Without it, the event will no different from a regularly injected event, and the
+    // injected device id will be overwritten.
+    testInjectedKey(POLICY_FLAG_FILTERED, 3 /*injectedDeviceId*/, 3 /*resolvedDeviceId*/,
+                    0 /*flags*/);
 }
 
-TEST_F(InputFilterInjectionPolicyTest, EventsInjectedFromAccessibility_HaveAccessibilityDeviceId) {
+TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
     testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
-                    3 /*injectedDeviceId*/, ACCESSIBILITY_DEVICE_ID /*resolvedDeviceId*/);
+                    3 /*injectedDeviceId*/, 3 /*resolvedDeviceId*/,
+                    AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
+}
+
+TEST_F(InputFilterInjectionPolicyTest,
+       MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
+    testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
+                       3 /*injectedDeviceId*/, 3 /*resolvedDeviceId*/,
+                       AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
 }
 
 TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
     testInjectedKey(0 /*policyFlags*/, 3 /*injectedDeviceId*/,
-                    VIRTUAL_KEYBOARD_ID /*resolvedDeviceId*/);
+                    VIRTUAL_KEYBOARD_ID /*resolvedDeviceId*/, 0 /*flags*/);
 }
 
 class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {