diff options
author | 2023-06-28 15:57:47 -0700 | |
---|---|---|
committer | 2023-07-04 20:39:21 +0000 | |
commit | 1160ecdfa295225f9eec1a20212746e412ca5c29 (patch) | |
tree | 2ea1233163568350bf6013397f0b8bb5031581de | |
parent | 556a811bacebb21be966fd22d36d0a3c64eb5cd6 (diff) |
Add hovering support to verifier
In order to allow fuzzing of dispatcher, we need to be able to avoid
incorrect hover sequences sent to the listener.
Add hovering support for verifier in this CL.
Bug: 211379801
Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST
Change-Id: If7ee8ecb62044768915acc4657029366e193c6db
-rw-r--r-- | include/input/InputVerifier.h | 2 | ||||
-rw-r--r-- | libs/input/InputVerifier.cpp | 9 | ||||
-rw-r--r-- | libs/input/rust/input_verifier.rs | 131 | ||||
-rw-r--r-- | libs/input/rust/lib.rs | 9 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 4 |
5 files changed, 150 insertions, 5 deletions
diff --git a/include/input/InputVerifier.h b/include/input/InputVerifier.h index 3715408388..b8574829f3 100644 --- a/include/input/InputVerifier.h +++ b/include/input/InputVerifier.h @@ -51,6 +51,8 @@ public: const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, int32_t flags); + void resetDevice(int32_t deviceId); + private: rust::Box<android::input::verifier::InputVerifier> mVerifier; }; diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp index b0546a5243..851babfb54 100644 --- a/libs/input/InputVerifier.cpp +++ b/libs/input/InputVerifier.cpp @@ -24,6 +24,8 @@ using android::base::Error; using android::base::Result; using android::input::RustPointerProperties; +using DeviceId = int32_t; + namespace android { // --- InputVerifier --- @@ -31,7 +33,8 @@ namespace android { InputVerifier::InputVerifier(const std::string& name) : mVerifier(android::input::verifier::create(name)){}; -Result<void> InputVerifier::processMovement(int32_t deviceId, int32_t action, uint32_t pointerCount, +Result<void> InputVerifier::processMovement(DeviceId deviceId, int32_t action, + uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, int32_t flags) { std::vector<RustPointerProperties> rpp; @@ -49,4 +52,8 @@ Result<void> InputVerifier::processMovement(int32_t deviceId, int32_t action, ui } } +void InputVerifier::resetDevice(DeviceId deviceId) { + android::input::verifier::reset_device(*mVerifier, deviceId); +} + } // namespace android diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs index 1cc11297b6..fdb623033b 100644 --- a/libs/input/rust/input_verifier.rs +++ b/libs/input/rust/input_verifier.rs @@ -27,6 +27,7 @@ pub struct InputVerifier { name: String, should_log: bool, touching_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>, + hovering_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>, } impl InputVerifier { @@ -37,7 +38,12 @@ impl InputVerifier { .with_tag_on_device("InputVerifier") .with_min_level(log::Level::Trace), ); - Self { name: name.to_owned(), should_log, touching_pointer_ids_by_device: HashMap::new() } + Self { + name: name.to_owned(), + should_log, + touching_pointer_ids_by_device: HashMap::new(), + hovering_pointer_ids_by_device: HashMap::new(), + } } /// Process a pointer movement event from an InputDevice. @@ -135,7 +141,7 @@ impl InputVerifier { self.name, pointer_id, it, device_id )); } - it.clear(); + self.touching_pointer_ids_by_device.remove(&device_id); } MotionAction::Cancel => { if flags.contains(MotionFlags::CANCELED) { @@ -153,11 +159,68 @@ impl InputVerifier { } self.touching_pointer_ids_by_device.remove(&device_id); } + /* + * The hovering protocol currently supports a single pointer only, because we do not + * have ACTION_HOVER_POINTER_ENTER or ACTION_HOVER_POINTER_EXIT. + * Still, we are keeping the infrastructure here pretty general in case that is + * eventually supported. + */ + MotionAction::HoverEnter => { + if self.hovering_pointer_ids_by_device.contains_key(&device_id) { + return Err(format!( + "{}: Invalid HOVER_ENTER event - pointers already hovering for device {:?}:\ + {:?}", + self.name, device_id, self.hovering_pointer_ids_by_device + )); + } + let it = self + .hovering_pointer_ids_by_device + .entry(device_id) + .or_insert_with(HashSet::new); + it.insert(pointer_properties[0].id); + } + MotionAction::HoverMove => { + // For compatibility reasons, we allow HOVER_MOVE without a prior HOVER_ENTER. + // If there was no prior HOVER_ENTER, just start a new hovering pointer. + let it = self + .hovering_pointer_ids_by_device + .entry(device_id) + .or_insert_with(HashSet::new); + it.insert(pointer_properties[0].id); + } + MotionAction::HoverExit => { + if !self.hovering_pointer_ids_by_device.contains_key(&device_id) { + return Err(format!( + "{}: Invalid HOVER_EXIT event - no pointers are hovering for device {:?}", + self.name, device_id + )); + } + let pointer_id = pointer_properties[0].id; + let it = self.hovering_pointer_ids_by_device.get_mut(&device_id).unwrap(); + it.remove(&pointer_id); + + if !it.is_empty() { + return Err(format!( + "{}: Removed hovering pointer {}, but pointers are still\ + hovering for device {:?}: {:?}", + self.name, pointer_id, device_id, it + )); + } + self.hovering_pointer_ids_by_device.remove(&device_id); + } _ => return Ok(()), } Ok(()) } + /// Notify the verifier that the device has been reset, which will cause the verifier to erase + /// the current internal state for this device. Subsequent events from this device are expected + //// to start a new gesture. + pub fn reset_device(&mut self, device_id: DeviceId) { + self.touching_pointer_ids_by_device.remove(&device_id); + self.hovering_pointer_ids_by_device.remove(&device_id); + } + fn ensure_touching_pointers_match( &self, device_id: DeviceId, @@ -272,4 +335,68 @@ mod tests { ) .is_err()); } + + #[test] + fn correct_hover_sequence() { + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + } + + #[test] + fn double_hover_enter() { + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + &pointer_properties, + MotionFlags::empty(), + ) + .is_err()); + } } diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs index 25b2ecbcda..892f558da6 100644 --- a/libs/input/rust/lib.rs +++ b/libs/input/rust/lib.rs @@ -54,6 +54,7 @@ mod ffi { pointer_properties: &[RustPointerProperties], flags: i32, ) -> String; + fn reset_device(verifier: &mut InputVerifier, device_id: i32); } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] @@ -64,6 +65,10 @@ mod ffi { use crate::ffi::RustPointerProperties; +fn create(name: String) -> Box<InputVerifier> { + Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents"))) +} + fn process_movement( verifier: &mut InputVerifier, device_id: i32, @@ -83,6 +88,6 @@ fn process_movement( } } -fn create(name: String) -> Box<InputVerifier> { - Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents"))) +fn reset_device(verifier: &mut InputVerifier, device_id: i32) { + verifier.reset_device(DeviceId(device_id)); } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 29c4e469ea..482e23f043 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4516,6 +4516,10 @@ void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs& args) { std::unique_ptr<DeviceResetEntry> newEntry = std::make_unique<DeviceResetEntry>(args.id, args.eventTime, args.deviceId); needWake = enqueueInboundEventLocked(std::move(newEntry)); + + for (auto& [_, verifier] : mVerifiersByDisplay) { + verifier.resetDevice(args.deviceId); + } } // release lock if (needWake) { |