Loading libs/input/android/os/InputEventInjectionResult.aidl +2 −3 Original line number Diff line number Diff line Loading @@ -29,9 +29,8 @@ enum InputEventInjectionResult { /* Injection succeeded. */ SUCCEEDED = 0, /* Injection failed because the injector did not have permission to inject * into the application with input focus. */ PERMISSION_DENIED = 1, /* Injection failed because the injected event did not target the appropriate window. */ TARGET_MISMATCH = 1, /* Injection failed because there were no available input targets. */ FAILED = 2, Loading services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +10 −12 Original line number Diff line number Diff line Loading @@ -31,11 +31,11 @@ using android::os::InputEventInjectionSync; namespace android::inputdispatcher { // An arbitrary device id. static const int32_t DEVICE_ID = 1; constexpr int32_t DEVICE_ID = 1; // An arbitrary injector pid / uid pair that has permission to inject events. static const int32_t INJECTOR_PID = 999; static const int32_t INJECTOR_UID = 1001; // The default pid and uid for windows created by the test. constexpr int32_t WINDOW_PID = 999; constexpr int32_t WINDOW_UID = 1001; static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s; static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms; Loading Loading @@ -106,8 +106,6 @@ private: void pokeUserActivity(nsecs_t, int32_t, int32_t) override {} bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override { return false; } void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {} void setPointerCapture(const PointerCaptureRequest&) override {} Loading Loading @@ -194,8 +192,8 @@ public: mInfo.globalScaleFactor = 1.0; mInfo.touchableRegion.clear(); mInfo.addTouchableRegion(mFrame); mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.ownerPid = WINDOW_PID; mInfo.ownerUid = WINDOW_UID; mInfo.displayId = ADISPLAY_ID_DEFAULT; } Loading Loading @@ -308,14 +306,14 @@ static void benchmarkInjectMotion(benchmark::State& state) { for (auto _ : state) { MotionEvent event = generateMotionEvent(); // Send ACTION_DOWN dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); // Send ACTION_UP event.setAction(AMOTION_EVENT_ACTION_UP); dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); window->consumeEvent(); Loading services/inputflinger/dispatcher/InjectionState.cpp +2 −3 Original line number Diff line number Diff line Loading @@ -20,10 +20,9 @@ namespace android::inputdispatcher { InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) InjectionState::InjectionState(const std::optional<int32_t>& targetUid) : refCount(1), injectorPid(injectorPid), injectorUid(injectorUid), targetUid(targetUid), injectionResult(android::os::InputEventInjectionResult::PENDING), injectionIsAsync(false), pendingForegroundDispatches(0) {} Loading services/inputflinger/dispatcher/InjectionState.h +2 −3 Original line number Diff line number Diff line Loading @@ -27,13 +27,12 @@ namespace inputdispatcher { struct InjectionState { mutable int32_t refCount; int32_t injectorPid; int32_t injectorUid; std::optional<int32_t> targetUid; android::os::InputEventInjectionResult injectionResult; // initially PENDING bool injectionIsAsync; // set to true if injection is not waiting for the result int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress InjectionState(int32_t injectorPid, int32_t injectorUid); explicit InjectionState(const std::optional<int32_t>& targetUid); void release(); private: Loading services/inputflinger/dispatcher/InputDispatcher.cpp +87 −81 Original line number Diff line number Diff line Loading @@ -577,6 +577,27 @@ bool isWindowOwnedBy(const sp<WindowInfoHandle>& windowHandle, int32_t pid, int3 return false; } // Checks targeted injection using the window's owner's uid. // Returns an empty string if an entry can be sent to the given window, or an error message if the // entry is a targeted injection whose uid target doesn't match the window owner. std::optional<std::string> verifyTargetedInjection(const sp<WindowInfoHandle>& window, const EventEntry& entry) { if (entry.injectionState == nullptr || !entry.injectionState->targetUid) { // The event was not injected, or the injected event does not target a window. return {}; } const int32_t uid = *entry.injectionState->targetUid; if (window == nullptr) { return StringPrintf("No valid window target for injection into uid %d.", uid); } if (entry.injectionState->targetUid != window->getInfo()->ownerUid) { return StringPrintf("Injected event targeted at uid %d would be dispatched to window '%s' " "owned by uid %d.", uid, window->getName().c_str(), window->getInfo()->ownerUid); } return {}; } } // namespace // --- InputDispatcher --- Loading Loading @@ -1035,6 +1056,8 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE switch (entry.type) { case EventEntry::Type::KEY: { LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0, "Unexpected untrusted event."); // Optimize app switch latency. // If the application takes too long to catch up then we drop all events preceding // the app switch key. Loading Loading @@ -1072,6 +1095,8 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE } case EventEntry::Type::MOTION: { LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0, "Unexpected untrusted event."); if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(entry))) { mNextUnblockedEvent = mInboundQueue.back(); needWake = true; Loading Loading @@ -1719,8 +1744,7 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< } setInjectionResult(*entry, injectionResult); if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) { ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent)); if (injectionResult == InputEventInjectionResult::TARGET_MISMATCH) { return true; } if (injectionResult != InputEventInjectionResult::SUCCEEDED) { Loading Loading @@ -1977,9 +2001,10 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( // we have a valid, non-null focused window resetNoFocusedWindowTimeoutLocked(); // Check permissions. if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) { return InputEventInjectionResult::PERMISSION_DENIED; // Verify targeted injection. if (const auto err = verifyTargetedInjection(focusedWindowHandle, entry); err) { ALOGW("Dropping injected event: %s", (*err).c_str()); return InputEventInjectionResult::TARGET_MISMATCH; } if (focusedWindowHandle->getInfo()->inputConfig.test( Loading Loading @@ -2045,11 +2070,6 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) { ATRACE_CALL(); enum InjectionPermission { INJECTION_PERMISSION_UNKNOWN, INJECTION_PERMISSION_GRANTED, INJECTION_PERMISSION_DENIED }; // For security reasons, we defer updating the touch state until we are sure that // event injection will be allowed. Loading @@ -2059,7 +2079,6 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // Update the touch state as needed based on the properties of the touch event. InputEventInjectionResult injectionResult = InputEventInjectionResult::PENDING; InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; sp<WindowInfoHandle> newHoverWindowHandle(mLastHoverWindowHandle); sp<WindowInfoHandle> newTouchedWindowHandle; Loading Loading @@ -2108,7 +2127,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( "in display %" PRId32, displayId); // TODO: test multiple simultaneous input streams. injectionResult = InputEventInjectionResult::PERMISSION_DENIED; injectionResult = InputEventInjectionResult::FAILED; switchedDevice = false; wrongDevice = true; goto Failed; Loading Loading @@ -2141,6 +2160,14 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); } // Verify targeted injection. if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) { ALOGW("Dropping injected touch event: %s", (*err).c_str()); injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH; newTouchedWindowHandle = nullptr; goto Failed; } // Figure out whether splitting will be allowed for this window. if (newTouchedWindowHandle != nullptr) { if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { Loading Loading @@ -2184,6 +2211,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) { const WindowInfo& info = *windowHandle->getInfo(); // Skip spy window targets that are not valid for targeted injection. if (const auto err = verifyTargetedInjection(windowHandle, entry); err) { continue; } if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) { ALOGI("Not sending touch event to %s because it is paused", windowHandle->getName().c_str()); Loading Loading @@ -2271,6 +2303,14 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isStylus); // Verify targeted injection. if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) { ALOGW("Dropping injected event: %s", (*err).c_str()); injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH; newTouchedWindowHandle = nullptr; goto Failed; } // Drop touch events if requested by input feature if (newTouchedWindowHandle != nullptr && shouldDropInput(entry, newTouchedWindowHandle)) { Loading Loading @@ -2362,19 +2402,26 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( goto Failed; } // Check permission to inject into all touched foreground windows. if (std::any_of(tempTouchState.windows.begin(), tempTouchState.windows.end(), [this, &entry](const TouchedWindow& touchedWindow) { return (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0 && !checkInjectionPermission(touchedWindow.windowHandle, entry.injectionState); })) { injectionResult = InputEventInjectionResult::PERMISSION_DENIED; injectionPermission = INJECTION_PERMISSION_DENIED; // Ensure that all touched windows are valid for injection. if (entry.injectionState != nullptr) { std::string errs; for (const TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { // Allow ACTION_OUTSIDE events generated by targeted injection to be // dispatched to any uid, since the coords will be zeroed out later. continue; } const auto err = verifyTargetedInjection(touchedWindow.windowHandle, entry); if (err) errs += "\n - " + *err; } if (!errs.empty()) { ALOGW("Dropping targeted injection: At least one touched window is not owned by uid " "%d:%s", *entry.injectionState->targetUid, errs.c_str()); injectionResult = InputEventInjectionResult::TARGET_MISMATCH; goto Failed; } // Permission granted to inject into all touched foreground windows. injectionPermission = INJECTION_PERMISSION_GRANTED; } // Check whether windows listening for outside touches are owned by the same UID. If it is // set the policy flag that we will not reveal coordinate information to this window. Loading Loading @@ -2440,19 +2487,6 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( tempTouchState.filterNonAsIsTouchWindows(); Failed: // Check injection permission once and for all. if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) { if (checkInjectionPermission(nullptr, entry.injectionState)) { injectionPermission = INJECTION_PERMISSION_GRANTED; } else { injectionPermission = INJECTION_PERMISSION_DENIED; } } if (injectionPermission != INJECTION_PERMISSION_GRANTED) { return injectionResult; } // Update final pieces of touch state if the injector had permission. if (!wrongDevice) { if (switchedDevice) { Loading Loading @@ -2650,26 +2684,6 @@ void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& } } bool InputDispatcher::checkInjectionPermission(const sp<WindowInfoHandle>& windowHandle, const InjectionState* injectionState) { if (injectionState && (windowHandle == nullptr || windowHandle->getInfo()->ownerUid != injectionState->injectorUid) && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { if (windowHandle != nullptr) { ALOGW("Permission denied: injecting event from pid %d uid %d to window %s " "owned by uid %d", injectionState->injectorPid, injectionState->injectorUid, windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid); } else { ALOGW("Permission denied: injecting event from pid %d uid %d", injectionState->injectorPid, injectionState->injectorUid); } return false; } return true; } /** * Indicate whether one window handle should be considered as obscuring * another window handle. We only check a few preconditions. Actually Loading Loading @@ -4188,20 +4202,20 @@ void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChan } } InputEventInjectionResult InputDispatcher::injectInputEvent( const InputEvent* event, int32_t injectorPid, int32_t injectorUid, InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) { InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* event, std::optional<int32_t> targetUid, InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) { if (DEBUG_INBOUND_EVENT_DETAILS) { ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " "syncMode=%d, timeout=%lld, policyFlags=0x%08x", event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags); ALOGD("injectInputEvent - eventType=%d, targetUid=%s, syncMode=%d, timeout=%lld, " "policyFlags=0x%08x", event->getType(), targetUid ? std::to_string(*targetUid).c_str() : "none", syncMode, timeout.count(), policyFlags); } nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count(); policyFlags |= POLICY_FLAG_INJECTED; if (hasInjectionPermission(injectorPid, injectorUid)) { policyFlags |= POLICY_FLAG_TRUSTED; } policyFlags |= POLICY_FLAG_INJECTED | POLICY_FLAG_TRUSTED; // For all injected events, set device id = VIRTUAL_KEYBOARD_ID. The only exception is events // that have gone through the InputFilter. If the event passed through the InputFilter, assign Loading Loading @@ -4342,7 +4356,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( return InputEventInjectionResult::FAILED; } InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); InjectionState* injectionState = new InjectionState(targetUid); if (syncMode == InputEventInjectionSync::NONE) { injectionState->injectionIsAsync = true; } Loading Loading @@ -4414,8 +4428,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( } // release lock if (DEBUG_INJECTION) { ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d", injectionResult, injectorPid, injectorUid); ALOGD("injectInputEvent - Finished with result %d.", injectionResult); } return injectionResult; Loading Loading @@ -4454,19 +4467,12 @@ std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const Inpu return result; } bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { return injectorUid == 0 || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); } void InputDispatcher::setInjectionResult(EventEntry& entry, InputEventInjectionResult injectionResult) { InjectionState* injectionState = entry.injectionState; if (injectionState) { if (DEBUG_INJECTION) { ALOGD("Setting input event injection result to %d. " "injectorPid=%d, injectorUid=%d", injectionResult, injectionState->injectorPid, injectionState->injectorUid); ALOGD("Setting input event injection result to %d.", injectionResult); } if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) { Loading @@ -4475,12 +4481,12 @@ void InputDispatcher::setInjectionResult(EventEntry& entry, case InputEventInjectionResult::SUCCEEDED: ALOGV("Asynchronous input event injection succeeded."); break; case InputEventInjectionResult::TARGET_MISMATCH: ALOGV("Asynchronous input event injection target mismatch."); break; case InputEventInjectionResult::FAILED: ALOGW("Asynchronous input event injection failed."); break; case InputEventInjectionResult::PERMISSION_DENIED: ALOGW("Asynchronous input event injection permission denied."); break; case InputEventInjectionResult::TIMED_OUT: ALOGW("Asynchronous input event injection timed out."); break; Loading Loading
libs/input/android/os/InputEventInjectionResult.aidl +2 −3 Original line number Diff line number Diff line Loading @@ -29,9 +29,8 @@ enum InputEventInjectionResult { /* Injection succeeded. */ SUCCEEDED = 0, /* Injection failed because the injector did not have permission to inject * into the application with input focus. */ PERMISSION_DENIED = 1, /* Injection failed because the injected event did not target the appropriate window. */ TARGET_MISMATCH = 1, /* Injection failed because there were no available input targets. */ FAILED = 2, Loading
services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +10 −12 Original line number Diff line number Diff line Loading @@ -31,11 +31,11 @@ using android::os::InputEventInjectionSync; namespace android::inputdispatcher { // An arbitrary device id. static const int32_t DEVICE_ID = 1; constexpr int32_t DEVICE_ID = 1; // An arbitrary injector pid / uid pair that has permission to inject events. static const int32_t INJECTOR_PID = 999; static const int32_t INJECTOR_UID = 1001; // The default pid and uid for windows created by the test. constexpr int32_t WINDOW_PID = 999; constexpr int32_t WINDOW_UID = 1001; static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s; static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms; Loading Loading @@ -106,8 +106,6 @@ private: void pokeUserActivity(nsecs_t, int32_t, int32_t) override {} bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override { return false; } void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {} void setPointerCapture(const PointerCaptureRequest&) override {} Loading Loading @@ -194,8 +192,8 @@ public: mInfo.globalScaleFactor = 1.0; mInfo.touchableRegion.clear(); mInfo.addTouchableRegion(mFrame); mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.ownerPid = WINDOW_PID; mInfo.ownerUid = WINDOW_UID; mInfo.displayId = ADISPLAY_ID_DEFAULT; } Loading Loading @@ -308,14 +306,14 @@ static void benchmarkInjectMotion(benchmark::State& state) { for (auto _ : state) { MotionEvent event = generateMotionEvent(); // Send ACTION_DOWN dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); // Send ACTION_UP event.setAction(AMOTION_EVENT_ACTION_UP); dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); window->consumeEvent(); Loading
services/inputflinger/dispatcher/InjectionState.cpp +2 −3 Original line number Diff line number Diff line Loading @@ -20,10 +20,9 @@ namespace android::inputdispatcher { InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) InjectionState::InjectionState(const std::optional<int32_t>& targetUid) : refCount(1), injectorPid(injectorPid), injectorUid(injectorUid), targetUid(targetUid), injectionResult(android::os::InputEventInjectionResult::PENDING), injectionIsAsync(false), pendingForegroundDispatches(0) {} Loading
services/inputflinger/dispatcher/InjectionState.h +2 −3 Original line number Diff line number Diff line Loading @@ -27,13 +27,12 @@ namespace inputdispatcher { struct InjectionState { mutable int32_t refCount; int32_t injectorPid; int32_t injectorUid; std::optional<int32_t> targetUid; android::os::InputEventInjectionResult injectionResult; // initially PENDING bool injectionIsAsync; // set to true if injection is not waiting for the result int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress InjectionState(int32_t injectorPid, int32_t injectorUid); explicit InjectionState(const std::optional<int32_t>& targetUid); void release(); private: Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +87 −81 Original line number Diff line number Diff line Loading @@ -577,6 +577,27 @@ bool isWindowOwnedBy(const sp<WindowInfoHandle>& windowHandle, int32_t pid, int3 return false; } // Checks targeted injection using the window's owner's uid. // Returns an empty string if an entry can be sent to the given window, or an error message if the // entry is a targeted injection whose uid target doesn't match the window owner. std::optional<std::string> verifyTargetedInjection(const sp<WindowInfoHandle>& window, const EventEntry& entry) { if (entry.injectionState == nullptr || !entry.injectionState->targetUid) { // The event was not injected, or the injected event does not target a window. return {}; } const int32_t uid = *entry.injectionState->targetUid; if (window == nullptr) { return StringPrintf("No valid window target for injection into uid %d.", uid); } if (entry.injectionState->targetUid != window->getInfo()->ownerUid) { return StringPrintf("Injected event targeted at uid %d would be dispatched to window '%s' " "owned by uid %d.", uid, window->getName().c_str(), window->getInfo()->ownerUid); } return {}; } } // namespace // --- InputDispatcher --- Loading Loading @@ -1035,6 +1056,8 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE switch (entry.type) { case EventEntry::Type::KEY: { LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0, "Unexpected untrusted event."); // Optimize app switch latency. // If the application takes too long to catch up then we drop all events preceding // the app switch key. Loading Loading @@ -1072,6 +1095,8 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE } case EventEntry::Type::MOTION: { LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0, "Unexpected untrusted event."); if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(entry))) { mNextUnblockedEvent = mInboundQueue.back(); needWake = true; Loading Loading @@ -1719,8 +1744,7 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< } setInjectionResult(*entry, injectionResult); if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) { ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent)); if (injectionResult == InputEventInjectionResult::TARGET_MISMATCH) { return true; } if (injectionResult != InputEventInjectionResult::SUCCEEDED) { Loading Loading @@ -1977,9 +2001,10 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( // we have a valid, non-null focused window resetNoFocusedWindowTimeoutLocked(); // Check permissions. if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) { return InputEventInjectionResult::PERMISSION_DENIED; // Verify targeted injection. if (const auto err = verifyTargetedInjection(focusedWindowHandle, entry); err) { ALOGW("Dropping injected event: %s", (*err).c_str()); return InputEventInjectionResult::TARGET_MISMATCH; } if (focusedWindowHandle->getInfo()->inputConfig.test( Loading Loading @@ -2045,11 +2070,6 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) { ATRACE_CALL(); enum InjectionPermission { INJECTION_PERMISSION_UNKNOWN, INJECTION_PERMISSION_GRANTED, INJECTION_PERMISSION_DENIED }; // For security reasons, we defer updating the touch state until we are sure that // event injection will be allowed. Loading @@ -2059,7 +2079,6 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // Update the touch state as needed based on the properties of the touch event. InputEventInjectionResult injectionResult = InputEventInjectionResult::PENDING; InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; sp<WindowInfoHandle> newHoverWindowHandle(mLastHoverWindowHandle); sp<WindowInfoHandle> newTouchedWindowHandle; Loading Loading @@ -2108,7 +2127,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( "in display %" PRId32, displayId); // TODO: test multiple simultaneous input streams. injectionResult = InputEventInjectionResult::PERMISSION_DENIED; injectionResult = InputEventInjectionResult::FAILED; switchedDevice = false; wrongDevice = true; goto Failed; Loading Loading @@ -2141,6 +2160,14 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); } // Verify targeted injection. if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) { ALOGW("Dropping injected touch event: %s", (*err).c_str()); injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH; newTouchedWindowHandle = nullptr; goto Failed; } // Figure out whether splitting will be allowed for this window. if (newTouchedWindowHandle != nullptr) { if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { Loading Loading @@ -2184,6 +2211,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) { const WindowInfo& info = *windowHandle->getInfo(); // Skip spy window targets that are not valid for targeted injection. if (const auto err = verifyTargetedInjection(windowHandle, entry); err) { continue; } if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) { ALOGI("Not sending touch event to %s because it is paused", windowHandle->getName().c_str()); Loading Loading @@ -2271,6 +2303,14 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isStylus); // Verify targeted injection. if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) { ALOGW("Dropping injected event: %s", (*err).c_str()); injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH; newTouchedWindowHandle = nullptr; goto Failed; } // Drop touch events if requested by input feature if (newTouchedWindowHandle != nullptr && shouldDropInput(entry, newTouchedWindowHandle)) { Loading Loading @@ -2362,19 +2402,26 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( goto Failed; } // Check permission to inject into all touched foreground windows. if (std::any_of(tempTouchState.windows.begin(), tempTouchState.windows.end(), [this, &entry](const TouchedWindow& touchedWindow) { return (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0 && !checkInjectionPermission(touchedWindow.windowHandle, entry.injectionState); })) { injectionResult = InputEventInjectionResult::PERMISSION_DENIED; injectionPermission = INJECTION_PERMISSION_DENIED; // Ensure that all touched windows are valid for injection. if (entry.injectionState != nullptr) { std::string errs; for (const TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { // Allow ACTION_OUTSIDE events generated by targeted injection to be // dispatched to any uid, since the coords will be zeroed out later. continue; } const auto err = verifyTargetedInjection(touchedWindow.windowHandle, entry); if (err) errs += "\n - " + *err; } if (!errs.empty()) { ALOGW("Dropping targeted injection: At least one touched window is not owned by uid " "%d:%s", *entry.injectionState->targetUid, errs.c_str()); injectionResult = InputEventInjectionResult::TARGET_MISMATCH; goto Failed; } // Permission granted to inject into all touched foreground windows. injectionPermission = INJECTION_PERMISSION_GRANTED; } // Check whether windows listening for outside touches are owned by the same UID. If it is // set the policy flag that we will not reveal coordinate information to this window. Loading Loading @@ -2440,19 +2487,6 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( tempTouchState.filterNonAsIsTouchWindows(); Failed: // Check injection permission once and for all. if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) { if (checkInjectionPermission(nullptr, entry.injectionState)) { injectionPermission = INJECTION_PERMISSION_GRANTED; } else { injectionPermission = INJECTION_PERMISSION_DENIED; } } if (injectionPermission != INJECTION_PERMISSION_GRANTED) { return injectionResult; } // Update final pieces of touch state if the injector had permission. if (!wrongDevice) { if (switchedDevice) { Loading Loading @@ -2650,26 +2684,6 @@ void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& } } bool InputDispatcher::checkInjectionPermission(const sp<WindowInfoHandle>& windowHandle, const InjectionState* injectionState) { if (injectionState && (windowHandle == nullptr || windowHandle->getInfo()->ownerUid != injectionState->injectorUid) && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { if (windowHandle != nullptr) { ALOGW("Permission denied: injecting event from pid %d uid %d to window %s " "owned by uid %d", injectionState->injectorPid, injectionState->injectorUid, windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid); } else { ALOGW("Permission denied: injecting event from pid %d uid %d", injectionState->injectorPid, injectionState->injectorUid); } return false; } return true; } /** * Indicate whether one window handle should be considered as obscuring * another window handle. We only check a few preconditions. Actually Loading Loading @@ -4188,20 +4202,20 @@ void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChan } } InputEventInjectionResult InputDispatcher::injectInputEvent( const InputEvent* event, int32_t injectorPid, int32_t injectorUid, InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) { InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* event, std::optional<int32_t> targetUid, InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) { if (DEBUG_INBOUND_EVENT_DETAILS) { ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " "syncMode=%d, timeout=%lld, policyFlags=0x%08x", event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags); ALOGD("injectInputEvent - eventType=%d, targetUid=%s, syncMode=%d, timeout=%lld, " "policyFlags=0x%08x", event->getType(), targetUid ? std::to_string(*targetUid).c_str() : "none", syncMode, timeout.count(), policyFlags); } nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count(); policyFlags |= POLICY_FLAG_INJECTED; if (hasInjectionPermission(injectorPid, injectorUid)) { policyFlags |= POLICY_FLAG_TRUSTED; } policyFlags |= POLICY_FLAG_INJECTED | POLICY_FLAG_TRUSTED; // For all injected events, set device id = VIRTUAL_KEYBOARD_ID. The only exception is events // that have gone through the InputFilter. If the event passed through the InputFilter, assign Loading Loading @@ -4342,7 +4356,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( return InputEventInjectionResult::FAILED; } InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); InjectionState* injectionState = new InjectionState(targetUid); if (syncMode == InputEventInjectionSync::NONE) { injectionState->injectionIsAsync = true; } Loading Loading @@ -4414,8 +4428,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( } // release lock if (DEBUG_INJECTION) { ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d", injectionResult, injectorPid, injectorUid); ALOGD("injectInputEvent - Finished with result %d.", injectionResult); } return injectionResult; Loading Loading @@ -4454,19 +4467,12 @@ std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const Inpu return result; } bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { return injectorUid == 0 || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); } void InputDispatcher::setInjectionResult(EventEntry& entry, InputEventInjectionResult injectionResult) { InjectionState* injectionState = entry.injectionState; if (injectionState) { if (DEBUG_INJECTION) { ALOGD("Setting input event injection result to %d. " "injectorPid=%d, injectorUid=%d", injectionResult, injectionState->injectorPid, injectionState->injectorUid); ALOGD("Setting input event injection result to %d.", injectionResult); } if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) { Loading @@ -4475,12 +4481,12 @@ void InputDispatcher::setInjectionResult(EventEntry& entry, case InputEventInjectionResult::SUCCEEDED: ALOGV("Asynchronous input event injection succeeded."); break; case InputEventInjectionResult::TARGET_MISMATCH: ALOGV("Asynchronous input event injection target mismatch."); break; case InputEventInjectionResult::FAILED: ALOGW("Asynchronous input event injection failed."); break; case InputEventInjectionResult::PERMISSION_DENIED: ALOGW("Asynchronous input event injection permission denied."); break; case InputEventInjectionResult::TIMED_OUT: ALOGW("Asynchronous input event injection timed out."); break; Loading