/* * 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. */ //! # The rust component of InputFlinger //! //! We use cxxbridge to create IInputFlingerRust - the Rust component of inputflinger - and //! pass it back to C++ as a local AIDL interface. mod bounce_keys_filter; mod input_filter; mod input_filter_thread; mod slow_keys_filter; mod sticky_keys_filter; use crate::input_filter::InputFilter; use binder::{ unstable_api::{new_spibinder, AIBinder}, BinderFeatures, Interface, StatusCode, Strong, }; use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{ IInputFilter::{BnInputFilter, IInputFilter, IInputFilterCallbacks::IInputFilterCallbacks}, IInputFlingerRust::{ BnInputFlingerRust, IInputFlingerRust, IInputFlingerRustBootstrapCallback::IInputFlingerRustBootstrapCallback, }, }; use log::debug; const LOG_TAG: &str = "inputflinger_bootstrap"; #[cxx::bridge] #[allow(unsafe_op_in_unsafe_fn)] mod ffi { extern "C++" { include!("InputFlingerBootstrap.h"); type IInputFlingerRustBootstrapCallbackAIBinder; } extern "Rust" { unsafe fn create_inputflinger_rust( callback: *mut IInputFlingerRustBootstrapCallbackAIBinder, ); } } /// Create the IInputFlingerRust implementation. /// This is the singular entry point from C++ into Rust. /// The `callback` parameter must be a valid pointer to an AIBinder implementation of /// the `IInputFlingerRustBootstrapCallback` interface. The IInputFlingerRust implementation that /// is created will be passed back through the callback from within this function. /// NOTE: This function must not hold a strong reference to the callback beyond its scope. /// /// # Safety /// /// The provided `callback` must be a valid pointer to an `AIBinder` interface of type /// `IInputFlingerRustBootstrapCallback`, and the caller must give this function ownership of one /// strong refcount to the interface. See `binder::unstable_api::new_spibinder`. unsafe fn create_inputflinger_rust(callback: *mut ffi::IInputFlingerRustBootstrapCallbackAIBinder) { logger::init( logger::Config::default() .with_tag_on_device(LOG_TAG) .with_max_level(log::LevelFilter::Trace), ); let callback = callback as *mut AIBinder; if callback.is_null() { panic!("create_inputflinger_rust cannot be called with a null callback"); } // SAFETY: Our caller guaranteed that `callback` is a valid pointer to an `AIBinder` and its // reference count has been incremented.. let Some(callback) = (unsafe { new_spibinder(callback) }) else { panic!("Failed to get SpAIBinder from raw callback pointer"); }; let callback: Result, StatusCode> = callback.into_interface(); match callback { Ok(callback) => { debug!("Creating InputFlingerRust"); let service = BnInputFlingerRust::new_binder(InputFlingerRust {}, BinderFeatures::default()); callback.onProvideInputFlingerRust(&service).unwrap(); } Err(status) => { panic!("Failed to convert AIBinder into the callback interface: {}", status); } } } struct InputFlingerRust {} impl Interface for InputFlingerRust {} impl IInputFlingerRust for InputFlingerRust { fn createInputFilter( &self, callbacks: &Strong, ) -> binder::Result> { debug!("Creating InputFilter"); let filter = BnInputFilter::new_binder( InputFilter::new(callbacks.clone()), BinderFeatures::default(), ); Result::Ok(filter) } } impl Drop for InputFlingerRust { fn drop(&mut self) { debug!("Destroying InputFlingerRust"); } }