diff options
| author | 2021-06-16 03:55:32 +0000 | |
|---|---|---|
| committer | 2021-06-30 18:11:59 +0000 | |
| commit | f00a4ec687e2bf9110106238c7738927fc3e87d7 (patch) | |
| tree | da6c6f59b222c21f55b7cb40111a06aa8c052d25 | |
| parent | 4019c52f68e694278e1f5833a45a04137af3780c (diff) | |
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
| -rw-r--r-- | include/input/Input.h | 30 | ||||
| -rw-r--r-- | include/input/InputDevice.h | 2 | ||||
| -rw-r--r-- | libs/input/android/os/IInputConstants.aidl | 15 | ||||
| -rw-r--r-- | services/inputflinger/TEST_MAPPING | 9 | ||||
| -rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 29 | ||||
| -rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 65 |
6 files changed, 113 insertions, 37 deletions
diff --git a/include/input/Input.h b/include/input/Input.h index e8678d27c3..f3369e8f71 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 @@ enum { */ 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 @@ enum { * 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 @@ enum { 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 1955104a22..7f0324a4a8 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -318,8 +318,6 @@ extern std::string getInputDeviceConfigurationFilePathByName( 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 3038d9daa5..474a1e410d 100644 --- a/libs/input/android/os/IInputConstants.aidl +++ b/libs/input/android/os/IInputConstants.aidl @@ -42,16 +42,15 @@ interface IInputConstants 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. + * The input event was injected from accessibility. Used in policyFlags for input event + * injection. */ - const int POLICY_FLAG_INPUTFILTER_TRUSTED = 0x10000; + const int POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000; /** - * The input event was injected from accessibility + * 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 POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000; + const int INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800; } diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING index dc0e60c858..6fdb046d3f 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 c0010abf8a..1899c5f29d 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3787,7 +3787,7 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { 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 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( } // 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 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( } 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 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( 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 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( } } + 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 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( 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 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( 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 77ca12c5dc..3a9dede89b 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -3171,7 +3171,8 @@ protected: 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 @@ protected: 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 @@ private: }; 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 { |