Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1160ecdf authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

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
parent 556a811b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;
};
+8 −1
Original line number Diff line number Diff line
@@ -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
+129 −2
Original line number Diff line number Diff line
@@ -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());
    }
}
+7 −2
Original line number Diff line number Diff line
@@ -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));
}
+4 −0
Original line number Diff line number Diff line
@@ -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) {