Merge "Reland: Change input injection security model" into tm-dev
diff --git a/libs/input/android/os/InputEventInjectionResult.aidl b/libs/input/android/os/InputEventInjectionResult.aidl
index 34f10ec..3bc7068 100644
--- a/libs/input/android/os/InputEventInjectionResult.aidl
+++ b/libs/input/android/os/InputEventInjectionResult.aidl
@@ -29,9 +29,8 @@
     /* 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,
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 32eec29..a2e60c4 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -31,11 +31,11 @@
 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;
@@ -108,8 +108,6 @@
 
     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 {}
@@ -196,8 +194,8 @@
         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;
     }
 
@@ -310,14 +308,14 @@
     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();
diff --git a/services/inputflinger/dispatcher/InjectionState.cpp b/services/inputflinger/dispatcher/InjectionState.cpp
index c8024a6..c2d3ad6 100644
--- a/services/inputflinger/dispatcher/InjectionState.cpp
+++ b/services/inputflinger/dispatcher/InjectionState.cpp
@@ -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) {}
diff --git a/services/inputflinger/dispatcher/InjectionState.h b/services/inputflinger/dispatcher/InjectionState.h
index 0bfafb1..90cf150 100644
--- a/services/inputflinger/dispatcher/InjectionState.h
+++ b/services/inputflinger/dispatcher/InjectionState.h
@@ -27,13 +27,12 @@
 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:
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 7852b30..b5a3825 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -578,6 +578,27 @@
     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 ---
@@ -1036,6 +1057,8 @@
 
     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.
@@ -1073,6 +1096,8 @@
         }
 
         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;
@@ -1720,8 +1745,7 @@
     }
 
     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) {
@@ -1972,9 +1996,10 @@
     // 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(
@@ -2040,11 +2065,6 @@
         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.
@@ -2054,7 +2074,6 @@
 
     // 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;
 
@@ -2103,7 +2122,7 @@
               "in display %" PRId32,
               displayId);
         // TODO: test multiple simultaneous input streams.
-        injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
+        injectionResult = InputEventInjectionResult::FAILED;
         switchedDevice = false;
         wrongDevice = true;
         goto Failed;
@@ -2136,6 +2155,14 @@
             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()) {
@@ -2179,6 +2206,11 @@
         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());
@@ -2272,6 +2304,14 @@
             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)) {
@@ -2363,19 +2403,26 @@
         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;
-        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;
+            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.
@@ -2441,19 +2488,6 @@
     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) {
@@ -2685,26 +2719,6 @@
     }
 }
 
-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
@@ -4223,20 +4237,20 @@
     }
 }
 
-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
@@ -4377,7 +4391,7 @@
             return InputEventInjectionResult::FAILED;
     }
 
-    InjectionState* injectionState = new InjectionState(injectorPid, injectorUid);
+    InjectionState* injectionState = new InjectionState(targetUid);
     if (syncMode == InputEventInjectionSync::NONE) {
         injectionState->injectionIsAsync = true;
     }
@@ -4449,8 +4463,7 @@
     } // 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;
@@ -4489,19 +4502,12 @@
     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)) {
@@ -4510,12 +4516,12 @@
                 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;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 34aed3b..ed89ed0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -104,7 +104,7 @@
     void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
     android::os::InputEventInjectionResult injectInputEvent(
-            const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
+            const InputEvent* event, std::optional<int32_t> targetUid,
             android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
             uint32_t policyFlags) override;
 
@@ -279,7 +279,6 @@
 
     // Event injection and synchronization.
     std::condition_variable mInjectionResultAvailable;
-    bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
     void setInjectionResult(EventEntry& entry,
                             android::os::InputEventInjectionResult injectionResult);
     void transformMotionEntryForInjectionLocked(MotionEntry&,
@@ -555,8 +554,6 @@
     void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId)
             REQUIRES(mLock);
     void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock);
-    bool checkInjectionPermission(const sp<android::gui::WindowInfoHandle>& windowHandle,
-                                  const InjectionState* injectionState);
     // Enqueue a drag event if needed, and update the touch state.
     // Uses findTouchedWindowTargetsLocked to make the decision
     void addDragEventLocked(const MotionEntry& entry) REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index d7bc5fb..67fed8b 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -68,10 +68,16 @@
      * input injection to proceed.
      * Returns one of the INPUT_EVENT_INJECTION_XXX constants.
      *
-     * This method may be called on any thread (usually by the input manager).
+     * If a targetUid is provided, InputDispatcher will only consider injecting the input event into
+     * windows owned by the provided uid. If the input event is targeted at a window that is not
+     * owned by the provided uid, input injection will fail. If no targetUid is provided, the input
+     * event will be dispatched as-is.
+     *
+     * This method may be called on any thread (usually by the input manager). The caller must
+     * perform all necessary permission checks prior to injecting events.
      */
     virtual android::os::InputEventInjectionResult injectInputEvent(
-            const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
+            const InputEvent* event, std::optional<int32_t> targetUid,
             android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
             uint32_t policyFlags) = 0;
 
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index de0b6da..575b3d7 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -125,15 +125,6 @@
     /* Poke user activity for an event dispatched to a window. */
     virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) = 0;
 
-    /* Checks whether a given application pid/uid has permission to inject input events
-     * into other applications.
-     *
-     * This method is special in that its implementation promises to be non-reentrant and
-     * is safe to call while holding other locks.  (Most other methods make no such guarantees!)
-     */
-    virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,
-                                                         int32_t injectorUid) = 0;
-
     /* Notifies the policy that a pointer down event has occurred outside the current focused
      * window.
      *
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 61e5fe3..91a666c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -45,10 +45,10 @@
 using namespace ftl::flag_operators;
 
 // An arbitrary time value.
-static const nsecs_t ARBITRARY_TIME = 1234;
+static constexpr nsecs_t ARBITRARY_TIME = 1234;
 
 // An arbitrary device id.
-static const int32_t DEVICE_ID = 1;
+static constexpr int32_t DEVICE_ID = 1;
 
 // An arbitrary display id.
 static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
@@ -61,9 +61,12 @@
 static constexpr int32_t POINTER_1_UP =
         AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
 
-// 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.
+static constexpr int32_t WINDOW_PID = 999;
+static constexpr int32_t WINDOW_UID = 1001;
+
+// The default policy flags to use for event injection by tests.
+static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
 
 // An arbitrary pid of the gesture monitor window
 static constexpr int32_t MONITOR_PID = 2001;
@@ -472,10 +475,6 @@
 
     void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
 
-    bool checkInjectEventsPermissionNonReentrant(int32_t pid, int32_t uid) override {
-        return pid == INJECTOR_PID && uid == INJECTOR_UID;
-    }
-
     void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {
         std::scoped_lock lock(mLock);
         mOnPointerDownToken = newToken;
@@ -560,8 +559,8 @@
                      /*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
                      ARBITRARY_TIME);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject key events with undefined action.";
 
     // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
@@ -569,8 +568,8 @@
                      INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
                      ARBITRARY_TIME, ARBITRARY_TIME);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject key events with ACTION_MULTIPLE.";
 }
 
@@ -599,8 +598,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with undefined action.";
 
     // Rejects pointer down with invalid index.
@@ -611,8 +610,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with pointer down index too large.";
 
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -623,8 +622,8 @@
                      identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with pointer down index too small.";
 
     // Rejects pointer up with invalid index.
@@ -635,8 +634,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with pointer up index too large.";
 
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -647,8 +646,8 @@
                      identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with pointer up index too small.";
 
     // Rejects motion events with invalid number of pointers.
@@ -659,8 +658,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 0, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with 0 pointers.";
 
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -670,8 +669,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with more than MAX_POINTERS pointers.";
 
     // Rejects motion events with invalid pointer ids.
@@ -683,8 +682,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with pointer ids less than 0.";
 
     pointerProperties[0].id = MAX_POINTER_ID + 1;
@@ -695,8 +694,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
 
     // Rejects motion events with duplicate pointer ids.
@@ -709,8 +708,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 2, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with duplicate pointer ids.";
 }
 
@@ -1013,8 +1012,8 @@
         mInfo.globalScaleFactor = 1.0;
         mInfo.touchableRegion.clear();
         mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
-        mInfo.ownerPid = INJECTOR_PID;
-        mInfo.ownerUid = INJECTOR_UID;
+        mInfo.ownerPid = WINDOW_PID;
+        mInfo.ownerUid = WINDOW_UID;
         mInfo.displayId = displayId;
         mInfo.inputConfig = WindowInfo::InputConfig::DEFAULT;
     }
@@ -1296,7 +1295,8 @@
         int32_t displayId = ADISPLAY_ID_NONE,
         InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
         std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
-        bool allowKeyRepeat = true) {
+        bool allowKeyRepeat = true, std::optional<int32_t> targetUid = {},
+        uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
     KeyEvent event;
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
@@ -1305,13 +1305,11 @@
                      INVALID_HMAC, action, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE,
                      repeatCount, currentTime, currentTime);
 
-    int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
     if (!allowKeyRepeat) {
         policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
     }
     // Inject event until dispatch out.
-    return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, syncMode,
-                                        injectionTimeout, policyFlags);
+    return dispatcher->injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
 }
 
 static InputEventInjectionResult injectKeyDown(const std::unique_ptr<InputDispatcher>& dispatcher,
@@ -1454,10 +1452,10 @@
 static InputEventInjectionResult injectMotionEvent(
         const std::unique_ptr<InputDispatcher>& dispatcher, const MotionEvent& event,
         std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
-        InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT) {
-    return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, injectionMode,
-                                        injectionTimeout,
-                                        POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+        InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
+        std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
+    return dispatcher->injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
+                                        policyFlags);
 }
 
 static InputEventInjectionResult injectMotionEvent(
@@ -1467,7 +1465,8 @@
                                         AMOTION_EVENT_INVALID_CURSOR_POSITION},
         std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
         InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
-        nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC)) {
+        nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
+        std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
     MotionEvent event = MotionEventBuilder(action, source)
                                 .displayId(displayId)
                                 .eventTime(eventTime)
@@ -1479,7 +1478,8 @@
                                 .build();
 
     // Inject event until dispatch out.
-    return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode);
+    return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode, targetUid,
+                             policyFlags);
 }
 
 static InputEventInjectionResult injectMotionDown(
@@ -3574,8 +3574,8 @@
  * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
  */
 TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
-    constexpr int32_t SLIPPERY_PID = INJECTOR_PID + 1;
-    constexpr int32_t SLIPPERY_UID = INJECTOR_UID + 1;
+    constexpr int32_t SLIPPERY_PID = WINDOW_PID + 1;
+    constexpr int32_t SLIPPERY_UID = WINDOW_UID + 1;
 
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -4102,7 +4102,7 @@
         const int32_t additionalPolicyFlags =
                 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
         ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-                  mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+                  mDispatcher->injectInputEvent(&event, {} /*targetUid*/,
                                                 InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
                                                 policyFlags | additionalPolicyFlags));
 
@@ -4137,7 +4137,7 @@
 
         const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
         ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-                  mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+                  mDispatcher->injectInputEvent(&event, {} /*targetUid*/,
                                                 InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
                                                 policyFlags | additionalPolicyFlags));
 
@@ -4644,7 +4644,7 @@
     const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
 
     InputEventInjectionResult result =
-            mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+            mDispatcher->injectInputEvent(&event, {} /* targetUid */,
                                           InputEventInjectionSync::WAIT_FOR_RESULT,
                                           INJECT_EVENT_TIMEOUT, policyFlags);
     ASSERT_EQ(InputEventInjectionResult::FAILED, result)
@@ -6558,8 +6558,8 @@
         mWindow->consumeFocusEvent(true);
 
         // Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
-        if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
-                                        INJECTOR_UID, /* hasPermission */ true)) {
+        if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
+                                        WINDOW_UID, /* hasPermission */ true)) {
             mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
             mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
         }
@@ -7190,4 +7190,149 @@
     window->assertNoEvents();
 }
 
+struct User {
+    int32_t mPid;
+    int32_t mUid;
+    uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
+    std::unique_ptr<InputDispatcher>& mDispatcher;
+
+    User(std::unique_ptr<InputDispatcher>& dispatcher, int32_t pid, int32_t uid)
+          : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
+
+    InputEventInjectionResult injectTargetedMotion(int32_t action) const {
+        return injectMotionEvent(mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
+                                 ADISPLAY_ID_DEFAULT, {100, 200},
+                                 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                  AMOTION_EVENT_INVALID_CURSOR_POSITION},
+                                 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
+                                 systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
+    }
+
+    InputEventInjectionResult injectTargetedKey(int32_t action) const {
+        return inputdispatcher::injectKey(mDispatcher, action, 0 /* repeatCount*/, ADISPLAY_ID_NONE,
+                                          InputEventInjectionSync::WAIT_FOR_RESULT,
+                                          INJECT_EVENT_TIMEOUT, false /*allowKeyRepeat*/, {mUid},
+                                          mPolicyFlags);
+    }
+
+    sp<FakeWindowHandle> createWindow() const {
+        std::shared_ptr<FakeApplicationHandle> overlayApplication =
+                std::make_shared<FakeApplicationHandle>();
+        sp<FakeWindowHandle> window = new FakeWindowHandle(overlayApplication, mDispatcher,
+                                                           "Owned Window", ADISPLAY_ID_DEFAULT);
+        window->setOwnerInfo(mPid, mUid);
+        return window;
+    }
+};
+
+using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
+    auto owner = User(mDispatcher, 10, 11);
+    auto window = owner.createWindow();
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+              owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+    window->consumeMotionDown();
+
+    setFocusedWindow(window);
+    window->consumeFocusEvent(true);
+
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+              owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
+    window->consumeKeyDown(ADISPLAY_ID_NONE);
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
+    auto owner = User(mDispatcher, 10, 11);
+    auto window = owner.createWindow();
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+    auto rando = User(mDispatcher, 20, 21);
+    EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
+              rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+
+    setFocusedWindow(window);
+    window->consumeFocusEvent(true);
+
+    EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
+              rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
+    window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
+    auto owner = User(mDispatcher, 10, 11);
+    auto window = owner.createWindow();
+    auto spy = owner.createWindow();
+    spy->setSpy(true);
+    spy->setTrustedOverlay(true);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+              owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+    spy->consumeMotionDown();
+    window->consumeMotionDown();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
+    auto owner = User(mDispatcher, 10, 11);
+    auto window = owner.createWindow();
+
+    auto rando = User(mDispatcher, 20, 21);
+    auto randosSpy = rando.createWindow();
+    randosSpy->setSpy(true);
+    randosSpy->setTrustedOverlay(true);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}});
+
+    // The event is targeted at owner's window, so injection should succeed, but the spy should
+    // not receive the event.
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+              owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+    randosSpy->assertNoEvents();
+    window->consumeMotionDown();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
+    auto owner = User(mDispatcher, 10, 11);
+    auto window = owner.createWindow();
+
+    auto rando = User(mDispatcher, 20, 21);
+    auto randosSpy = rando.createWindow();
+    randosSpy->setSpy(true);
+    randosSpy->setTrustedOverlay(true);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}});
+
+    // A user that has injection permission can inject into any window.
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                                ADISPLAY_ID_DEFAULT));
+    randosSpy->consumeMotionDown();
+    window->consumeMotionDown();
+
+    setFocusedWindow(randosSpy);
+    randosSpy->consumeFocusEvent(true);
+
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher));
+    randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
+    window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanGenerateActionOutsideToOtherUids) {
+    auto owner = User(mDispatcher, 10, 11);
+    auto window = owner.createWindow();
+
+    auto rando = User(mDispatcher, 20, 21);
+    auto randosWindow = rando.createWindow();
+    randosWindow->setFrame(Rect{-10, -10, -5, -5});
+    randosWindow->setWatchOutsideTouch(true);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosWindow, window}}});
+
+    // We allow generation of ACTION_OUTSIDE events into windows owned by different uids.
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+              owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+    window->consumeMotionDown();
+    randosWindow->consumeMotionOutside();
+}
+
 } // namespace android::inputdispatcher