diff options
-rw-r--r-- | include/input/InputVerifier.h | 2 | ||||
-rw-r--r-- | libs/input/Android.bp | 22 | ||||
-rw-r--r-- | libs/input/InputTransport.cpp | 4 | ||||
-rw-r--r-- | libs/input/InputVerifier.cpp | 6 | ||||
-rw-r--r-- | libs/input/rust/input.rs | 56 | ||||
-rw-r--r-- | libs/input/rust/input_verifier.rs | 76 | ||||
-rw-r--r-- | libs/input/rust/lib.rs | 5 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 6 |
8 files changed, 161 insertions, 16 deletions
diff --git a/include/input/InputVerifier.h b/include/input/InputVerifier.h index b8574829f3..14dd463425 100644 --- a/include/input/InputVerifier.h +++ b/include/input/InputVerifier.h @@ -46,7 +46,7 @@ class InputVerifier { public: InputVerifier(const std::string& name); - android::base::Result<void> processMovement(int32_t deviceId, int32_t action, + android::base::Result<void> processMovement(int32_t deviceId, int32_t source, int32_t action, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, int32_t flags); diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 36a01d37a5..ab4af1a7b6 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -90,6 +90,28 @@ rust_bindgen { "--allowlist-var=AMOTION_EVENT_ACTION_DOWN", "--allowlist-var=AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT", "--allowlist-var=MAX_POINTER_ID", + "--allowlist-var=AINPUT_SOURCE_CLASS_NONE", + "--allowlist-var=AINPUT_SOURCE_CLASS_BUTTON", + "--allowlist-var=AINPUT_SOURCE_CLASS_POINTER", + "--allowlist-var=AINPUT_SOURCE_CLASS_NAVIGATION", + "--allowlist-var=AINPUT_SOURCE_CLASS_POSITION", + "--allowlist-var=AINPUT_SOURCE_CLASS_JOYSTICK", + "--allowlist-var=AINPUT_SOURCE_UNKNOWN", + "--allowlist-var=AINPUT_SOURCE_KEYBOARD", + "--allowlist-var=AINPUT_SOURCE_DPAD", + "--allowlist-var=AINPUT_SOURCE_GAMEPAD", + "--allowlist-var=AINPUT_SOURCE_TOUCHSCREEN", + "--allowlist-var=AINPUT_SOURCE_MOUSE", + "--allowlist-var=AINPUT_SOURCE_STYLUS", + "--allowlist-var=AINPUT_SOURCE_BLUETOOTH_STYLUS", + "--allowlist-var=AINPUT_SOURCE_TRACKBALL", + "--allowlist-var=AINPUT_SOURCE_MOUSE_RELATIVE", + "--allowlist-var=AINPUT_SOURCE_TOUCHPAD", + "--allowlist-var=AINPUT_SOURCE_TOUCH_NAVIGATION", + "--allowlist-var=AINPUT_SOURCE_JOYSTICK", + "--allowlist-var=AINPUT_SOURCE_HDMI", + "--allowlist-var=AINPUT_SOURCE_SENSOR", + "--allowlist-var=AINPUT_SOURCE_ROTARY_ENCODER", ], static_libs: [ diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 16000139f7..b5a823d76a 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -632,8 +632,8 @@ status_t InputPublisher::publishMotionEvent( MotionEvent::actionToString(action).c_str())); if (verifyEvents()) { Result<void> result = - mInputVerifier.processMovement(deviceId, action, pointerCount, pointerProperties, - pointerCoords, flags); + mInputVerifier.processMovement(deviceId, source, action, pointerCount, + pointerProperties, pointerCoords, flags); if (!result.ok()) { LOG(FATAL) << "Bad stream: " << result.error(); } diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp index 6c602e031d..cec244539e 100644 --- a/libs/input/InputVerifier.cpp +++ b/libs/input/InputVerifier.cpp @@ -33,7 +33,7 @@ namespace android { InputVerifier::InputVerifier(const std::string& name) : mVerifier(android::input::verifier::create(rust::String::lossy(name))){}; -Result<void> InputVerifier::processMovement(DeviceId deviceId, int32_t action, +Result<void> InputVerifier::processMovement(DeviceId deviceId, int32_t source, int32_t action, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, int32_t flags) { @@ -43,8 +43,8 @@ Result<void> InputVerifier::processMovement(DeviceId deviceId, int32_t action, } rust::Slice<const RustPointerProperties> properties{rpp.data(), rpp.size()}; rust::String errorMessage = - android::input::verifier::process_movement(*mVerifier, deviceId, action, properties, - static_cast<uint32_t>(flags)); + android::input::verifier::process_movement(*mVerifier, deviceId, source, action, + properties, static_cast<uint32_t>(flags)); if (errorMessage.empty()) { return {}; } else { diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs index 9d3b38693a..9725b00212 100644 --- a/libs/input/rust/input.rs +++ b/libs/input/rust/input.rs @@ -23,6 +23,54 @@ use std::fmt; #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct DeviceId(pub i32); +#[repr(u32)] +pub enum SourceClass { + None = input_bindgen::AINPUT_SOURCE_CLASS_NONE, + Button = input_bindgen::AINPUT_SOURCE_CLASS_BUTTON, + Pointer = input_bindgen::AINPUT_SOURCE_CLASS_POINTER, + Navigation = input_bindgen::AINPUT_SOURCE_CLASS_NAVIGATION, + Position = input_bindgen::AINPUT_SOURCE_CLASS_POSITION, + Joystick = input_bindgen::AINPUT_SOURCE_CLASS_JOYSTICK, +} + +bitflags! { + /// Source of the input device or input events. + pub struct Source: u32 { + /// SOURCE_UNKNOWN + const Unknown = input_bindgen::AINPUT_SOURCE_UNKNOWN; + /// SOURCE_KEYBOARD + const Keyboard = input_bindgen::AINPUT_SOURCE_KEYBOARD; + /// SOURCE_DPAD + const Dpad = input_bindgen::AINPUT_SOURCE_DPAD; + /// SOURCE_GAMEPAD + const Gamepad = input_bindgen::AINPUT_SOURCE_GAMEPAD; + /// SOURCE_TOUCHSCREEN + const Touchscreen = input_bindgen::AINPUT_SOURCE_TOUCHSCREEN; + /// SOURCE_MOUSE + const Mouse = input_bindgen::AINPUT_SOURCE_MOUSE; + /// SOURCE_STYLUS + const Stylus = input_bindgen::AINPUT_SOURCE_STYLUS; + /// SOURCE_BLUETOOTH_STYLUS + const BluetoothStylus = input_bindgen::AINPUT_SOURCE_BLUETOOTH_STYLUS; + /// SOURCE_TRACKBALL + const Trackball = input_bindgen::AINPUT_SOURCE_TRACKBALL; + /// SOURCE_MOUSE_RELATIVE + const MouseRelative = input_bindgen::AINPUT_SOURCE_MOUSE_RELATIVE; + /// SOURCE_TOUCHPAD + const Touchpad = input_bindgen::AINPUT_SOURCE_TOUCHPAD; + /// SOURCE_TOUCH_NAVIGATION + const TouchNavigation = input_bindgen::AINPUT_SOURCE_TOUCH_NAVIGATION; + /// SOURCE_JOYSTICK + const Joystick = input_bindgen::AINPUT_SOURCE_JOYSTICK; + /// SOURCE_HDMI + const HDMI = input_bindgen::AINPUT_SOURCE_HDMI; + /// SOURCE_SENSOR + const Sensor = input_bindgen::AINPUT_SOURCE_SENSOR; + /// SOURCE_ROTARY_ENCODER + const RotaryEncoder = input_bindgen::AINPUT_SOURCE_ROTARY_ENCODER; + } +} + /// A rust enum representation of a MotionEvent action. #[repr(u32)] pub enum MotionAction { @@ -134,3 +182,11 @@ bitflags! { const NO_FOCUS_CHANGE = input_bindgen::AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE; } } + +impl Source { + /// Return true if this source is from the provided class + pub fn is_from_class(&self, source_class: SourceClass) -> bool { + let class_bits = source_class as u32; + self.bits() & class_bits == class_bits + } +} diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs index 64c0466687..2d94e70309 100644 --- a/libs/input/rust/input_verifier.rs +++ b/libs/input/rust/input_verifier.rs @@ -17,7 +17,7 @@ //! Contains the InputVerifier, used to validate a stream of input events. use crate::ffi::RustPointerProperties; -use crate::input::{DeviceId, MotionAction, MotionFlags}; +use crate::input::{DeviceId, MotionAction, MotionFlags, Source, SourceClass}; use log::info; use std::collections::HashMap; use std::collections::HashSet; @@ -51,10 +51,15 @@ impl InputVerifier { pub fn process_movement( &mut self, device_id: DeviceId, + source: Source, action: u32, pointer_properties: &[RustPointerProperties], flags: MotionFlags, ) -> Result<(), String> { + if !source.is_from_class(SourceClass::Pointer) { + // Skip non-pointer sources like MOUSE_RELATIVE for now + return Ok(()); + } if self.should_log { info!( "Processing {} for device {:?} ({} pointer{}) on {}", @@ -68,6 +73,13 @@ impl InputVerifier { match action.into() { MotionAction::Down => { + if pointer_properties.len() != 1 { + return Err(format!( + "{}: Invalid DOWN event: there are {} pointers in the event", + self.name, + pointer_properties.len() + )); + } let it = self .touching_pointer_ids_by_device .entry(device_id) @@ -90,10 +102,19 @@ impl InputVerifier { )); } let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap(); + if it.len() != pointer_properties.len() - 1 { + return Err(format!( + "{}: There are currently {} touching pointers, but the incoming \ + POINTER_DOWN event has {}", + self.name, + it.len(), + pointer_properties.len() + )); + } let pointer_id = pointer_properties[action_index].id; if it.contains(&pointer_id) { return Err(format!( - "{}: Pointer with id={} not found in the properties", + "{}: Pointer with id={} already present found in the properties", self.name, pointer_id )); } @@ -108,11 +129,10 @@ impl InputVerifier { } } MotionAction::PointerUp { action_index } => { - if !self.touching_pointer_ids_by_device.contains_key(&device_id) { + if !self.ensure_touching_pointers_match(device_id, pointer_properties) { return Err(format!( - "{}: Received POINTER_UP but no pointers are currently down for device \ - {:?}", - self.name, device_id + "{}: ACTION_POINTER_UP touching pointers don't match", + self.name )); } let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap(); @@ -120,6 +140,13 @@ impl InputVerifier { it.remove(&pointer_id); } MotionAction::Up => { + if pointer_properties.len() != 1 { + return Err(format!( + "{}: Invalid UP event: there are {} pointers in the event", + self.name, + pointer_properties.len() + )); + } if !self.touching_pointer_ids_by_device.contains_key(&device_id) { return Err(format!( "{} Received ACTION_UP but no pointers are currently down for device {:?}", @@ -246,6 +273,7 @@ mod tests { use crate::DeviceId; use crate::MotionFlags; use crate::RustPointerProperties; + use crate::Source; #[test] fn single_pointer_stream() { let mut verifier = InputVerifier::new("Test", /*should_log*/ false); @@ -253,6 +281,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, MotionFlags::empty(), @@ -261,6 +290,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_MOVE, &pointer_properties, MotionFlags::empty(), @@ -269,6 +299,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_UP, &pointer_properties, MotionFlags::empty(), @@ -283,6 +314,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, MotionFlags::empty(), @@ -291,6 +323,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_MOVE, &pointer_properties, MotionFlags::empty(), @@ -299,6 +332,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(2), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, MotionFlags::empty(), @@ -307,6 +341,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(2), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_MOVE, &pointer_properties, MotionFlags::empty(), @@ -315,6 +350,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_UP, &pointer_properties, MotionFlags::empty(), @@ -329,6 +365,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, MotionFlags::empty(), @@ -337,6 +374,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_CANCEL, &pointer_properties, MotionFlags::CANCELED, @@ -351,6 +389,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, MotionFlags::empty(), @@ -359,6 +398,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_CANCEL, &pointer_properties, MotionFlags::empty(), // forgot to set FLAG_CANCELED @@ -373,6 +413,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_UP, &pointer_properties, MotionFlags::empty(), @@ -387,6 +428,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, &pointer_properties, MotionFlags::empty(), @@ -396,6 +438,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE, &pointer_properties, MotionFlags::empty(), @@ -405,6 +448,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT, &pointer_properties, MotionFlags::empty(), @@ -414,6 +458,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, &pointer_properties, MotionFlags::empty(), @@ -428,6 +473,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, &pointer_properties, MotionFlags::empty(), @@ -437,10 +483,28 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, &pointer_properties, MotionFlags::empty(), ) .is_err()); } + + // Send a MOVE without a preceding DOWN event. This is OK because it's from source + // MOUSE_RELATIVE, which is used during pointer capture. The verifier should allow such event. + #[test] + fn relative_mouse_move() { + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(2), + Source::MouseRelative, + input_bindgen::AMOTION_EVENT_ACTION_MOVE, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + } } diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs index 1d3c434f76..01d959942c 100644 --- a/libs/input/rust/lib.rs +++ b/libs/input/rust/lib.rs @@ -19,7 +19,7 @@ mod input; mod input_verifier; -pub use input::{DeviceId, MotionAction, MotionFlags}; +pub use input::{DeviceId, MotionAction, MotionFlags, Source}; pub use input_verifier::InputVerifier; #[cxx::bridge(namespace = "android::input")] @@ -51,6 +51,7 @@ mod ffi { fn process_movement( verifier: &mut InputVerifier, device_id: i32, + source: u32, action: u32, pointer_properties: &[RustPointerProperties], flags: u32, @@ -73,12 +74,14 @@ fn create(name: String) -> Box<InputVerifier> { fn process_movement( verifier: &mut InputVerifier, device_id: i32, + source: u32, action: u32, pointer_properties: &[RustPointerProperties], flags: u32, ) -> String { let result = verifier.process_movement( DeviceId(device_id), + Source::from_bits(source).unwrap(), action, pointer_properties, MotionFlags::from_bits(flags).unwrap(), diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 9cd1e0903d..4657c011f6 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4324,9 +4324,9 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) { mVerifiersByDisplay.try_emplace(args.displayId, StringPrintf("display %" PRId32, args.displayId)); Result<void> result = - it->second.processMovement(args.deviceId, args.action, args.getPointerCount(), - args.pointerProperties.data(), args.pointerCoords.data(), - args.flags); + it->second.processMovement(args.deviceId, args.source, args.action, + args.getPointerCount(), args.pointerProperties.data(), + args.pointerCoords.data(), args.flags); if (!result.ok()) { LOG(FATAL) << "Bad stream: " << result.error() << " caused by " << args.dump(); } |