| /* |
| * Copyright (C) 2019 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 "InputDispatcher" |
| |
| #include "Entry.h" |
| |
| #include "Connection.h" |
| #include "DebugConfig.h" |
| |
| #include <android-base/stringprintf.h> |
| #include <cutils/atomic.h> |
| #include <inttypes.h> |
| |
| using android::base::StringPrintf; |
| |
| namespace android::inputdispatcher { |
| |
| VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry) { |
| return {{VerifiedInputEvent::Type::KEY, entry.deviceId, entry.eventTime, entry.source, |
| entry.displayId}, |
| entry.action, |
| entry.flags & VERIFIED_KEY_EVENT_FLAGS, |
| entry.downTime, |
| entry.keyCode, |
| entry.scanCode, |
| entry.metaState, |
| entry.repeatCount}; |
| } |
| |
| VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry, |
| const ui::Transform& rawTransform) { |
| const vec2 rawXY = MotionEvent::calculateTransformedXY(entry.source, rawTransform, |
| entry.pointerCoords[0].getXYValue()); |
| const int actionMasked = entry.action & AMOTION_EVENT_ACTION_MASK; |
| return {{VerifiedInputEvent::Type::MOTION, entry.deviceId, entry.eventTime, entry.source, |
| entry.displayId}, |
| rawXY.x, |
| rawXY.y, |
| actionMasked, |
| entry.flags & VERIFIED_MOTION_EVENT_FLAGS, |
| entry.downTime, |
| entry.metaState, |
| entry.buttonState}; |
| } |
| |
| // --- EventEntry --- |
| |
| EventEntry::EventEntry(int32_t id, Type type, nsecs_t eventTime, uint32_t policyFlags) |
| : id(id), |
| type(type), |
| eventTime(eventTime), |
| policyFlags(policyFlags), |
| injectionState(nullptr), |
| dispatchInProgress(false) {} |
| |
| // --- ConfigurationChangedEntry --- |
| |
| ConfigurationChangedEntry::ConfigurationChangedEntry(int32_t id, nsecs_t eventTime) |
| : EventEntry(id, Type::CONFIGURATION_CHANGED, eventTime, 0) {} |
| |
| std::string ConfigurationChangedEntry::getDescription() const { |
| return StringPrintf("ConfigurationChangedEvent(), policyFlags=0x%08x", policyFlags); |
| } |
| |
| // --- DeviceResetEntry --- |
| |
| DeviceResetEntry::DeviceResetEntry(int32_t id, nsecs_t eventTime, int32_t deviceId) |
| : EventEntry(id, Type::DEVICE_RESET, eventTime, 0), deviceId(deviceId) {} |
| |
| std::string DeviceResetEntry::getDescription() const { |
| return StringPrintf("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", deviceId, policyFlags); |
| } |
| |
| // --- FocusEntry --- |
| |
| // Focus notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER for all entries |
| FocusEntry::FocusEntry(int32_t id, nsecs_t eventTime, sp<IBinder> connectionToken, bool hasFocus, |
| const std::string& reason) |
| : EventEntry(id, Type::FOCUS, eventTime, POLICY_FLAG_PASS_TO_USER), |
| connectionToken(connectionToken), |
| hasFocus(hasFocus), |
| reason(reason) {} |
| |
| std::string FocusEntry::getDescription() const { |
| return StringPrintf("FocusEvent(hasFocus=%s)", hasFocus ? "true" : "false"); |
| } |
| |
| // --- PointerCaptureChangedEntry --- |
| |
| // PointerCaptureChanged notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER |
| // for all entries. |
| PointerCaptureChangedEntry::PointerCaptureChangedEntry(int32_t id, nsecs_t eventTime, |
| const PointerCaptureRequest& request) |
| : EventEntry(id, Type::POINTER_CAPTURE_CHANGED, eventTime, POLICY_FLAG_PASS_TO_USER), |
| pointerCaptureRequest(request) {} |
| |
| std::string PointerCaptureChangedEntry::getDescription() const { |
| return StringPrintf("PointerCaptureChangedEvent(pointerCaptureEnabled=%s)", |
| pointerCaptureRequest.enable ? "true" : "false"); |
| } |
| |
| // --- DragEntry --- |
| |
| // Drag notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER for all entries |
| DragEntry::DragEntry(int32_t id, nsecs_t eventTime, sp<IBinder> connectionToken, bool isExiting, |
| float x, float y) |
| : EventEntry(id, Type::DRAG, eventTime, POLICY_FLAG_PASS_TO_USER), |
| connectionToken(connectionToken), |
| isExiting(isExiting), |
| x(x), |
| y(y) {} |
| |
| std::string DragEntry::getDescription() const { |
| return StringPrintf("DragEntry(isExiting=%s, x=%f, y=%f)", isExiting ? "true" : "false", x, y); |
| } |
| |
| // --- KeyEntry --- |
| |
| KeyEntry::KeyEntry(int32_t id, std::shared_ptr<InjectionState> injectionState, nsecs_t eventTime, |
| int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, |
| int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, |
| int32_t metaState, int32_t repeatCount, nsecs_t downTime) |
| : EventEntry(id, Type::KEY, eventTime, policyFlags), |
| deviceId(deviceId), |
| source(source), |
| displayId(displayId), |
| action(action), |
| keyCode(keyCode), |
| scanCode(scanCode), |
| metaState(metaState), |
| downTime(downTime), |
| syntheticRepeat(false), |
| interceptKeyResult(KeyEntry::InterceptKeyResult::UNKNOWN), |
| interceptKeyWakeupTime(0), |
| flags(flags), |
| repeatCount(repeatCount) { |
| EventEntry::injectionState = std::move(injectionState); |
| } |
| |
| std::string KeyEntry::getDescription() const { |
| if (!IS_DEBUGGABLE_BUILD) { |
| return "KeyEvent"; |
| } |
| return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64 ", source=%s, displayId=%" PRId32 |
| ", action=%s, " |
| "flags=0x%08x, keyCode=%s(%d), scanCode=%d, metaState=0x%08x, " |
| "repeatCount=%d), policyFlags=0x%08x", |
| deviceId, eventTime, inputEventSourceToString(source).c_str(), displayId, |
| KeyEvent::actionToString(action), flags, KeyEvent::getLabel(keyCode), |
| keyCode, scanCode, metaState, repeatCount, policyFlags); |
| } |
| |
| std::ostream& operator<<(std::ostream& out, const KeyEntry& keyEntry) { |
| out << keyEntry.getDescription(); |
| return out; |
| } |
| |
| // --- TouchModeEntry --- |
| |
| TouchModeEntry::TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode, int displayId) |
| : EventEntry(id, Type::TOUCH_MODE_CHANGED, eventTime, POLICY_FLAG_PASS_TO_USER), |
| inTouchMode(inTouchMode), |
| displayId(displayId) {} |
| |
| std::string TouchModeEntry::getDescription() const { |
| return StringPrintf("TouchModeEvent(inTouchMode=%s)", inTouchMode ? "true" : "false"); |
| } |
| |
| // --- MotionEntry --- |
| |
| MotionEntry::MotionEntry(int32_t id, std::shared_ptr<InjectionState> injectionState, |
| nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId, |
| uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, |
| int32_t metaState, int32_t buttonState, |
| MotionClassification classification, int32_t edgeFlags, float xPrecision, |
| float yPrecision, float xCursorPosition, float yCursorPosition, |
| nsecs_t downTime, const std::vector<PointerProperties>& pointerProperties, |
| const std::vector<PointerCoords>& pointerCoords) |
| : EventEntry(id, Type::MOTION, eventTime, policyFlags), |
| deviceId(deviceId), |
| source(source), |
| displayId(displayId), |
| action(action), |
| actionButton(actionButton), |
| flags(flags), |
| metaState(metaState), |
| buttonState(buttonState), |
| classification(classification), |
| edgeFlags(edgeFlags), |
| xPrecision(xPrecision), |
| yPrecision(yPrecision), |
| xCursorPosition(xCursorPosition), |
| yCursorPosition(yCursorPosition), |
| downTime(downTime), |
| pointerProperties(pointerProperties), |
| pointerCoords(pointerCoords) { |
| EventEntry::injectionState = std::move(injectionState); |
| } |
| |
| std::string MotionEntry::getDescription() const { |
| if (!IS_DEBUGGABLE_BUILD) { |
| return "MotionEvent"; |
| } |
| std::string msg; |
| msg += StringPrintf("MotionEvent(deviceId=%d, eventTime=%" PRIu64 |
| ", source=%s, displayId=%" PRId32 |
| ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, " |
| "buttonState=0x%08x, " |
| "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, " |
| "xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[", |
| deviceId, eventTime, inputEventSourceToString(source).c_str(), displayId, |
| MotionEvent::actionToString(action).c_str(), actionButton, flags, metaState, |
| buttonState, motionClassificationToString(classification), edgeFlags, |
| xPrecision, yPrecision, xCursorPosition, yCursorPosition); |
| |
| for (uint32_t i = 0; i < getPointerCount(); i++) { |
| if (i) { |
| msg += ", "; |
| } |
| msg += StringPrintf("%d: (%.1f, %.1f)", pointerProperties[i].id, pointerCoords[i].getX(), |
| pointerCoords[i].getY()); |
| } |
| msg += StringPrintf("]), policyFlags=0x%08x", policyFlags); |
| return msg; |
| } |
| |
| std::ostream& operator<<(std::ostream& out, const MotionEntry& motionEntry) { |
| out << motionEntry.getDescription(); |
| return out; |
| } |
| |
| // --- SensorEntry --- |
| |
| SensorEntry::SensorEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, |
| uint32_t policyFlags, nsecs_t hwTimestamp, |
| InputDeviceSensorType sensorType, InputDeviceSensorAccuracy accuracy, |
| bool accuracyChanged, std::vector<float> values) |
| : EventEntry(id, Type::SENSOR, eventTime, policyFlags), |
| deviceId(deviceId), |
| source(source), |
| sensorType(sensorType), |
| accuracy(accuracy), |
| accuracyChanged(accuracyChanged), |
| hwTimestamp(hwTimestamp), |
| values(std::move(values)) {} |
| |
| std::string SensorEntry::getDescription() const { |
| std::string msg; |
| msg += StringPrintf("SensorEntry(deviceId=%d, source=%s, sensorType=%s, " |
| "accuracy=0x%08x, hwTimestamp=%" PRId64, |
| deviceId, inputEventSourceToString(source).c_str(), |
| ftl::enum_string(sensorType).c_str(), accuracy, hwTimestamp); |
| |
| if (IS_DEBUGGABLE_BUILD) { |
| for (size_t i = 0; i < values.size(); i++) { |
| if (i > 0) { |
| msg += ", "; |
| } |
| msg += StringPrintf("(%.3f)", values[i]); |
| } |
| } |
| msg += StringPrintf(", policyFlags=0x%08x", policyFlags); |
| return msg; |
| } |
| |
| // --- DispatchEntry --- |
| |
| volatile int32_t DispatchEntry::sNextSeqAtomic; |
| |
| DispatchEntry::DispatchEntry(std::shared_ptr<const EventEntry> eventEntry, |
| ftl::Flags<InputTargetFlags> targetFlags, |
| const ui::Transform& transform, const ui::Transform& rawTransform, |
| float globalScaleFactor, gui::Uid targetUid, int64_t vsyncId, |
| std::optional<int32_t> windowId) |
| : seq(nextSeq()), |
| eventEntry(std::move(eventEntry)), |
| targetFlags(targetFlags), |
| transform(transform), |
| rawTransform(rawTransform), |
| globalScaleFactor(globalScaleFactor), |
| deliveryTime(0), |
| resolvedFlags(0), |
| targetUid(targetUid), |
| vsyncId(vsyncId), |
| windowId(windowId) { |
| switch (this->eventEntry->type) { |
| case EventEntry::Type::KEY: { |
| const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*this->eventEntry); |
| resolvedFlags = keyEntry.flags; |
| break; |
| } |
| case EventEntry::Type::MOTION: { |
| const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*this->eventEntry); |
| resolvedFlags = motionEntry.flags; |
| break; |
| } |
| default: { |
| break; |
| } |
| } |
| } |
| |
| uint32_t DispatchEntry::nextSeq() { |
| // Sequence number 0 is reserved and will never be returned. |
| uint32_t seq; |
| do { |
| seq = android_atomic_inc(&sNextSeqAtomic); |
| } while (!seq); |
| return seq; |
| } |
| |
| std::ostream& operator<<(std::ostream& out, const DispatchEntry& entry) { |
| std::string transform; |
| entry.transform.dump(transform, "transform"); |
| out << "DispatchEntry{resolvedFlags=" << entry.resolvedFlags |
| << ", targetFlags=" << entry.targetFlags.string() << ", transform=" << transform |
| << "} original: " << entry.eventEntry->getDescription(); |
| return out; |
| } |
| |
| } // namespace android::inputdispatcher |