Loading libs/input/android/os/InputEventInjectionResult.aidl +3 −2 Original line number Diff line number Diff line Loading @@ -29,8 +29,9 @@ enum InputEventInjectionResult { /* Injection succeeded. */ SUCCEEDED = 0, /* Injection failed because the injected event did not target the appropriate window. */ TARGET_MISMATCH = 1, /* Injection failed because the injector did not have permission to inject * into the application with input focus. */ PERMISSION_DENIED = 1, /* Injection failed because there were no available input targets. */ FAILED = 2, Loading services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +12 −10 Original line number Diff line number Diff line Loading @@ -31,11 +31,11 @@ using android::os::InputEventInjectionSync; namespace android::inputdispatcher { // An arbitrary device id. constexpr int32_t DEVICE_ID = 1; static const int32_t DEVICE_ID = 1; // The default pid and uid for windows created by the test. constexpr int32_t WINDOW_PID = 999; constexpr int32_t WINDOW_UID = 1001; // 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; static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s; static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms; Loading Loading @@ -108,6 +108,8 @@ 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 +196,8 @@ public: mInfo.globalScaleFactor = 1.0; mInfo.touchableRegion.clear(); mInfo.addTouchableRegion(mFrame); mInfo.ownerPid = WINDOW_PID; mInfo.ownerUid = WINDOW_UID; mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = ADISPLAY_ID_DEFAULT; } Loading Loading @@ -308,14 +310,14 @@ static void benchmarkInjectMotion(benchmark::State& state) { for (auto _ : state) { MotionEvent event = generateMotionEvent(); // Send ACTION_DOWN dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, 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, {} /*targetUid*/, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); window->consumeEvent(); Loading services/inputflinger/dispatcher/InjectionState.cpp +3 −2 Original line number Diff line number Diff line Loading @@ -20,9 +20,10 @@ namespace android::inputdispatcher { InjectionState::InjectionState(const std::optional<int32_t>& targetUid) InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) : refCount(1), targetUid(targetUid), injectorPid(injectorPid), injectorUid(injectorUid), injectionResult(android::os::InputEventInjectionResult::PENDING), injectionIsAsync(false), pendingForegroundDispatches(0) {} Loading services/inputflinger/dispatcher/InjectionState.h +3 −2 Original line number Diff line number Diff line Loading @@ -27,12 +27,13 @@ namespace inputdispatcher { struct InjectionState { mutable int32_t refCount; std::optional<int32_t> targetUid; int32_t injectorPid; int32_t injectorUid; 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 explicit InjectionState(const std::optional<int32_t>& targetUid); InjectionState(int32_t injectorPid, int32_t injectorUid); void release(); private: Loading services/inputflinger/dispatcher/InputDispatcher.cpp +81 −87 Original line number Diff line number Diff line Loading @@ -578,27 +578,6 @@ 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 @@ -1057,8 +1036,6 @@ 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 @@ -1096,8 +1073,6 @@ 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 @@ -1743,7 +1718,8 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< } setInjectionResult(*entry, injectionResult); if (injectionResult == InputEventInjectionResult::TARGET_MISMATCH) { if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) { ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent)); return true; } if (injectionResult != InputEventInjectionResult::SUCCEEDED) { Loading Loading @@ -2000,10 +1976,9 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( // we have a valid, non-null focused window resetNoFocusedWindowTimeoutLocked(); // Verify targeted injection. if (const auto err = verifyTargetedInjection(focusedWindowHandle, entry); err) { ALOGW("Dropping injected event: %s", (*err).c_str()); return InputEventInjectionResult::TARGET_MISMATCH; // Check permissions. if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) { return InputEventInjectionResult::PERMISSION_DENIED; } if (focusedWindowHandle->getInfo()->inputConfig.test( Loading Loading @@ -2069,6 +2044,11 @@ 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 @@ -2078,6 +2058,7 @@ 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 @@ -2126,7 +2107,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( "in display %" PRId32, displayId); // TODO: test multiple simultaneous input streams. injectionResult = InputEventInjectionResult::FAILED; injectionResult = InputEventInjectionResult::PERMISSION_DENIED; switchedDevice = false; wrongDevice = true; goto Failed; Loading Loading @@ -2159,14 +2140,6 @@ 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 @@ -2210,11 +2183,6 @@ 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 @@ -2308,14 +2276,6 @@ 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 @@ -2407,26 +2367,19 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( goto Failed; } // 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; // 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; 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 @@ -2492,6 +2445,19 @@ 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 @@ -2689,6 +2655,26 @@ 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 @@ -4207,20 +4193,20 @@ void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChan } } InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* event, std::optional<int32_t> targetUid, InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) { InputEventInjectionResult InputDispatcher::injectInputEvent( const InputEvent* event, int32_t injectorPid, int32_t injectorUid, InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) { if (DEBUG_INBOUND_EVENT_DETAILS) { 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); ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " "syncMode=%d, timeout=%lld, policyFlags=0x%08x", event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags); } nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count(); policyFlags |= POLICY_FLAG_INJECTED | POLICY_FLAG_TRUSTED; policyFlags |= POLICY_FLAG_INJECTED; if (hasInjectionPermission(injectorPid, injectorUid)) { policyFlags |= 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 @@ -4361,7 +4347,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev return InputEventInjectionResult::FAILED; } InjectionState* injectionState = new InjectionState(targetUid); InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); if (syncMode == InputEventInjectionSync::NONE) { injectionState->injectionIsAsync = true; } Loading Loading @@ -4433,7 +4419,8 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev } // release lock if (DEBUG_INJECTION) { ALOGD("injectInputEvent - Finished with result %d.", injectionResult); ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d", injectionResult, injectorPid, injectorUid); } return injectionResult; Loading Loading @@ -4472,12 +4459,19 @@ 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.", injectionResult); ALOGD("Setting input event injection result to %d. " "injectorPid=%d, injectorUid=%d", injectionResult, injectionState->injectorPid, injectionState->injectorUid); } if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) { Loading @@ -4486,12 +4480,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 +3 −2 Original line number Diff line number Diff line Loading @@ -29,8 +29,9 @@ enum InputEventInjectionResult { /* Injection succeeded. */ SUCCEEDED = 0, /* Injection failed because the injected event did not target the appropriate window. */ TARGET_MISMATCH = 1, /* Injection failed because the injector did not have permission to inject * into the application with input focus. */ PERMISSION_DENIED = 1, /* Injection failed because there were no available input targets. */ FAILED = 2, Loading
services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +12 −10 Original line number Diff line number Diff line Loading @@ -31,11 +31,11 @@ using android::os::InputEventInjectionSync; namespace android::inputdispatcher { // An arbitrary device id. constexpr int32_t DEVICE_ID = 1; static const int32_t DEVICE_ID = 1; // The default pid and uid for windows created by the test. constexpr int32_t WINDOW_PID = 999; constexpr int32_t WINDOW_UID = 1001; // 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; static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s; static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms; Loading Loading @@ -108,6 +108,8 @@ 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 +196,8 @@ public: mInfo.globalScaleFactor = 1.0; mInfo.touchableRegion.clear(); mInfo.addTouchableRegion(mFrame); mInfo.ownerPid = WINDOW_PID; mInfo.ownerUid = WINDOW_UID; mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = ADISPLAY_ID_DEFAULT; } Loading Loading @@ -308,14 +310,14 @@ static void benchmarkInjectMotion(benchmark::State& state) { for (auto _ : state) { MotionEvent event = generateMotionEvent(); // Send ACTION_DOWN dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, 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, {} /*targetUid*/, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); window->consumeEvent(); Loading
services/inputflinger/dispatcher/InjectionState.cpp +3 −2 Original line number Diff line number Diff line Loading @@ -20,9 +20,10 @@ namespace android::inputdispatcher { InjectionState::InjectionState(const std::optional<int32_t>& targetUid) InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) : refCount(1), targetUid(targetUid), injectorPid(injectorPid), injectorUid(injectorUid), injectionResult(android::os::InputEventInjectionResult::PENDING), injectionIsAsync(false), pendingForegroundDispatches(0) {} Loading
services/inputflinger/dispatcher/InjectionState.h +3 −2 Original line number Diff line number Diff line Loading @@ -27,12 +27,13 @@ namespace inputdispatcher { struct InjectionState { mutable int32_t refCount; std::optional<int32_t> targetUid; int32_t injectorPid; int32_t injectorUid; 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 explicit InjectionState(const std::optional<int32_t>& targetUid); InjectionState(int32_t injectorPid, int32_t injectorUid); void release(); private: Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +81 −87 Original line number Diff line number Diff line Loading @@ -578,27 +578,6 @@ 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 @@ -1057,8 +1036,6 @@ 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 @@ -1096,8 +1073,6 @@ 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 @@ -1743,7 +1718,8 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< } setInjectionResult(*entry, injectionResult); if (injectionResult == InputEventInjectionResult::TARGET_MISMATCH) { if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) { ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent)); return true; } if (injectionResult != InputEventInjectionResult::SUCCEEDED) { Loading Loading @@ -2000,10 +1976,9 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( // we have a valid, non-null focused window resetNoFocusedWindowTimeoutLocked(); // Verify targeted injection. if (const auto err = verifyTargetedInjection(focusedWindowHandle, entry); err) { ALOGW("Dropping injected event: %s", (*err).c_str()); return InputEventInjectionResult::TARGET_MISMATCH; // Check permissions. if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) { return InputEventInjectionResult::PERMISSION_DENIED; } if (focusedWindowHandle->getInfo()->inputConfig.test( Loading Loading @@ -2069,6 +2044,11 @@ 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 @@ -2078,6 +2058,7 @@ 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 @@ -2126,7 +2107,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( "in display %" PRId32, displayId); // TODO: test multiple simultaneous input streams. injectionResult = InputEventInjectionResult::FAILED; injectionResult = InputEventInjectionResult::PERMISSION_DENIED; switchedDevice = false; wrongDevice = true; goto Failed; Loading Loading @@ -2159,14 +2140,6 @@ 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 @@ -2210,11 +2183,6 @@ 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 @@ -2308,14 +2276,6 @@ 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 @@ -2407,26 +2367,19 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( goto Failed; } // 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; // 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; 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 @@ -2492,6 +2445,19 @@ 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 @@ -2689,6 +2655,26 @@ 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 @@ -4207,20 +4193,20 @@ void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChan } } InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* event, std::optional<int32_t> targetUid, InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) { InputEventInjectionResult InputDispatcher::injectInputEvent( const InputEvent* event, int32_t injectorPid, int32_t injectorUid, InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) { if (DEBUG_INBOUND_EVENT_DETAILS) { 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); ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " "syncMode=%d, timeout=%lld, policyFlags=0x%08x", event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags); } nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count(); policyFlags |= POLICY_FLAG_INJECTED | POLICY_FLAG_TRUSTED; policyFlags |= POLICY_FLAG_INJECTED; if (hasInjectionPermission(injectorPid, injectorUid)) { policyFlags |= 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 @@ -4361,7 +4347,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev return InputEventInjectionResult::FAILED; } InjectionState* injectionState = new InjectionState(targetUid); InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); if (syncMode == InputEventInjectionSync::NONE) { injectionState->injectionIsAsync = true; } Loading Loading @@ -4433,7 +4419,8 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev } // release lock if (DEBUG_INJECTION) { ALOGD("injectInputEvent - Finished with result %d.", injectionResult); ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d", injectionResult, injectorPid, injectorUid); } return injectionResult; Loading Loading @@ -4472,12 +4459,19 @@ 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.", injectionResult); ALOGD("Setting input event injection result to %d. " "injectorPid=%d, injectorUid=%d", injectionResult, injectionState->injectorPid, injectionState->injectorUid); } if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) { Loading @@ -4486,12 +4480,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