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

Commit 7f187a9d authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Re-organize and export libinput_rust as a rust library"

parents 3cef465d 0762b1f7
Loading
Loading
Loading
Loading
+1 −60
Original line number Diff line number Diff line
@@ -109,62 +109,6 @@ cc_library_static {
    ],
}

genrule {
    name: "libinput_cxx_bridge_code",
    tools: ["cxxbridge"],
    cmd: "$(location cxxbridge) $(in) >> $(out)",
    srcs: ["input_verifier.rs"],
    out: ["inputverifier_generated.cpp"],
}

genrule {
    name: "libinput_cxx_bridge_header",
    tools: ["cxxbridge"],
    cmd: "$(location cxxbridge) $(in) --header >> $(out)",
    srcs: ["input_verifier.rs"],
    out: ["input_verifier.rs.h"],
}

rust_defaults {
    name: "libinput_rust_defaults",
    srcs: ["input_verifier.rs"],
    host_supported: true,
    rustlibs: [
        "libbitflags",
        "libcxx",
        "libinput_bindgen",
        "liblogger",
        "liblog_rust",
        "inputconstants-rust",
    ],

    shared_libs: [
        "libbase",
        "liblog",
    ],
}

rust_ffi_static {
    name: "libinput_rust",
    crate_name: "input",
    defaults: ["libinput_rust_defaults"],
}

rust_test {
    name: "libinput_rust_test",
    defaults: ["libinput_rust_defaults"],
    whole_static_libs: [
        "libinput_from_rust_to_cpp",
    ],
    test_options: {
        unit_test: true,
    },
    test_suites: ["device_tests"],
    sanitize: {
        hwaddress: true,
    },
}

cc_library {
    name: "libinput",
    cpp_std: "c++20",
@@ -176,7 +120,6 @@ cc_library {
        "-Wno-unused-parameter",
    ],
    srcs: [
        "FromRustToCpp.cpp",
        "Input.cpp",
        "InputDevice.cpp",
        "InputEventLabels.cpp",
@@ -208,8 +151,6 @@ cc_library {
        "toolbox_input_labels",
    ],

    generated_sources: ["libinput_cxx_bridge_code"],

    shared_libs: [
        "libbase",
        "libcutils",
@@ -235,7 +176,7 @@ cc_library {
    ],

    whole_static_libs: [
        "libinput_rust",
        "libinput_rust_ffi",
    ],

    export_static_lib_headers: [
+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@

#include <android-base/logging.h>
#include <input/InputVerifier.h>
#include "input_verifier.rs.h"
#include "input_cxx_bridge.rs.h"

using android::base::Error;
using android::base::Result;
+72 −0
Original line number Diff line number Diff line
// Copyright 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

rust_defaults {
    name: "libinput_rust_defaults",
    crate_name: "input",
    srcs: ["lib.rs"],
    host_supported: true,
    rustlibs: [
        "libbitflags",
        "libcxx",
        "libinput_bindgen",
        "liblogger",
        "liblog_rust",
        "inputconstants-rust",
    ],
    whole_static_libs: [
        "libinput_from_rust_to_cpp",
    ],
    shared_libs: [
        "libbase",
    ],
}

rust_library {
    name: "libinput_rust",
    defaults: ["libinput_rust_defaults"],
}

rust_ffi_static {
    name: "libinput_rust_ffi",
    defaults: ["libinput_rust_defaults"],
}

rust_test {
    name: "libinput_rust_test",
    defaults: ["libinput_rust_defaults"],
    test_options: {
        unit_test: true,
    },
    test_suites: ["device_tests"],
    sanitize: {
        hwaddress: true,
    },
}

genrule {
    name: "libinput_cxx_bridge_code",
    tools: ["cxxbridge"],
    cmd: "$(location cxxbridge) $(in) >> $(out)",
    srcs: ["lib.rs"],
    out: ["input_cxx_bridge_generated.cpp"],
}

genrule {
    name: "libinput_cxx_bridge_header",
    tools: ["cxxbridge"],
    cmd: "$(location cxxbridge) $(in) --header >> $(out)",
    srcs: ["lib.rs"],
    out: ["input_cxx_bridge.rs.h"],
}
+126 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! Common definitions of the Android Input Framework in rust.

use bitflags::bitflags;
use std::fmt;

/// The InputDevice ID.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DeviceId(pub i32);

/// A rust enum representation of a MotionEvent action.
#[repr(u32)]
pub enum MotionAction {
    /// ACTION_DOWN
    Down = input_bindgen::AMOTION_EVENT_ACTION_DOWN,
    /// ACTION_UP
    Up = input_bindgen::AMOTION_EVENT_ACTION_UP,
    /// ACTION_MOVE
    Move = input_bindgen::AMOTION_EVENT_ACTION_MOVE,
    /// ACTION_CANCEL
    Cancel = input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
    /// ACTION_OUTSIDE
    Outside = input_bindgen::AMOTION_EVENT_ACTION_OUTSIDE,
    /// ACTION_POINTER_DOWN
    PointerDown {
        /// The index of the affected pointer.
        action_index: usize,
    } = input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN,
    /// ACTION_POINTER_UP
    PointerUp {
        /// The index of the affected pointer.
        action_index: usize,
    } = input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP,
    /// ACTION_HOVER_ENTER
    HoverEnter = input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
    /// ACTION_HOVER_MOVE
    HoverMove = input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE,
    /// ACTION_HOVER_EXIT
    HoverExit = input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT,
    /// ACTION_SCROLL
    Scroll = input_bindgen::AMOTION_EVENT_ACTION_SCROLL,
    /// ACTION_BUTTON_PRESS
    ButtonPress = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
    /// ACTION_BUTTON_RELEASE
    ButtonRelease = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE,
}

impl fmt::Display for MotionAction {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            MotionAction::Down => write!(f, "DOWN"),
            MotionAction::Up => write!(f, "UP"),
            MotionAction::Move => write!(f, "MOVE"),
            MotionAction::Cancel => write!(f, "CANCEL"),
            MotionAction::Outside => write!(f, "OUTSIDE"),
            MotionAction::PointerDown { action_index } => {
                write!(f, "POINTER_DOWN({})", action_index)
            }
            MotionAction::PointerUp { action_index } => write!(f, "POINTER_UP({})", action_index),
            MotionAction::HoverMove => write!(f, "HOVER_MOVE"),
            MotionAction::Scroll => write!(f, "SCROLL"),
            MotionAction::HoverEnter => write!(f, "HOVER_ENTER"),
            MotionAction::HoverExit => write!(f, "HOVER_EXIT"),
            MotionAction::ButtonPress => write!(f, "BUTTON_PRESS"),
            MotionAction::ButtonRelease => write!(f, "BUTTON_RELEASE"),
        }
    }
}

impl From<u32> for MotionAction {
    fn from(action: u32) -> Self {
        let (action_masked, action_index) = MotionAction::breakdown_action(action);
        match action_masked {
            input_bindgen::AMOTION_EVENT_ACTION_DOWN => MotionAction::Down,
            input_bindgen::AMOTION_EVENT_ACTION_UP => MotionAction::Up,
            input_bindgen::AMOTION_EVENT_ACTION_MOVE => MotionAction::Move,
            input_bindgen::AMOTION_EVENT_ACTION_CANCEL => MotionAction::Cancel,
            input_bindgen::AMOTION_EVENT_ACTION_OUTSIDE => MotionAction::Outside,
            input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN => {
                MotionAction::PointerDown { action_index }
            }
            input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP => {
                MotionAction::PointerUp { action_index }
            }
            input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER => MotionAction::HoverEnter,
            input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE => MotionAction::HoverMove,
            input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT => MotionAction::HoverExit,
            input_bindgen::AMOTION_EVENT_ACTION_SCROLL => MotionAction::Scroll,
            input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS => MotionAction::ButtonPress,
            input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE => MotionAction::ButtonRelease,
            _ => panic!("Unknown action: {}", action),
        }
    }
}

impl MotionAction {
    fn breakdown_action(action: u32) -> (u32, usize) {
        let action_masked = action & input_bindgen::AMOTION_EVENT_ACTION_MASK;
        let index = (action & input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
            >> input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
        (action_masked, index.try_into().unwrap())
    }
}

bitflags! {
    /// MotionEvent flags.
    pub struct MotionFlags: i32 {
        /// FLAG_CANCELED
        const CANCELED = input_bindgen::AMOTION_EVENT_FLAG_CANCELED;
    }
}
+31 −177
Original line number Diff line number Diff line
@@ -14,191 +14,45 @@
 * limitations under the License.
 */

//! Validate the incoming motion stream.
//! This class is not thread-safe.
//! State is stored in the "InputVerifier" object
//! that can be created via the 'create' method.
//! Usage:
//! Box<InputVerifier> verifier = create("inputChannel name");
//! result = process_movement(verifier, ...);
//! if (result) {
//!    crash(result.error_message());
//! }
//! Contains the InputVerifier, used to validate a stream of input events.

use crate::ffi::RustPointerProperties;
use crate::input::{DeviceId, MotionAction, MotionFlags};
use log::info;
use std::collections::HashMap;
use std::collections::HashSet;

use bitflags::bitflags;
use log::info;

#[cxx::bridge(namespace = "android::input")]
mod ffi {
    #[namespace = "android"]
    unsafe extern "C++" {
        include!("ffi/FromRustToCpp.h");
        fn shouldLog(tag: &str) -> bool;
    }
    #[namespace = "android::input::verifier"]
    extern "Rust" {
        type InputVerifier;

        fn create(name: String) -> Box<InputVerifier>;
        fn process_movement(
            verifier: &mut InputVerifier,
            device_id: i32,
            action: u32,
            pointer_properties: &[RustPointerProperties],
            flags: i32,
        ) -> String;
    }

    pub struct RustPointerProperties {
        id: i32,
    }
}

use crate::ffi::shouldLog;
use crate::ffi::RustPointerProperties;

#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
struct DeviceId(i32);

fn process_movement(
    verifier: &mut InputVerifier,
    device_id: i32,
    action: u32,
    pointer_properties: &[RustPointerProperties],
    flags: i32,
) -> String {
    let result = verifier.process_movement(
        DeviceId(device_id),
        action,
        pointer_properties,
        Flags::from_bits(flags).unwrap(),
    );
    match result {
        Ok(()) => "".to_string(),
        Err(e) => e,
    }
}

fn create(name: String) -> Box<InputVerifier> {
    Box::new(InputVerifier::new(&name))
}

#[repr(u32)]
enum MotionAction {
    Down = input_bindgen::AMOTION_EVENT_ACTION_DOWN,
    Up = input_bindgen::AMOTION_EVENT_ACTION_UP,
    Move = input_bindgen::AMOTION_EVENT_ACTION_MOVE,
    Cancel = input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
    Outside = input_bindgen::AMOTION_EVENT_ACTION_OUTSIDE,
    PointerDown { action_index: usize } = input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN,
    PointerUp { action_index: usize } = input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP,
    HoverEnter = input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
    HoverMove = input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE,
    HoverExit = input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT,
    Scroll = input_bindgen::AMOTION_EVENT_ACTION_SCROLL,
    ButtonPress = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
    ButtonRelease = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE,
}

fn get_action_index(action: u32) -> usize {
    let index = (action & input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
        >> input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
    index.try_into().unwrap()
}

impl From<u32> for MotionAction {
    fn from(action: u32) -> Self {
        let action_masked = action & input_bindgen::AMOTION_EVENT_ACTION_MASK;
        let action_index = get_action_index(action);
        match action_masked {
            input_bindgen::AMOTION_EVENT_ACTION_DOWN => MotionAction::Down,
            input_bindgen::AMOTION_EVENT_ACTION_UP => MotionAction::Up,
            input_bindgen::AMOTION_EVENT_ACTION_MOVE => MotionAction::Move,
            input_bindgen::AMOTION_EVENT_ACTION_CANCEL => MotionAction::Cancel,
            input_bindgen::AMOTION_EVENT_ACTION_OUTSIDE => MotionAction::Outside,
            input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN => {
                MotionAction::PointerDown { action_index }
            }
            input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP => {
                MotionAction::PointerUp { action_index }
            }
            input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER => MotionAction::HoverEnter,
            input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE => MotionAction::HoverMove,
            input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT => MotionAction::HoverExit,
            input_bindgen::AMOTION_EVENT_ACTION_SCROLL => MotionAction::Scroll,
            input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS => MotionAction::ButtonPress,
            input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE => MotionAction::ButtonRelease,
            _ => panic!("Unknown action: {}", action),
        }
    }
}

bitflags! {
    struct Flags: i32 {
        const CANCELED = input_bindgen::AMOTION_EVENT_FLAG_CANCELED;
    }
}

fn motion_action_to_string(action: u32) -> String {
    match action.into() {
        MotionAction::Down => "DOWN".to_string(),
        MotionAction::Up => "UP".to_string(),
        MotionAction::Move => "MOVE".to_string(),
        MotionAction::Cancel => "CANCEL".to_string(),
        MotionAction::Outside => "OUTSIDE".to_string(),
        MotionAction::PointerDown { action_index } => {
            format!("POINTER_DOWN({})", action_index)
        }
        MotionAction::PointerUp { action_index } => {
            format!("POINTER_UP({})", action_index)
        }
        MotionAction::HoverMove => "HOVER_MOVE".to_string(),
        MotionAction::Scroll => "SCROLL".to_string(),
        MotionAction::HoverEnter => "HOVER_ENTER".to_string(),
        MotionAction::HoverExit => "HOVER_EXIT".to_string(),
        MotionAction::ButtonPress => "BUTTON_PRESS".to_string(),
        MotionAction::ButtonRelease => "BUTTON_RELEASE".to_string(),
    }
}

/**
 * Log all of the movements that are sent to this verifier. Helps to identify the streams that lead
 * to inconsistent events.
 * Enable this via "adb shell setprop log.tag.InputVerifierLogEvents DEBUG"
 */
fn log_events() -> bool {
    shouldLog("InputVerifierLogEvents")
}

struct InputVerifier {
/// The InputVerifier is used to validate a stream of input events.
pub struct InputVerifier {
    name: String,
    should_log: bool,
    touching_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>,
}

impl InputVerifier {
    fn new(name: &str) -> Self {
    /// Create a new InputVerifier.
    pub fn new(name: &str, should_log: bool) -> Self {
        logger::init(
            logger::Config::default()
                .with_tag_on_device("InputVerifier")
                .with_min_level(log::Level::Trace),
        );
        Self { name: name.to_owned(), touching_pointer_ids_by_device: HashMap::new() }
        Self { name: name.to_owned(), should_log, touching_pointer_ids_by_device: HashMap::new() }
    }

    fn process_movement(
    /// Process a pointer movement event from an InputDevice.
    /// If the event is not valid, we return an error string that describes the issue.
    pub fn process_movement(
        &mut self,
        device_id: DeviceId,
        action: u32,
        pointer_properties: &[RustPointerProperties],
        flags: Flags,
        flags: MotionFlags,
    ) -> Result<(), String> {
        if log_events() {
        if self.should_log {
            info!(
                "Processing {} for device {:?} ({} pointer{}) on {}",
                motion_action_to_string(action),
                MotionAction::from(action).to_string(),
                device_id,
                pointer_properties.len(),
                if pointer_properties.len() == 1 { "" } else { "s" },
@@ -284,7 +138,7 @@ impl InputVerifier {
                it.clear();
            }
            MotionAction::Cancel => {
                if flags.contains(Flags::CANCELED) {
                if flags.contains(MotionFlags::CANCELED) {
                    return Err(format!(
                        "{}: For ACTION_CANCEL, must set FLAG_CANCELED",
                        self.name
@@ -325,20 +179,20 @@ impl InputVerifier {

#[cfg(test)]
mod tests {
    use crate::input_verifier::InputVerifier;
    use crate::DeviceId;
    use crate::Flags;
    use crate::InputVerifier;
    use crate::MotionFlags;
    use crate::RustPointerProperties;
    #[test]
    fn single_pointer_stream() {
        let mut verifier = InputVerifier::new("Test");
        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_DOWN,
                &pointer_properties,
                Flags::empty(),
                MotionFlags::empty(),
            )
            .is_ok());
        assert!(verifier
@@ -346,7 +200,7 @@ mod tests {
                DeviceId(1),
                input_bindgen::AMOTION_EVENT_ACTION_MOVE,
                &pointer_properties,
                Flags::empty(),
                MotionFlags::empty(),
            )
            .is_ok());
        assert!(verifier
@@ -354,21 +208,21 @@ mod tests {
                DeviceId(1),
                input_bindgen::AMOTION_EVENT_ACTION_UP,
                &pointer_properties,
                Flags::empty(),
                MotionFlags::empty(),
            )
            .is_ok());
    }

    #[test]
    fn multi_device_stream() {
        let mut verifier = InputVerifier::new("Test");
        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_DOWN,
                &pointer_properties,
                Flags::empty(),
                MotionFlags::empty(),
            )
            .is_ok());
        assert!(verifier
@@ -376,7 +230,7 @@ mod tests {
                DeviceId(1),
                input_bindgen::AMOTION_EVENT_ACTION_MOVE,
                &pointer_properties,
                Flags::empty(),
                MotionFlags::empty(),
            )
            .is_ok());
        assert!(verifier
@@ -384,7 +238,7 @@ mod tests {
                DeviceId(2),
                input_bindgen::AMOTION_EVENT_ACTION_DOWN,
                &pointer_properties,
                Flags::empty(),
                MotionFlags::empty(),
            )
            .is_ok());
        assert!(verifier
@@ -392,7 +246,7 @@ mod tests {
                DeviceId(2),
                input_bindgen::AMOTION_EVENT_ACTION_MOVE,
                &pointer_properties,
                Flags::empty(),
                MotionFlags::empty(),
            )
            .is_ok());
        assert!(verifier
@@ -400,21 +254,21 @@ mod tests {
                DeviceId(1),
                input_bindgen::AMOTION_EVENT_ACTION_UP,
                &pointer_properties,
                Flags::empty(),
                MotionFlags::empty(),
            )
            .is_ok());
    }

    #[test]
    fn test_invalid_up() {
        let mut verifier = InputVerifier::new("Test");
        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_UP,
                &pointer_properties,
                Flags::empty(),
                MotionFlags::empty(),
            )
            .is_err());
    }
Loading