/* * Copyright (C) 2010 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. */ #define LOG_TAG "InputManager" //#define LOG_NDEBUG 0 #include "InputManager.h" #include "InputDispatcherFactory.h" #include "InputReaderFactory.h" #include "UnwantedInteractionBlocker.h" #include #include #include #include #include #include #include #include namespace input_flags = com::android::input::flags; namespace android { namespace { const bool ENABLE_INPUT_DEVICE_USAGE_METRICS = sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true); const bool ENABLE_INPUT_FILTER_RUST = input_flags::enable_input_filter_rust_impl(); int32_t exceptionCodeFromStatusT(status_t status) { switch (status) { case OK: return binder::Status::EX_NONE; case INVALID_OPERATION: return binder::Status::EX_UNSUPPORTED_OPERATION; case BAD_VALUE: case BAD_TYPE: case NAME_NOT_FOUND: return binder::Status::EX_ILLEGAL_ARGUMENT; case NO_INIT: return binder::Status::EX_ILLEGAL_STATE; case PERMISSION_DENIED: return binder::Status::EX_SECURITY; default: return binder::Status::EX_TRANSACTION_FAILED; } } // Convert a binder interface into a raw pointer to an AIBinder. using IInputFlingerRustBootstrapCallback = aidl::com::android::server::inputflinger:: IInputFlingerRust::IInputFlingerRustBootstrapCallback; IInputFlingerRustBootstrapCallbackAIBinder* binderToPointer( IInputFlingerRustBootstrapCallback& interface) { ndk::SpAIBinder spAIBinder = interface.asBinder(); auto* ptr = spAIBinder.get(); AIBinder_incStrong(ptr); return ptr; } // Create the Rust component of InputFlinger that uses AIDL interfaces as a the foreign function // interface (FFI). The bootstraping process for IInputFlingerRust is as follows: // - Create BnInputFlingerRustBootstrapCallback in C++. // - Use the cxxbridge ffi interface to call the Rust function `create_inputflinger_rust()`, and // pass the callback binder object as a raw pointer. // - The Rust implementation will create the implementation of IInputFlingerRust, and pass it // to C++ through the callback. // - After the Rust function returns, the binder interface provided to the callback will be the // only strong reference to the IInputFlingerRust. std::shared_ptr createInputFlingerRust() { using namespace aidl::com::android::server::inputflinger; class Callback : public IInputFlingerRust::BnInputFlingerRustBootstrapCallback { ndk::ScopedAStatus onProvideInputFlingerRust( const std::shared_ptr& inputFlingerRust) override { mService = inputFlingerRust; return ndk::ScopedAStatus::ok(); } public: std::shared_ptr consumeInputFlingerRust() { auto service = mService; mService.reset(); return service; } private: std::shared_ptr mService; }; auto callback = ndk::SharedRefBase::make(); create_inputflinger_rust(binderToPointer(*callback)); auto service = callback->consumeInputFlingerRust(); LOG_ALWAYS_FATAL_IF(!service, "create_inputflinger_rust did not provide the IInputFlingerRust " "implementation through the callback."); return service; } } // namespace /** * The event flow is via the "InputListener" interface, as follows: * InputReader * -> UnwantedInteractionBlocker * -> InputFilter * -> PointerChoreographer * -> InputProcessor * -> InputDeviceMetricsCollector * -> InputDispatcher */ InputManager::InputManager(const sp& readerPolicy, InputDispatcherPolicyInterface& dispatcherPolicy, PointerChoreographerPolicyInterface& choreographerPolicy, InputFilterPolicyInterface& inputFilterPolicy) { mInputFlingerRust = createInputFlingerRust(); mDispatcher = createInputDispatcher(dispatcherPolicy); mTracingStages.emplace_back( std::make_unique("InputDispatcher", *mDispatcher)); if (ENABLE_INPUT_FILTER_RUST) { mInputFilter = std::make_unique(*mTracingStages.back(), *mInputFlingerRust, inputFilterPolicy); mTracingStages.emplace_back( std::make_unique("InputFilter", *mInputFilter)); } if (ENABLE_INPUT_DEVICE_USAGE_METRICS) { mCollector = std::make_unique(*mTracingStages.back()); mTracingStages.emplace_back( std::make_unique("MetricsCollector", *mCollector)); } mProcessor = std::make_unique(*mTracingStages.back()); mTracingStages.emplace_back( std::make_unique("InputProcessor", *mProcessor)); mChoreographer = std::make_unique(*mTracingStages.back(), choreographerPolicy); mTracingStages.emplace_back( std::make_unique("PointerChoreographer", *mChoreographer)); mBlocker = std::make_unique(*mTracingStages.back()); mTracingStages.emplace_back( std::make_unique("UnwantedInteractionBlocker", *mBlocker)); mReader = createInputReader(readerPolicy, *mTracingStages.back()); } InputManager::~InputManager() { stop(); } status_t InputManager::start() { status_t result = mDispatcher->start(); if (result) { ALOGE("Could not start InputDispatcher thread due to error %d.", result); return result; } result = mReader->start(); if (result) { ALOGE("Could not start InputReader due to error %d.", result); mDispatcher->stop(); return result; } return OK; } status_t InputManager::stop() { status_t status = OK; status_t result = mReader->stop(); if (result) { ALOGW("Could not stop InputReader due to error %d.", result); status = result; } result = mDispatcher->stop(); if (result) { ALOGW("Could not stop InputDispatcher thread due to error %d.", result); status = result; } return status; } InputReaderInterface& InputManager::getReader() { return *mReader; } PointerChoreographerInterface& InputManager::getChoreographer() { return *mChoreographer; } InputProcessorInterface& InputManager::getProcessor() { return *mProcessor; } InputDeviceMetricsCollectorInterface& InputManager::getMetricsCollector() { return *mCollector; } InputDispatcherInterface& InputManager::getDispatcher() { return *mDispatcher; } InputFilterInterface& InputManager::getInputFilter() { return *mInputFilter; } void InputManager::monitor() { mReader->monitor(); mBlocker->monitor(); mProcessor->monitor(); if (ENABLE_INPUT_DEVICE_USAGE_METRICS) { mCollector->monitor(); } mDispatcher->monitor(); } void InputManager::dump(std::string& dump) { mReader->dump(dump); dump += '\n'; mBlocker->dump(dump); dump += '\n'; mChoreographer->dump(dump); dump += '\n'; mProcessor->dump(dump); dump += '\n'; if (ENABLE_INPUT_DEVICE_USAGE_METRICS) { mCollector->dump(dump); dump += '\n'; } mDispatcher->dump(dump); dump += '\n'; } // Used by tests only. binder::Status InputManager::createInputChannel(const std::string& name, android::os::InputChannelCore* outChannel) { IPCThreadState* ipc = IPCThreadState::self(); const uid_t uid = ipc->getCallingUid(); if (uid != AID_SHELL && uid != AID_ROOT) { LOG(ERROR) << __func__ << " can only be called by SHELL or ROOT users, " << "but was called from UID " << uid; return binder::Status:: fromExceptionCode(EX_SECURITY, "This uid is not allowed to call createInputChannel"); } base::Result> channel = mDispatcher->createInputChannel(name); if (!channel.ok()) { return binder::Status::fromExceptionCode(exceptionCodeFromStatusT(channel.error().code()), channel.error().message().c_str()); } InputChannel::moveChannel(std::move(*channel), *outChannel); return binder::Status::ok(); } binder::Status InputManager::removeInputChannel(const sp& connectionToken) { mDispatcher->removeInputChannel(connectionToken); return binder::Status::ok(); } status_t InputManager::dump(int fd, const Vector& args) { std::string dump; dump += " InputFlinger dump\n"; TEMP_FAILURE_RETRY(::write(fd, dump.c_str(), dump.size())); return NO_ERROR; } binder::Status InputManager::setFocusedWindow(const gui::FocusRequest& request) { mDispatcher->setFocusedWindow(request); return binder::Status::ok(); } } // namespace android