blob: 39c3465aeaf6789c6f0d3c576ea07d020d7282a5 [file]
/*
* 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.
*/
//! InputFilter manages all the filtering components that can intercept events, modify the events,
//! block events, etc depending on the situation. This will be used support Accessibility features
//! like Sticky keys, Slow keys, Bounce keys, etc.
use binder::{Interface, Strong};
use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
DeviceInfo::DeviceInfo,
IInputFilter::{IInputFilter, IInputFilterCallbacks::IInputFilterCallbacks},
IInputThread::{IInputThread, IInputThreadCallback::IInputThreadCallback},
InputFilterConfiguration::InputFilterConfiguration,
KeyEvent::KeyEvent,
};
use crate::bounce_keys_filter::BounceKeysFilter;
use crate::input_filter_thread::InputFilterThread;
use crate::slow_keys_filter::SlowKeysFilter;
use crate::sticky_keys_filter::StickyKeysFilter;
use input::ModifierState;
use log::{error, info};
use std::any::Any;
use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};
/// Virtual keyboard device ID
pub const VIRTUAL_KEYBOARD_DEVICE_ID: i32 = -1;
/// Interface for all the sub input filters
pub trait Filter {
fn notify_key(&mut self, event: &KeyEvent);
fn notify_devices_changed(&mut self, device_infos: &[DeviceInfo]);
fn destroy(&mut self);
fn save(
&mut self,
state: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
) -> HashMap<&'static str, Box<dyn Any + Send + Sync>>;
fn restore(&mut self, state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>);
fn dump(&mut self, dump_str: String) -> String;
}
struct InputFilterState {
first_filter: Box<dyn Filter + Send + Sync>,
enabled: bool,
}
/// The rust implementation of InputFilter
pub struct InputFilter {
// In order to have multiple immutable references to the callbacks that is thread safe need to
// wrap the callbacks in Arc<RwLock<...>>
callbacks: Arc<RwLock<Strong<dyn IInputFilterCallbacks>>>,
// Access to mutable references to mutable state (includes access to filters, enabled, etc.) is
// guarded by Mutex for thread safety
state: Mutex<InputFilterState>,
input_filter_thread: InputFilterThread,
}
impl Interface for InputFilter {}
impl InputFilter {
/// Create a new InputFilter instance.
pub fn new(callbacks: Strong<dyn IInputFilterCallbacks>) -> InputFilter {
let ref_callbacks = Arc::new(RwLock::new(callbacks));
let base_filter = Box::new(BaseFilter::new(ref_callbacks.clone()));
Self::create_input_filter(base_filter, ref_callbacks)
}
/// Create test instance of InputFilter
fn create_input_filter(
first_filter: Box<dyn Filter + Send + Sync>,
callbacks: Arc<RwLock<Strong<dyn IInputFilterCallbacks>>>,
) -> InputFilter {
Self {
callbacks: callbacks.clone(),
state: Mutex::new(InputFilterState { first_filter, enabled: false }),
input_filter_thread: InputFilterThread::new(InputFilterThreadCreator::new(callbacks)),
}
}
}
impl IInputFilter for InputFilter {
fn isEnabled(&self) -> binder::Result<bool> {
Result::Ok(self.state.lock().unwrap().enabled)
}
fn notifyKey(&self, event: &KeyEvent) -> binder::Result<()> {
let first_filter = &mut self.state.lock().unwrap().first_filter;
first_filter.notify_key(event);
Result::Ok(())
}
fn notifyInputDevicesChanged(&self, device_infos: &[DeviceInfo]) -> binder::Result<()> {
let first_filter = &mut self.state.lock().unwrap().first_filter;
first_filter.notify_devices_changed(device_infos);
Result::Ok(())
}
fn notifyConfigurationChanged(&self, config: &InputFilterConfiguration) -> binder::Result<()> {
{
let mut state = self.state.lock().unwrap();
let saved_state = state.first_filter.save(HashMap::new());
state.first_filter.destroy();
let mut first_filter: Box<dyn Filter + Send + Sync> =
Box::new(BaseFilter::new(self.callbacks.clone()));
if config.stickyKeysEnabled {
first_filter = Box::new(StickyKeysFilter::new(
first_filter,
ModifierStateListener::new(self.callbacks.clone()),
));
state.enabled = true;
info!("Sticky keys filter is installed");
}
if config.slowKeysThresholdNs > 0 {
first_filter = Box::new(SlowKeysFilter::new(
first_filter,
config.slowKeysThresholdNs,
self.input_filter_thread.clone(),
));
state.enabled = true;
info!(
"Slow keys filter is installed, threshold = {:?}ns",
config.slowKeysThresholdNs
);
}
if config.bounceKeysThresholdNs > 0 {
first_filter =
Box::new(BounceKeysFilter::new(first_filter, config.bounceKeysThresholdNs));
state.enabled = true;
info!(
"Bounce keys filter is installed, threshold = {:?}ns",
config.bounceKeysThresholdNs
);
}
state.first_filter = first_filter;
state.first_filter.restore(&saved_state);
}
Result::Ok(())
}
fn dumpFilter(&self) -> binder::Result<String> {
let first_filter = &mut self.state.lock().unwrap().first_filter;
let dump_str = first_filter.dump(String::new());
Result::Ok(dump_str)
}
}
struct BaseFilter {
callbacks: Arc<RwLock<Strong<dyn IInputFilterCallbacks>>>,
}
impl BaseFilter {
fn new(callbacks: Arc<RwLock<Strong<dyn IInputFilterCallbacks>>>) -> BaseFilter {
Self { callbacks }
}
}
impl Filter for BaseFilter {
fn notify_key(&mut self, event: &KeyEvent) {
match self.callbacks.read().unwrap().sendKeyEvent(event) {
Ok(_) => (),
_ => error!("Failed to send key event back to native C++"),
}
}
fn notify_devices_changed(&mut self, _device_infos: &[DeviceInfo]) {
// do nothing
}
fn destroy(&mut self) {
// do nothing
}
fn save(
&mut self,
state: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
) -> HashMap<&'static str, Box<dyn Any + Send + Sync>> {
// do nothing
state
}
fn restore(&mut self, _state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>) {
// do nothing
}
fn dump(&mut self, dump_str: String) -> String {
// do nothing
dump_str
}
}
/// This struct wraps around IInputFilterCallbacks restricting access to only
/// {@code onModifierStateChanged()} method of the callback.
#[derive(Clone)]
pub struct ModifierStateListener(Arc<RwLock<Strong<dyn IInputFilterCallbacks>>>);
impl ModifierStateListener {
pub fn new(callbacks: Arc<RwLock<Strong<dyn IInputFilterCallbacks>>>) -> ModifierStateListener {
Self(callbacks)
}
pub fn modifier_state_changed(
&self,
modifier_state: ModifierState,
locked_modifier_state: ModifierState,
) {
let _ = self.0.read().unwrap().onModifierStateChanged(
modifier_state.bits() as i32,
locked_modifier_state.bits() as i32,
);
}
}
/// This struct wraps around IInputFilterCallbacks restricting access to only
/// {@code createInputFilterThread()} method of the callback.
#[derive(Clone)]
pub struct InputFilterThreadCreator(Arc<RwLock<Strong<dyn IInputFilterCallbacks>>>);
impl InputFilterThreadCreator {
pub fn new(
callbacks: Arc<RwLock<Strong<dyn IInputFilterCallbacks>>>,
) -> InputFilterThreadCreator {
Self(callbacks)
}
pub fn create(
&self,
input_thread_callback: &Strong<dyn IInputThreadCallback>,
) -> Strong<dyn IInputThread> {
self.0.read().unwrap().createInputFilterThread(input_thread_callback).unwrap()
}
}
#[cfg(test)]
mod tests {
use crate::input_filter::{
test_callbacks::TestCallbacks, test_filter::TestFilter, InputFilter,
};
use android_hardware_input_common::aidl::android::hardware::input::common::Source::Source;
use binder::Strong;
use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
DeviceInfo::DeviceInfo, IInputFilter::IInputFilter,
InputFilterConfiguration::InputFilterConfiguration, KeyEvent::KeyEvent,
KeyEventAction::KeyEventAction,
};
use input::KeyboardType;
use std::sync::{Arc, RwLock};
#[test]
fn test_not_enabled_with_default_filter() {
let test_callbacks = TestCallbacks::new();
let input_filter = InputFilter::new(Strong::new(Box::new(test_callbacks)));
let result = input_filter.isEnabled();
assert!(result.is_ok());
assert!(!result.unwrap());
}
#[test]
fn test_notify_key_with_no_filters() {
let test_callbacks = TestCallbacks::new();
let input_filter = InputFilter::new(Strong::new(Box::new(test_callbacks.clone())));
let event = create_key_event();
assert!(input_filter.notifyKey(&event).is_ok());
assert_eq!(test_callbacks.last_event().unwrap(), event);
}
#[test]
fn test_notify_key_with_filter() {
let test_filter = TestFilter::new();
let test_callbacks = TestCallbacks::new();
let input_filter = InputFilter::create_input_filter(
Box::new(test_filter.clone()),
Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks)))),
);
let event = create_key_event();
assert!(input_filter.notifyKey(&event).is_ok());
assert_eq!(test_filter.last_event().unwrap(), event);
}
#[test]
fn test_notify_devices_changed() {
let test_filter = TestFilter::new();
let test_callbacks = TestCallbacks::new();
let input_filter = InputFilter::create_input_filter(
Box::new(test_filter.clone()),
Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks)))),
);
assert!(input_filter
.notifyInputDevicesChanged(&[DeviceInfo {
deviceId: 0,
external: true,
keyboardType: KeyboardType::None as i32
}])
.is_ok());
assert!(test_filter.is_device_changed_called());
}
#[test]
fn test_notify_configuration_changed_enabled_bounce_keys() {
let test_callbacks = TestCallbacks::new();
let input_filter = InputFilter::new(Strong::new(Box::new(test_callbacks)));
let result = input_filter.notifyConfigurationChanged(&InputFilterConfiguration {
bounceKeysThresholdNs: 100,
..Default::default()
});
assert!(result.is_ok());
let result = input_filter.isEnabled();
assert!(result.is_ok());
assert!(result.unwrap());
}
#[test]
fn test_notify_configuration_changed_enabled_sticky_keys() {
let test_callbacks = TestCallbacks::new();
let input_filter = InputFilter::new(Strong::new(Box::new(test_callbacks)));
let result = input_filter.notifyConfigurationChanged(&InputFilterConfiguration {
stickyKeysEnabled: true,
..Default::default()
});
assert!(result.is_ok());
let result = input_filter.isEnabled();
assert!(result.is_ok());
assert!(result.unwrap());
}
#[test]
fn test_notify_configuration_changed_enabled_slow_keys() {
let test_callbacks = TestCallbacks::new();
let input_filter = InputFilter::new(Strong::new(Box::new(test_callbacks)));
let result = input_filter.notifyConfigurationChanged(&InputFilterConfiguration {
slowKeysThresholdNs: 100,
..Default::default()
});
assert!(result.is_ok());
let result = input_filter.isEnabled();
assert!(result.is_ok());
assert!(result.unwrap());
}
#[test]
fn test_notify_configuration_changed_destroys_existing_filters() {
let test_filter = TestFilter::new();
let test_callbacks = TestCallbacks::new();
let input_filter = InputFilter::create_input_filter(
Box::new(test_filter.clone()),
Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks)))),
);
let _ = input_filter
.notifyConfigurationChanged(&InputFilterConfiguration { ..Default::default() });
assert!(test_filter.is_destroy_called());
}
fn create_key_event() -> KeyEvent {
KeyEvent {
id: 1,
deviceId: 1,
downTime: 0,
readTime: 0,
eventTime: 0,
source: Source::KEYBOARD,
displayId: 0,
policyFlags: 0,
action: KeyEventAction::DOWN,
flags: 0,
keyCode: 0,
scanCode: 0,
metaState: 0,
}
}
}
#[cfg(test)]
pub mod test_filter {
use crate::input_filter::Filter;
use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
DeviceInfo::DeviceInfo, KeyEvent::KeyEvent,
};
use std::any::Any;
use std::collections::HashMap;
use std::sync::{Arc, RwLock, RwLockWriteGuard};
#[derive(Default)]
struct TestFilterInner {
is_device_changed_called: bool,
last_event: Option<KeyEvent>,
is_destroy_called: bool,
}
#[derive(Default, Clone)]
pub struct TestFilter(Arc<RwLock<TestFilterInner>>);
impl TestFilter {
pub fn new() -> Self {
Default::default()
}
fn inner(&mut self) -> RwLockWriteGuard<'_, TestFilterInner> {
self.0.write().unwrap()
}
pub fn last_event(&self) -> Option<KeyEvent> {
self.0.read().unwrap().last_event
}
pub fn clear(&mut self) {
self.inner().last_event = None
}
pub fn is_device_changed_called(&self) -> bool {
self.0.read().unwrap().is_device_changed_called
}
pub fn is_destroy_called(&self) -> bool {
self.0.read().unwrap().is_destroy_called
}
}
impl Filter for TestFilter {
fn notify_key(&mut self, event: &KeyEvent) {
self.inner().last_event = Some(*event);
}
fn notify_devices_changed(&mut self, _device_infos: &[DeviceInfo]) {
self.inner().is_device_changed_called = true;
}
fn destroy(&mut self) {
self.inner().is_destroy_called = true;
}
fn save(
&mut self,
state: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
) -> HashMap<&'static str, Box<dyn Any + Send + Sync>> {
// do nothing
state
}
fn restore(&mut self, _state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>) {
// do nothing
}
fn dump(&mut self, dump_str: String) -> String {
// do nothing
dump_str
}
}
}
#[cfg(test)]
pub mod test_callbacks {
use binder::{BinderFeatures, Interface, Strong};
use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
IInputFilter::IInputFilterCallbacks::IInputFilterCallbacks,
IInputThread::{BnInputThread, IInputThread, IInputThreadCallback::IInputThreadCallback},
KeyEvent::KeyEvent,
};
use input::ModifierState;
use nix::{sys::time::TimeValLike, time::clock_gettime, time::ClockId};
use std::sync::{atomic::AtomicBool, atomic::Ordering, Arc, RwLock, RwLockWriteGuard};
use std::time::Duration;
#[derive(Default)]
struct TestCallbacksInner {
last_modifier_state: ModifierState,
last_locked_modifier_state: ModifierState,
last_event: Option<KeyEvent>,
test_thread: Option<FakeCppThread>,
}
#[derive(Default, Clone)]
pub struct TestCallbacks(Arc<RwLock<TestCallbacksInner>>);
impl Interface for TestCallbacks {}
impl TestCallbacks {
pub fn new() -> Self {
Default::default()
}
fn inner(&self) -> RwLockWriteGuard<'_, TestCallbacksInner> {
self.0.write().unwrap()
}
pub fn last_event(&self) -> Option<KeyEvent> {
self.0.read().unwrap().last_event
}
pub fn clear(&mut self) {
self.inner().last_event = None;
self.inner().last_modifier_state = ModifierState::None;
self.inner().last_locked_modifier_state = ModifierState::None;
}
pub fn get_last_modifier_state(&self) -> ModifierState {
self.0.read().unwrap().last_modifier_state
}
pub fn get_last_locked_modifier_state(&self) -> ModifierState {
self.0.read().unwrap().last_locked_modifier_state
}
pub fn is_thread_running(&self) -> bool {
if let Some(test_thread) = &self.0.read().unwrap().test_thread {
return test_thread.is_running();
}
false
}
}
impl IInputFilterCallbacks for TestCallbacks {
fn sendKeyEvent(&self, event: &KeyEvent) -> binder::Result<()> {
self.inner().last_event = Some(*event);
Result::Ok(())
}
fn onModifierStateChanged(
&self,
modifier_state: i32,
locked_modifier_state: i32,
) -> std::result::Result<(), binder::Status> {
self.inner().last_modifier_state =
ModifierState::from_bits(modifier_state as u32).unwrap();
self.inner().last_locked_modifier_state =
ModifierState::from_bits(locked_modifier_state as u32).unwrap();
Result::Ok(())
}
fn createInputFilterThread(
&self,
callback: &Strong<dyn IInputThreadCallback>,
) -> std::result::Result<Strong<dyn IInputThread>, binder::Status> {
let test_thread = FakeCppThread::new(callback.clone());
test_thread.start_looper();
self.inner().test_thread = Some(test_thread.clone());
Result::Ok(BnInputThread::new_binder(test_thread, BinderFeatures::default()))
}
}
#[derive(Default)]
struct FakeCppThreadInner {
join_handle: Option<std::thread::JoinHandle<()>>,
}
#[derive(Clone)]
struct FakeCppThread {
callback: Arc<RwLock<Strong<dyn IInputThreadCallback>>>,
inner: Arc<RwLock<FakeCppThreadInner>>,
exit_flag: Arc<AtomicBool>,
}
impl Interface for FakeCppThread {}
impl FakeCppThread {
pub fn new(callback: Strong<dyn IInputThreadCallback>) -> Self {
let thread = Self {
callback: Arc::new(RwLock::new(callback)),
inner: Arc::new(RwLock::new(FakeCppThreadInner { join_handle: None })),
exit_flag: Arc::new(AtomicBool::new(true)),
};
thread.create_looper();
thread
}
fn inner(&self) -> RwLockWriteGuard<'_, FakeCppThreadInner> {
self.inner.write().unwrap()
}
fn create_looper(&self) {
let clone = self.clone();
let join_handle = std::thread::Builder::new()
.name("fake_cpp_thread".to_string())
.spawn(move || loop {
if !clone.exit_flag.load(Ordering::Relaxed) {
clone.loop_once();
}
})
.unwrap();
self.inner().join_handle = Some(join_handle);
// Sleep until the looper thread starts
std::thread::sleep(Duration::from_millis(10));
}
pub fn start_looper(&self) {
self.exit_flag.store(false, Ordering::Relaxed);
}
pub fn stop_looper(&self) {
self.exit_flag.store(true, Ordering::Relaxed);
if let Some(join_handle) = &self.inner.read().unwrap().join_handle {
join_handle.thread().unpark();
}
}
pub fn is_running(&self) -> bool {
!self.exit_flag.load(Ordering::Relaxed)
}
fn loop_once(&self) {
let _ = self.callback.read().unwrap().loopOnce();
}
}
impl IInputThread for FakeCppThread {
fn finish(&self) -> binder::Result<()> {
self.stop_looper();
Result::Ok(())
}
fn wake(&self) -> binder::Result<()> {
if let Some(join_handle) = &self.inner.read().unwrap().join_handle {
join_handle.thread().unpark();
}
Result::Ok(())
}
fn sleepUntil(&self, wake_up_time: i64) -> binder::Result<()> {
let now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_nanoseconds();
if wake_up_time == i64::MAX {
std::thread::park();
} else {
let duration_now = Duration::from_nanos(now as u64);
let duration_wake_up = Duration::from_nanos(wake_up_time as u64);
std::thread::park_timeout(duration_wake_up - duration_now);
}
Result::Ok(())
}
}
}