| /* |
| * 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 <android/sysprop/InputProperties.sysprop.h> |
| #include <binder/IPCThreadState.h> |
| |
| #include <log/log.h> |
| #include <unordered_map> |
| |
| #include <private/android_filesystem_config.h> |
| |
| namespace android { |
| |
| static const bool ENABLE_INPUT_DEVICE_USAGE_METRICS = |
| sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true); |
| |
| using gui::FocusRequest; |
| |
| static 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; |
| } |
| } |
| |
| /** |
| * The event flow is via the "InputListener" interface, as follows: |
| * InputReader |
| * -> UnwantedInteractionBlocker |
| * -> InputProcessor |
| * -> InputDeviceMetricsCollector |
| * -> InputDispatcher |
| */ |
| InputManager::InputManager(const sp<InputReaderPolicyInterface>& readerPolicy, |
| InputDispatcherPolicyInterface& dispatcherPolicy) { |
| mDispatcher = createInputDispatcher(dispatcherPolicy); |
| |
| if (ENABLE_INPUT_DEVICE_USAGE_METRICS) { |
| mCollector = std::make_unique<InputDeviceMetricsCollector>(*mDispatcher); |
| } |
| |
| mProcessor = ENABLE_INPUT_DEVICE_USAGE_METRICS ? std::make_unique<InputProcessor>(*mCollector) |
| : std::make_unique<InputProcessor>(*mDispatcher); |
| mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mProcessor); |
| mReader = createInputReader(readerPolicy, *mBlocker); |
| } |
| |
| 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; |
| } |
| |
| InputProcessorInterface& InputManager::getProcessor() { |
| return *mProcessor; |
| } |
| |
| InputDeviceMetricsCollectorInterface& InputManager::getMetricsCollector() { |
| return *mCollector; |
| } |
| |
| InputDispatcherInterface& InputManager::getDispatcher() { |
| return *mDispatcher; |
| } |
| |
| void InputManager::monitor() { |
| mReader->monitor(); |
| mBlocker->monitor(); |
| mProcessor->monitor(); |
| mDispatcher->monitor(); |
| } |
| |
| void InputManager::dump(std::string& dump) { |
| mReader->dump(dump); |
| dump += '\n'; |
| mBlocker->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, InputChannel* outChannel) { |
| IPCThreadState* ipc = IPCThreadState::self(); |
| const int uid = ipc->getCallingUid(); |
| if (uid != AID_SHELL && uid != AID_ROOT) { |
| ALOGE("Invalid attempt to register input channel over IPC" |
| "from non shell/root entity (PID: %d)", ipc->getCallingPid()); |
| return binder::Status::ok(); |
| } |
| |
| base::Result<std::unique_ptr<InputChannel>> channel = mDispatcher->createInputChannel(name); |
| if (!channel.ok()) { |
| return binder::Status::fromExceptionCode(exceptionCodeFromStatusT(channel.error().code()), |
| channel.error().message().c_str()); |
| } |
| (*channel)->copyTo(*outChannel); |
| return binder::Status::ok(); |
| } |
| |
| binder::Status InputManager::removeInputChannel(const sp<IBinder>& connectionToken) { |
| mDispatcher->removeInputChannel(connectionToken); |
| return binder::Status::ok(); |
| } |
| |
| status_t InputManager::dump(int fd, const Vector<String16>& args) { |
| std::string dump; |
| |
| dump += " InputFlinger dump\n"; |
| |
| ::write(fd, dump.c_str(), dump.size()); |
| return NO_ERROR; |
| } |
| |
| binder::Status InputManager::setFocusedWindow(const FocusRequest& request) { |
| mDispatcher->setFocusedWindow(request); |
| return binder::Status::ok(); |
| } |
| |
| } // namespace android |