From 90f0cee685f9b13e6bac7793717a9d15de8eafe8 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Fri, 8 Oct 2010 22:31:17 -0700 Subject: [PATCH] Added more robust tracking and cancelation of events. This change fixes several issues where events would be dropped in the input dispatch pipeline in such a way that the dispatcher could not accurately track the state of the input device. Given more robust tracking, we can now also provide robust cancelation of input events in cases where an application might otherwise become out of sync with the event stream due to ANR, app switch, policy decisions, or forced focus transitions. Pruned some of the input dispatcher log output. Moved the responsibility for calling intercept*BeforeQueueing into the input dispatcher instead of the input reader and added support for early interception of injected events for events coming from trusted sources. This enables behaviors like injection of media keys while the screen is off, haptic feedback of injected virtual keys, so injected events become more "first class" in a way. Change-Id: Iec6ff1dd21e5f3c7feb80ea4feb5382bd090dbd9 --- include/ui/Input.h | 7 + include/ui/InputDispatcher.h | 90 +++-- include/ui/InputReader.h | 47 --- libs/ui/InputDispatcher.cpp | 623 +++++++++++++++++++++-------------- libs/ui/InputReader.cpp | 82 +---- 5 files changed, 464 insertions(+), 385 deletions(-) diff --git a/include/ui/Input.h b/include/ui/Input.h index ee40b85d7..66061fd71 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -71,6 +71,8 @@ namespace android { /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. + * + * These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java. */ enum { /* These flags originate in RawEvents and are generally set in the key map. @@ -102,6 +104,11 @@ enum { // Indicates that the screen was dim when the event was received and the event // should brighten the device. POLICY_FLAG_BRIGHT_HERE = 0x20000000, + + // Indicates that the event should be dispatched to applications. + // The input event should still be sent to the InputDispatcher so that it can see all + // input events received include those that it will not deliver. + POLICY_FLAG_PASS_TO_USER = 0x40000000, }; /* diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h index 47c5326f9..0834e8650 100644 --- a/include/ui/InputDispatcher.h +++ b/include/ui/InputDispatcher.h @@ -282,10 +282,35 @@ public: */ virtual int32_t getMaxEventsPerSecond() = 0; + /* Intercepts a key event immediately before queueing it. + * The policy can use this method as an opportunity to perform power management functions + * and early event preprocessing such as updating policy flags. + * + * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event + * should be dispatched to applications. + */ + virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId, + int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode, + uint32_t& policyFlags) = 0; + + /* Intercepts a generic touch, trackball or other event before queueing it. + * The policy can use this method as an opportunity to perform power management functions + * and early event preprocessing such as updating policy flags. + * + * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event + * should be dispatched to applications. + */ + virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0; + /* Allows the policy a chance to intercept a key before dispatching. */ virtual bool interceptKeyBeforeDispatching(const sp& inputChannel, const KeyEvent* keyEvent, uint32_t policyFlags) = 0; + /* Notifies the policy about switch events. + */ + virtual void notifySwitch(nsecs_t when, + int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0; + /* Poke user activity for an event dispatched to a window. */ virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0; @@ -333,6 +358,8 @@ public: int32_t metaState, int32_t edgeFlags, uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime) = 0; + virtual void notifySwitch(nsecs_t when, + int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0; /* Injects an input event and optionally waits for sync. * The synchronization mode determines whether the method blocks while waiting for @@ -408,6 +435,8 @@ public: int32_t metaState, int32_t edgeFlags, uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime); + virtual void notifySwitch(nsecs_t when, + int32_t switchCode, int32_t switchValue, uint32_t policyFlags) ; virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis); @@ -447,6 +476,7 @@ private: mutable int32_t refCount; int32_t type; nsecs_t eventTime; + uint32_t policyFlags; InjectionState* injectionState; bool dispatchInProgress; // initially false, set to true while dispatching @@ -460,7 +490,6 @@ private: struct KeyEntry : EventEntry { int32_t deviceId; int32_t source; - uint32_t policyFlags; int32_t action; int32_t flags; int32_t keyCode; @@ -489,7 +518,6 @@ private: struct MotionEntry : EventEntry { int32_t deviceId; int32_t source; - uint32_t policyFlags; int32_t action; int32_t flags; int32_t metaState; @@ -664,7 +692,8 @@ private: Pool mDispatchEntryPool; Pool mCommandEntryPool; - void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime); + void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime, + uint32_t policyFlags); void releaseEventEntryInjectionState(EventEntry* entry); }; @@ -685,21 +714,19 @@ private: BROKEN }; + // Specifies the sources to cancel. + enum CancelationOptions { + CANCEL_ALL_EVENTS = 0, + CANCEL_POINTER_EVENTS = 1, + CANCEL_NON_POINTER_EVENTS = 2, + }; + InputState(); ~InputState(); // Returns true if there is no state to be canceled. bool isNeutral() const; - // Returns true if the input state believes it is out of sync. - bool isOutOfSync() const; - - // Sets the input state to be out of sync if it is not neutral. - void setOutOfSync(); - - // Resets the input state out of sync flag. - void resetOutOfSync(); - // Records tracking information for an event that has just been published. // Returns whether the event is consistent with the current input state. Consistency trackEvent(const EventEntry* entry); @@ -712,16 +739,14 @@ private: // Returns whether the event is consistent with the current input state. Consistency trackMotion(const MotionEntry* entry); - // Synthesizes cancelation events for the current state. - void synthesizeCancelationEvents(Allocator* allocator, - Vector& outEvents) const; + // Synthesizes cancelation events for the current state and resets the tracked state. + void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator, + Vector& outEvents, CancelationOptions options); // Clears the current state. void clear(); private: - bool mIsOutOfSync; - struct KeyMemento { int32_t deviceId; int32_t source; @@ -745,6 +770,8 @@ private: Vector mKeyMementos; Vector mMotionMementos; + + static bool shouldCancelEvent(int32_t eventSource, CancelationOptions options); }; /* Manages the dispatch state associated with a single input channel. */ @@ -794,6 +821,13 @@ private: status_t initialize(); }; + enum DropReason { + DROP_REASON_NOT_DROPPED = 0, + DROP_REASON_POLICY = 1, + DROP_REASON_APP_SWITCH = 2, + DROP_REASON_DISABLED = 3, + }; + sp mPolicy; Mutex mLock; @@ -813,12 +847,16 @@ private: // Enqueues an inbound event. Returns true if mLooper->wake() should be called. bool enqueueInboundEventLocked(EventEntry* entry); + // Cleans up input state when dropping an inbound event. + void dropInboundEventLocked(EventEntry* entry, DropReason dropReason); + // App switch latency optimization. + bool mAppSwitchSawKeyDown; nsecs_t mAppSwitchDueTime; - static bool isAppSwitchKey(int32_t keyCode); + static bool isAppSwitchKeyCode(int32_t keyCode); + bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry); bool isAppSwitchPendingLocked(); - bool detectPendingAppSwitchLocked(KeyEntry* inboundKeyEntry); void resetPendingAppSwitchLocked(bool handled); // All registered connections mapped by receive pipe file descriptor. @@ -840,7 +878,7 @@ private: // Event injection and synchronization. Condition mInjectionResultAvailableCondition; - EventEntry* createEntryFromInjectedInputEventLocked(const InputEvent* event); + bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult); Condition mInjectionSyncFinishedCondition; @@ -875,7 +913,7 @@ private: void drainInboundQueueLocked(); void releasePendingEventLocked(); void releaseInboundEventLocked(EventEntry* entry); - bool isEventFromReliableSourceLocked(EventEntry* entry); + bool isEventFromTrustedSourceLocked(EventEntry* entry); // Dispatch state. bool mDispatchEnabled; @@ -984,11 +1022,17 @@ private: void startDispatchCycleLocked(nsecs_t currentTime, const sp& connection); void finishDispatchCycleLocked(nsecs_t currentTime, const sp& connection); void startNextDispatchCycleLocked(nsecs_t currentTime, const sp& connection); - void abortDispatchCycleLocked(nsecs_t currentTime, const sp& connection, - bool broken); + void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp& connection); void drainOutboundQueueLocked(Connection* connection); static int handleReceiveCallback(int receiveFd, int events, void* data); + void synthesizeCancelationEventsForAllConnectionsLocked( + InputState::CancelationOptions options, const char* reason); + void synthesizeCancelationEventsForInputChannelLocked(const sp& channel, + InputState::CancelationOptions options, const char* reason); + void synthesizeCancelationEventsForConnectionLocked(const sp& connection, + InputState::CancelationOptions options, const char* reason); + // Splitting motion events across windows. MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds); diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h index 3619189e1..c15e3825e 100644 --- a/include/ui/InputReader.h +++ b/include/ui/InputReader.h @@ -87,49 +87,12 @@ public: ROTATION_270 = 3 }; - /* Actions returned by interceptXXX methods. */ - enum { - // The input dispatcher should do nothing and discard the input unless other - // flags are set. - ACTION_NONE = 0, - - // The input dispatcher should dispatch the input to the application. - ACTION_DISPATCH = 0x00000001, - }; - /* Gets information about the display with the specified id. * Returns true if the display info is available, false otherwise. */ virtual bool getDisplayInfo(int32_t displayId, int32_t* width, int32_t* height, int32_t* orientation) = 0; - /* Intercepts a key event. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * Returns a policy action constant such as ACTION_DISPATCH. - */ - virtual int32_t interceptKey(nsecs_t when, int32_t deviceId, - bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) = 0; - - /* Intercepts a switch event. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * Switches are not dispatched to applications so this method should - * usually return ACTION_NONE. - */ - virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, - uint32_t& policyFlags) = 0; - - /* Intercepts a generic touch, trackball or other event. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * Returns a policy action constant such as ACTION_DISPATCH. - */ - virtual int32_t interceptGeneric(nsecs_t when, uint32_t& policyFlags) = 0; - /* Determines whether to turn on some hacks we have to improve the touch interaction with a * certain device whose screen currently is not all that good. */ @@ -403,8 +366,6 @@ public: protected: InputDevice* mDevice; InputReaderContext* mContext; - - bool applyStandardPolicyActions(nsecs_t when, int32_t policyActions); }; @@ -466,8 +427,6 @@ private: void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags); - void applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags, - bool down, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime); ssize_t findKeyDownLocked(int32_t scanCode); }; @@ -525,8 +484,6 @@ private: void initializeLocked(); void sync(nsecs_t when); - void applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction, - PointerCoords* pointerCoords, nsecs_t downTime); }; @@ -829,10 +786,6 @@ private: BitSet32 idBits, uint32_t changedId, uint32_t pointerCount, int32_t motionEventAction); - void applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags, - int32_t keyCode, int32_t scanCode, nsecs_t downTime); - bool isPointInsideSurfaceLocked(int32_t x, int32_t y); const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y); diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index fe8555d20..58c2cdfda 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -95,16 +95,19 @@ static bool validateKeyEvent(int32_t action) { return true; } -static bool isValidMotionAction(int32_t action) { +static bool isValidMotionAction(int32_t action, size_t pointerCount) { switch (action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_POINTER_UP: case AMOTION_EVENT_ACTION_OUTSIDE: return true; + case AMOTION_EVENT_ACTION_POINTER_DOWN: + case AMOTION_EVENT_ACTION_POINTER_UP: { + int32_t index = getMotionEventActionPointerIndex(action); + return index >= 0 && size_t(index) < pointerCount; + } default: return false; } @@ -112,7 +115,7 @@ static bool isValidMotionAction(int32_t action) { static bool validateMotionEvent(int32_t action, size_t pointerCount, const int32_t* pointerIds) { - if (! isValidMotionAction(action)) { + if (! isValidMotionAction(action, pointerCount)) { LOGE("Motion event has invalid action code 0x%x", action); return false; } @@ -235,16 +238,6 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, resetKeyRepeatLocked(); } - // If dispatching is disabled, drop all events in the queue. - if (! mDispatchEnabled) { - if (mPendingEvent || ! mInboundQueue.isEmpty()) { - LOGI("Dropping pending events because input dispatch is disabled."); - releasePendingEventLocked(); - drainInboundQueueLocked(); - } - return; - } - // If dispatching is frozen, do not process timeouts or try to deliver any new events. if (mDispatchFrozen) { #if DEBUG_FOCUS @@ -294,7 +287,11 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, // samples may be appended to this event by the time the throttling timeout // expires. // TODO Make this smarter and consider throttling per device independently. - if (entry->type == EventEntry::TYPE_MOTION) { + if (entry->type == EventEntry::TYPE_MOTION + && !isAppSwitchDue + && mDispatchEnabled + && (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) + && !entry->isInjected()) { MotionEntry* motionEntry = static_cast(entry); int32_t deviceId = motionEntry->deviceId; uint32_t source = motionEntry->source; @@ -347,39 +344,43 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, // Now we have an event to dispatch. assert(mPendingEvent != NULL); bool done = false; + DropReason dropReason = DROP_REASON_NOT_DROPPED; + if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) { + dropReason = DROP_REASON_POLICY; + } else if (!mDispatchEnabled) { + dropReason = DROP_REASON_DISABLED; + } switch (mPendingEvent->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ConfigurationChangedEntry* typedEntry = static_cast(mPendingEvent); done = dispatchConfigurationChangedLocked(currentTime, typedEntry); + dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped break; } case EventEntry::TYPE_KEY: { KeyEntry* typedEntry = static_cast(mPendingEvent); - bool appSwitchKey = isAppSwitchKey(typedEntry->keyCode); - bool dropEvent = isAppSwitchDue && ! appSwitchKey; - done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, dropEvent, - nextWakeupTime); - if (done) { - if (dropEvent) { - LOGI("Dropped key because of pending overdue app switch."); - } else if (appSwitchKey) { + if (isAppSwitchDue) { + if (isAppSwitchKeyEventLocked(typedEntry)) { resetPendingAppSwitchLocked(true); + isAppSwitchDue = false; + } else if (dropReason == DROP_REASON_NOT_DROPPED) { + dropReason = DROP_REASON_APP_SWITCH; } } + done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, + dropReason != DROP_REASON_NOT_DROPPED, nextWakeupTime); break; } case EventEntry::TYPE_MOTION: { MotionEntry* typedEntry = static_cast(mPendingEvent); - bool dropEvent = isAppSwitchDue; - done = dispatchMotionLocked(currentTime, typedEntry, dropEvent, nextWakeupTime); - if (done) { - if (dropEvent) { - LOGI("Dropped motion because of pending overdue app switch."); - } + if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { + dropReason = DROP_REASON_APP_SWITCH; } + done = dispatchMotionLocked(currentTime, typedEntry, + dropReason != DROP_REASON_NOT_DROPPED, nextWakeupTime); break; } @@ -389,6 +390,10 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, } if (done) { + if (dropReason != DROP_REASON_NOT_DROPPED) { + dropInboundEventLocked(mPendingEvent, dropReason); + } + releasePendingEventLocked(); *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately } @@ -399,36 +404,83 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { mInboundQueue.enqueueAtTail(entry); switch (entry->type) { - case EventEntry::TYPE_KEY: - needWake |= detectPendingAppSwitchLocked(static_cast(entry)); + case EventEntry::TYPE_KEY: { + KeyEntry* keyEntry = static_cast(entry); + if (isAppSwitchKeyEventLocked(keyEntry)) { + if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { + mAppSwitchSawKeyDown = true; + } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { + if (mAppSwitchSawKeyDown) { +#if DEBUG_APP_SWITCH + LOGD("App switch is pending!"); +#endif + mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; + mAppSwitchSawKeyDown = false; + needWake = true; + } + } + } break; } + } return needWake; } -bool InputDispatcher::isAppSwitchKey(int32_t keyCode) { +void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { + const char* reason; + switch (dropReason) { + case DROP_REASON_POLICY: + reason = "inbound event was dropped because the policy requested that it not be " + "delivered to the application"; + break; + case DROP_REASON_DISABLED: + LOGI("Dropped event because input dispatch is disabled."); + reason = "inbound event was dropped because input dispatch is disabled"; + break; + case DROP_REASON_APP_SWITCH: + LOGI("Dropped event because of pending overdue app switch."); + reason = "inbound event was dropped because of pending overdue app switch"; + break; + default: + assert(false); + return; + } + + switch (entry->type) { + case EventEntry::TYPE_KEY: + synthesizeCancelationEventsForAllConnectionsLocked( + InputState::CANCEL_NON_POINTER_EVENTS, reason); + break; + case EventEntry::TYPE_MOTION: { + MotionEntry* motionEntry = static_cast(entry); + if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { + synthesizeCancelationEventsForAllConnectionsLocked( + InputState::CANCEL_POINTER_EVENTS, reason); + } else { + synthesizeCancelationEventsForAllConnectionsLocked( + InputState::CANCEL_NON_POINTER_EVENTS, reason); + } + break; + } + } +} + +bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) { return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL; } +bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) { + return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) + && isAppSwitchKeyCode(keyEntry->keyCode) + && isEventFromTrustedSourceLocked(keyEntry) + && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); +} + bool InputDispatcher::isAppSwitchPendingLocked() { return mAppSwitchDueTime != LONG_LONG_MAX; } -bool InputDispatcher::detectPendingAppSwitchLocked(KeyEntry* inboundKeyEntry) { - if (inboundKeyEntry->action == AKEY_EVENT_ACTION_UP - && ! (inboundKeyEntry->flags & AKEY_EVENT_FLAG_CANCELED) - && isAppSwitchKey(inboundKeyEntry->keyCode) - && isEventFromReliableSourceLocked(inboundKeyEntry)) { -#if DEBUG_APP_SWITCH - LOGD("App switch is pending!"); -#endif - mAppSwitchDueTime = inboundKeyEntry->eventTime + APP_SWITCH_TIMEOUT; - return true; // need wake - } - return false; -} - void InputDispatcher::resetPendingAppSwitchLocked(bool handled) { mAppSwitchDueTime = LONG_LONG_MAX; @@ -489,12 +541,10 @@ void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) { mAllocator.releaseEventEntry(entry); } -bool InputDispatcher::isEventFromReliableSourceLocked(EventEntry* entry) { +bool InputDispatcher::isEventFromTrustedSourceLocked(EventEntry* entry) { InjectionState* injectionState = entry->injectionState; return ! injectionState - || injectionState->injectorUid == 0 - || mPolicy->checkInjectEventsPermissionNonReentrant( - injectionState->injectorPid, injectionState->injectorUid); + || hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid); } void InputDispatcher::resetKeyRepeatLocked() { @@ -509,7 +559,7 @@ InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked( KeyEntry* entry = mKeyRepeatState.lastKeyEntry; // Reuse the repeated key entry if it is otherwise unreferenced. - uint32_t policyFlags = entry->policyFlags & POLICY_FLAG_RAW_MASK; + uint32_t policyFlags = entry->policyFlags & (POLICY_FLAG_RAW_MASK | POLICY_FLAG_PASS_TO_USER); if (entry->refCount == 1) { mAllocator.recycleKeyEntry(entry); entry->eventTime = currentTime; @@ -565,7 +615,7 @@ bool InputDispatcher::dispatchKeyLocked( if (! dropEvent && mFocusedWindow) { trusted = checkInjectionPermission(mFocusedWindow, entry->injectionState); } else { - trusted = isEventFromReliableSourceLocked(entry); + trusted = isEventFromTrustedSourceLocked(entry); } if (trusted) { CommandEntry* commandEntry = postCommandLocked( @@ -793,9 +843,11 @@ void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTi prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget, resumeWithAppendedMotionSample); } else { - LOGW("Framework requested delivery of an input event to channel '%s' but it " - "is not registered with the input dispatcher.", +#if DEBUG_FOCUS + LOGD("Dropping event delivery to target with channel '%s' because it " + "is no longer registered with the input dispatcher.", inputTarget.inputChannel->getName().string()); +#endif } } } @@ -876,7 +928,9 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); if (connectionIndex >= 0) { sp connection = mConnectionsByReceiveFd.valueAt(connectionIndex); - connection->inputState.setOutOfSync(); + synthesizeCancelationEventsForConnectionLocked( + connection, InputState::CANCEL_ALL_EVENTS, + "application not responding"); } } } @@ -1236,7 +1290,9 @@ Failed: } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { // First pointer went down. if (mTouchState.down) { - LOGW("Pointer down received while already down."); +#if DEBUG_FOCUS + LOGD("Pointer down received while already down."); +#endif } } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { // One pointer went up. @@ -1307,23 +1363,19 @@ void InputDispatcher::addMonitoringTargetsLocked() { bool InputDispatcher::checkInjectionPermission(const InputWindow* window, const InjectionState* injectionState) { if (injectionState - && injectionState->injectorUid > 0 - && (window == NULL || window->ownerUid != injectionState->injectorUid)) { - bool result = mPolicy->checkInjectEventsPermissionNonReentrant( - injectionState->injectorPid, injectionState->injectorUid); - if (! result) { - if (window) { - LOGW("Permission denied: injecting event from pid %d uid %d to window " - "with input channel %s owned by uid %d", - injectionState->injectorPid, injectionState->injectorUid, - window->inputChannel->getName().string(), - window->ownerUid); - } else { - LOGW("Permission denied: injecting event from pid %d uid %d", - injectionState->injectorPid, injectionState->injectorUid); - } - return false; + && (window == NULL || window->ownerUid != injectionState->injectorUid) + && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { + if (window) { + LOGW("Permission denied: injecting event from pid %d uid %d to window " + "with input channel %s owned by uid %d", + injectionState->injectorPid, injectionState->injectorUid, + window->inputChannel->getName().string(), + window->ownerUid); + } else { + LOGW("Permission denied: injecting event from pid %d uid %d", + injectionState->injectorPid, injectionState->injectorUid); } + return false; } return true; } @@ -1408,8 +1460,10 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, // Skip this event if the connection status is not normal. // We don't want to enqueue additional outbound events if the connection is broken. if (connection->status != Connection::STATUS_NORMAL) { - LOGW("channel '%s' ~ Dropping event because the channel status is %s", +#if DEBUG_DISPATCH_CYCLE + LOGD("channel '%s' ~ Dropping event because the channel status is %s", connection->getInputChannelName(), connection->getStatusLabel()); +#endif return; } @@ -1508,40 +1562,6 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, } } - // Bring the input state back in line with reality in case it drifted off during an ANR. - if (connection->inputState.isOutOfSync()) { - mTempCancelationEvents.clear(); - connection->inputState.synthesizeCancelationEvents(& mAllocator, mTempCancelationEvents); - connection->inputState.resetOutOfSync(); - - if (! mTempCancelationEvents.isEmpty()) { - LOGI("channel '%s' ~ Generated %d cancelation events to bring channel back in sync " - "with reality.", - connection->getInputChannelName(), mTempCancelationEvents.size()); - - for (size_t i = 0; i < mTempCancelationEvents.size(); i++) { - EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i); - switch (cancelationEventEntry->type) { - case EventEntry::TYPE_KEY: - logOutboundKeyDetailsLocked(" ", - static_cast(cancelationEventEntry)); - break; - case EventEntry::TYPE_MOTION: - logOutboundMotionDetailsLocked(" ", - static_cast(cancelationEventEntry)); - break; - } - - DispatchEntry* cancelationDispatchEntry = - mAllocator.obtainDispatchEntry(cancelationEventEntry, - 0, inputTarget->xOffset, inputTarget->yOffset); // increments ref - connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry); - - mAllocator.releaseEventEntry(cancelationEventEntry); - } - } - } - // This is a new event. // Enqueue a new dispatch entry onto the outbound queue for this connection. DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref @@ -1635,7 +1655,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, if (status) { LOGE("channel '%s' ~ Could not publish key event, " "status=%d", connection->getInputChannelName(), status); - abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + abortBrokenDispatchCycleLocked(currentTime, connection); return; } break; @@ -1685,7 +1705,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, if (status) { LOGE("channel '%s' ~ Could not publish motion event, " "status=%d", connection->getInputChannelName(), status); - abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + abortBrokenDispatchCycleLocked(currentTime, connection); return; } @@ -1706,7 +1726,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, LOGE("channel '%s' ~ Could not append motion sample " "for a reason other than out of memory, status=%d", connection->getInputChannelName(), status); - abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + abortBrokenDispatchCycleLocked(currentTime, connection); return; } } @@ -1727,7 +1747,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, if (status) { LOGE("channel '%s' ~ Could not send dispatch signal, status=%d", connection->getInputChannelName(), status); - abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + abortBrokenDispatchCycleLocked(currentTime, connection); return; } @@ -1764,7 +1784,7 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, if (status) { LOGE("channel '%s' ~ Could not reset publisher, status=%d", connection->getInputChannelName(), status); - abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + abortBrokenDispatchCycleLocked(currentTime, connection); return; } @@ -1806,28 +1826,23 @@ void InputDispatcher::startNextDispatchCycleLocked(nsecs_t currentTime, deactivateConnectionLocked(connection.get()); } -void InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime, - const sp& connection, bool broken) { +void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, + const sp& connection) { #if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ abortDispatchCycle - broken=%s", + LOGD("channel '%s' ~ abortBrokenDispatchCycle - broken=%s", connection->getInputChannelName(), toString(broken)); #endif - // Input state will no longer be realistic. - connection->inputState.setOutOfSync(); - // Clear the outbound queue. drainOutboundQueueLocked(connection.get()); - // Handle the case where the connection appears to be unrecoverably broken. + // The connection appears to be unrecoverably broken. // Ignore already broken or zombie connections. - if (broken) { - if (connection->status == Connection::STATUS_NORMAL) { - connection->status = Connection::STATUS_BROKEN; + if (connection->status == Connection::STATUS_NORMAL) { + connection->status = Connection::STATUS_BROKEN; - // Notify other system components. - onDispatchCycleBrokenLocked(currentTime, connection); - } + // Notify other system components. + onDispatchCycleBrokenLocked(currentTime, connection); } } @@ -1862,7 +1877,7 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { LOGE("channel '%s' ~ Consumer closed input channel or an error occurred. " "events=0x%x", connection->getInputChannelName(), events); - d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + d->abortBrokenDispatchCycleLocked(currentTime, connection); d->runCommandsLockedInterruptible(); return 0; // remove the callback } @@ -1877,7 +1892,7 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data if (status) { LOGE("channel '%s' ~ Failed to receive finished signal. status=%d", connection->getInputChannelName(), status); - d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + d->abortBrokenDispatchCycleLocked(currentTime, connection); d->runCommandsLockedInterruptible(); return 0; // remove the callback } @@ -1888,6 +1903,77 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data } // release lock } +void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( + InputState::CancelationOptions options, const char* reason) { + for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) { + synthesizeCancelationEventsForConnectionLocked( + mConnectionsByReceiveFd.valueAt(i), options, reason); + } +} + +void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( + const sp& channel, InputState::CancelationOptions options, + const char* reason) { + ssize_t index = getConnectionIndexLocked(channel); + if (index >= 0) { + synthesizeCancelationEventsForConnectionLocked( + mConnectionsByReceiveFd.valueAt(index), options, reason); + } +} + +void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( + const sp& connection, InputState::CancelationOptions options, + const char* reason) { + nsecs_t currentTime = now(); + + mTempCancelationEvents.clear(); + connection->inputState.synthesizeCancelationEvents(currentTime, & mAllocator, + mTempCancelationEvents, options); + + if (! mTempCancelationEvents.isEmpty() + && connection->status != Connection::STATUS_BROKEN) { +#if DEBUG_OUTBOUND_EVENT_DETAILS + LOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync " + "with reality: %s, options=%d.", + connection->getInputChannelName(), mTempCancelationEvents.size(), reason, options); +#endif + for (size_t i = 0; i < mTempCancelationEvents.size(); i++) { + EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i); + switch (cancelationEventEntry->type) { + case EventEntry::TYPE_KEY: + logOutboundKeyDetailsLocked("cancel - ", + static_cast(cancelationEventEntry)); + break; + case EventEntry::TYPE_MOTION: + logOutboundMotionDetailsLocked("cancel - ", + static_cast(cancelationEventEntry)); + break; + } + + int32_t xOffset, yOffset; + const InputWindow* window = getWindowLocked(connection->inputChannel); + if (window) { + xOffset = -window->frameLeft; + yOffset = -window->frameTop; + } else { + xOffset = 0; + yOffset = 0; + } + + DispatchEntry* cancelationDispatchEntry = + mAllocator.obtainDispatchEntry(cancelationEventEntry, // increments ref + 0, xOffset, yOffset); + connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry); + + mAllocator.releaseEventEntry(cancelationEventEntry); + } + + if (!connection->outboundQueue.headSentinel.next->inProgress) { + startDispatchCycleLocked(currentTime, connection); + } + } +} + InputDispatcher::MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) { assert(pointerIds.value != 0); @@ -1999,6 +2085,9 @@ void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t sou return; } + mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags, + keyCode, scanCode, /*byref*/ policyFlags); + bool needWake; { // acquire lock AutoMutex _l(mLock); @@ -2041,6 +2130,8 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t return; } + mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags); + bool needWake; { // acquire lock AutoMutex _l(mLock); @@ -2165,6 +2256,16 @@ NoBatchingOrStreaming:; } } +void InputDispatcher::notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, + uint32_t policyFlags) { +#if DEBUG_INBOUND_EVENT_DETAILS + LOGD("notifySwitch - switchCode=%d, switchValue=%d, policyFlags=0x%x", + switchCode, switchValue, policyFlags); +#endif + + mPolicy->notifySwitch(when, switchCode, switchValue, policyFlags); +} + int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) { #if DEBUG_INBOUND_EVENT_DETAILS @@ -2174,27 +2275,84 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, #endif nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); + bool trusted = hasInjectionPermission(injectorPid, injectorUid); - InjectionState* injectionState; - bool needWake; - { // acquire lock - AutoMutex _l(mLock); - - EventEntry* injectedEntry = createEntryFromInjectedInputEventLocked(event); - if (! injectedEntry) { + EventEntry* injectedEntry; + switch (event->getType()) { + case AINPUT_EVENT_TYPE_KEY: { + const KeyEvent* keyEvent = static_cast(event); + int32_t action = keyEvent->getAction(); + if (! validateKeyEvent(action)) { return INPUT_EVENT_INJECTION_FAILED; } - injectionState = mAllocator.obtainInjectionState(injectorPid, injectorUid); - if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { - injectionState->injectionIsAsync = true; + nsecs_t eventTime = keyEvent->getEventTime(); + int32_t deviceId = keyEvent->getDeviceId(); + int32_t flags = keyEvent->getFlags(); + int32_t keyCode = keyEvent->getKeyCode(); + int32_t scanCode = keyEvent->getScanCode(); + uint32_t policyFlags = POLICY_FLAG_INJECTED; + if (trusted) { + mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags, + keyCode, scanCode, /*byref*/ policyFlags); } - injectionState->refCount += 1; - injectedEntry->injectionState = injectionState; + mLock.lock(); + injectedEntry = mAllocator.obtainKeyEntry(eventTime, deviceId, keyEvent->getSource(), + policyFlags, action, flags, keyCode, scanCode, keyEvent->getMetaState(), + keyEvent->getRepeatCount(), keyEvent->getDownTime()); + break; + } - needWake = enqueueInboundEventLocked(injectedEntry); - } // release lock + case AINPUT_EVENT_TYPE_MOTION: { + const MotionEvent* motionEvent = static_cast(event); + int32_t action = motionEvent->getAction(); + size_t pointerCount = motionEvent->getPointerCount(); + const int32_t* pointerIds = motionEvent->getPointerIds(); + if (! validateMotionEvent(action, pointerCount, pointerIds)) { + return INPUT_EVENT_INJECTION_FAILED; + } + + nsecs_t eventTime = motionEvent->getEventTime(); + uint32_t policyFlags = POLICY_FLAG_INJECTED; + if (trusted) { + mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags); + } + + mLock.lock(); + const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); + const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); + MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes, + motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, + action, motionEvent->getFlags(), + motionEvent->getMetaState(), motionEvent->getEdgeFlags(), + motionEvent->getXPrecision(), motionEvent->getYPrecision(), + motionEvent->getDownTime(), uint32_t(pointerCount), + pointerIds, samplePointerCoords); + for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { + sampleEventTimes += 1; + samplePointerCoords += pointerCount; + mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords); + } + injectedEntry = motionEntry; + break; + } + + default: + LOGW("Cannot inject event of type %d", event->getType()); + return INPUT_EVENT_INJECTION_FAILED; + } + + InjectionState* injectionState = mAllocator.obtainInjectionState(injectorPid, injectorUid); + if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { + injectionState->injectionIsAsync = true; + } + + injectionState->refCount += 1; + injectedEntry->injectionState = injectionState; + + bool needWake = enqueueInboundEventLocked(injectedEntry); + mLock.unlock(); if (needWake) { mLooper->wake(); @@ -2260,6 +2418,11 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, return injectionResult; } +bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { + return injectorUid == 0 + || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); +} + void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) { InjectionState* injectionState = entry->injectionState; if (injectionState) { @@ -2310,59 +2473,6 @@ void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* ent } } -InputDispatcher::EventEntry* InputDispatcher::createEntryFromInjectedInputEventLocked( - const InputEvent* event) { - switch (event->getType()) { - case AINPUT_EVENT_TYPE_KEY: { - const KeyEvent* keyEvent = static_cast(event); - if (! validateKeyEvent(keyEvent->getAction())) { - return NULL; - } - - uint32_t policyFlags = POLICY_FLAG_INJECTED; - - KeyEntry* keyEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(), - keyEvent->getDeviceId(), keyEvent->getSource(), policyFlags, - keyEvent->getAction(), keyEvent->getFlags(), - keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(), - keyEvent->getRepeatCount(), keyEvent->getDownTime()); - return keyEntry; - } - - case AINPUT_EVENT_TYPE_MOTION: { - const MotionEvent* motionEvent = static_cast(event); - if (! validateMotionEvent(motionEvent->getAction(), - motionEvent->getPointerCount(), motionEvent->getPointerIds())) { - return NULL; - } - - uint32_t policyFlags = POLICY_FLAG_INJECTED; - - const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); - const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); - size_t pointerCount = motionEvent->getPointerCount(); - - MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - motionEvent->getAction(), motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), uint32_t(pointerCount), - motionEvent->getPointerIds(), samplePointerCoords); - for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { - sampleEventTimes += 1; - samplePointerCoords += pointerCount; - mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords); - } - return motionEntry; - } - - default: - assert(false); - return NULL; - } -} - const InputWindow* InputDispatcher::getWindowLocked(const sp& inputChannel) { for (size_t i = 0; i < mWindows.size(); i++) { const InputWindow* window = & mWindows[i]; @@ -2381,7 +2491,12 @@ void InputDispatcher::setInputWindows(const Vector& inputWindows) { AutoMutex _l(mLock); // Clear old window pointers. - mFocusedWindow = NULL; + sp oldFocusedWindowChannel; + if (mFocusedWindow) { + oldFocusedWindowChannel = mFocusedWindow->inputChannel; + mFocusedWindow = NULL; + } + mWindows.clear(); // Loop over new windows and rebuild the necessary window pointers for @@ -2397,6 +2512,24 @@ void InputDispatcher::setInputWindows(const Vector& inputWindows) { } } + if (oldFocusedWindowChannel != NULL) { + if (!mFocusedWindow || oldFocusedWindowChannel != mFocusedWindow->inputChannel) { +#if DEBUG_FOCUS + LOGD("Focus left window: %s", + oldFocusedWindowChannel->getName().string()); +#endif + synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel, + InputState::CANCEL_NON_POINTER_EVENTS, "focus left window"); + oldFocusedWindowChannel.clear(); + } + } + if (mFocusedWindow && oldFocusedWindowChannel == NULL) { +#if DEBUG_FOCUS + LOGD("Focus entered window: %s", + mFocusedWindow->inputChannel->getName().string()); +#endif + } + for (size_t i = 0; i < mTouchState.windows.size(); ) { TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i); const InputWindow* window = getWindowLocked(touchedWindow.channel); @@ -2404,12 +2537,17 @@ void InputDispatcher::setInputWindows(const Vector& inputWindows) { touchedWindow.window = window; i += 1; } else { +#if DEBUG_FOCUS + LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string()); +#endif mTouchState.windows.removeAt(i); + synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel, + InputState::CANCEL_POINTER_EVENTS, "touched window was removed"); } } #if DEBUG_FOCUS - logDispatchStateLocked(); + //logDispatchStateLocked(); #endif } // release lock @@ -2432,7 +2570,7 @@ void InputDispatcher::setFocusedApplication(const InputApplication* inputApplica } #if DEBUG_FOCUS - logDispatchStateLocked(); + //logDispatchStateLocked(); #endif } // release lock @@ -2469,7 +2607,7 @@ void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { } #if DEBUG_FOCUS - logDispatchStateLocked(); + //logDispatchStateLocked(); #endif } // release lock @@ -2571,11 +2709,10 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { for (size_t i = 0; i < mActiveConnections.size(); i++) { const Connection* connection = mActiveConnections[i]; dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u" - "inputState.isNeutral=%s, inputState.isOutOfSync=%s\n", + "inputState.isNeutral=%s\n", i, connection->getInputChannelName(), connection->getStatusLabel(), connection->outboundQueue.count(), - toString(connection->inputState.isNeutral()), - toString(connection->inputState.isOutOfSync())); + toString(connection->inputState.isNeutral())); } } else { dump.append(INDENT "ActiveConnections: \n"); @@ -2656,7 +2793,7 @@ status_t InputDispatcher::unregisterInputChannel(const sp& inputCh mLooper->removeFd(inputChannel->getReceivePipeFd()); nsecs_t currentTime = now(); - abortDispatchCycleLocked(currentTime, connection, true /*broken*/); + abortBrokenDispatchCycleLocked(currentTime, connection); runCommandsLockedInterruptible(); } // release lock @@ -2837,11 +2974,12 @@ InputDispatcher::Allocator::obtainInjectionState(int32_t injectorPid, int32_t in } void InputDispatcher::Allocator::initializeEventEntry(EventEntry* entry, int32_t type, - nsecs_t eventTime) { + nsecs_t eventTime, uint32_t policyFlags) { entry->type = type; entry->refCount = 1; entry->dispatchInProgress = false; entry->eventTime = eventTime; + entry->policyFlags = policyFlags; entry->injectionState = NULL; } @@ -2855,7 +2993,7 @@ void InputDispatcher::Allocator::releaseEventEntryInjectionState(EventEntry* ent InputDispatcher::ConfigurationChangedEntry* InputDispatcher::Allocator::obtainConfigurationChangedEntry(nsecs_t eventTime) { ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc(); - initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime); + initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime, 0); return entry; } @@ -2864,11 +3002,10 @@ InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry(nsecs_t ev int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime) { KeyEntry* entry = mKeyEntryPool.alloc(); - initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime); + initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime, policyFlags); entry->deviceId = deviceId; entry->source = source; - entry->policyFlags = policyFlags; entry->action = action; entry->flags = flags; entry->keyCode = keyCode; @@ -2887,12 +3024,11 @@ InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsec nsecs_t downTime, uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords) { MotionEntry* entry = mMotionEntryPool.alloc(); - initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime); + initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime, policyFlags); entry->eventTime = eventTime; entry->deviceId = deviceId; entry->source = source; - entry->policyFlags = policyFlags; entry->action = action; entry->flags = flags; entry->metaState = metaState; @@ -3039,8 +3175,7 @@ uint32_t InputDispatcher::MotionEntry::countSamples() const { // --- InputDispatcher::InputState --- -InputDispatcher::InputState::InputState() : - mIsOutOfSync(false) { +InputDispatcher::InputState::InputState() { } InputDispatcher::InputState::~InputState() { @@ -3050,20 +3185,6 @@ bool InputDispatcher::InputState::isNeutral() const { return mKeyMementos.isEmpty() && mMotionMementos.isEmpty(); } -bool InputDispatcher::InputState::isOutOfSync() const { - return mIsOutOfSync; -} - -void InputDispatcher::InputState::setOutOfSync() { - if (! isNeutral()) { - mIsOutOfSync = true; - } -} - -void InputDispatcher::InputState::resetOutOfSync() { - mIsOutOfSync = false; -} - InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackEvent( const EventEntry* entry) { switch (entry->type) { @@ -3090,9 +3211,6 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackKey( switch (action) { case AKEY_EVENT_ACTION_UP: mKeyMementos.removeAt(i); - if (isNeutral()) { - mIsOutOfSync = false; - } return CONSISTENT; case AKEY_EVENT_ACTION_DOWN: @@ -3132,9 +3250,6 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackMotio case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: mMotionMementos.removeAt(i); - if (isNeutral()) { - mIsOutOfSync = false; - } return CONSISTENT; case AMOTION_EVENT_ACTION_DOWN: @@ -3192,30 +3307,52 @@ void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* } } -void InputDispatcher::InputState::synthesizeCancelationEvents( - Allocator* allocator, Vector& outEvents) const { - for (size_t i = 0; i < mKeyMementos.size(); i++) { +void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime, + Allocator* allocator, Vector& outEvents, + CancelationOptions options) { + for (size_t i = 0; i < mKeyMementos.size(); ) { const KeyMemento& memento = mKeyMementos.itemAt(i); - outEvents.push(allocator->obtainKeyEntry(now(), - memento.deviceId, memento.source, 0, - AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED, - memento.keyCode, memento.scanCode, 0, 0, memento.downTime)); + if (shouldCancelEvent(memento.source, options)) { + outEvents.push(allocator->obtainKeyEntry(currentTime, + memento.deviceId, memento.source, 0, + AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED, + memento.keyCode, memento.scanCode, 0, 0, memento.downTime)); + mKeyMementos.removeAt(i); + } else { + i += 1; + } } for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos.itemAt(i); - outEvents.push(allocator->obtainMotionEntry(now(), - memento.deviceId, memento.source, 0, - AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0, - memento.xPrecision, memento.yPrecision, memento.downTime, - memento.pointerCount, memento.pointerIds, memento.pointerCoords)); + if (shouldCancelEvent(memento.source, options)) { + outEvents.push(allocator->obtainMotionEntry(currentTime, + memento.deviceId, memento.source, 0, + AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0, + memento.xPrecision, memento.yPrecision, memento.downTime, + memento.pointerCount, memento.pointerIds, memento.pointerCoords)); + mMotionMementos.removeAt(i); + } else { + i += 1; + } } } void InputDispatcher::InputState::clear() { mKeyMementos.clear(); mMotionMementos.clear(); - mIsOutOfSync = false; +} + +bool InputDispatcher::InputState::shouldCancelEvent(int32_t eventSource, + CancelationOptions options) { + switch (options) { + case CANCEL_POINTER_EVENTS: + return eventSource & AINPUT_SOURCE_CLASS_POINTER; + case CANCEL_NON_POINTER_EVENTS: + return !(eventSource & AINPUT_SOURCE_CLASS_POINTER); + default: + return true; + } } diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index 7adc764ab..0560bb89f 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -796,10 +796,6 @@ int32_t InputMapper::getMetaState() { return 0; } -bool InputMapper::applyStandardPolicyActions(nsecs_t when, int32_t policyActions) { - return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH; -} - // --- SwitchInputMapper --- @@ -823,11 +819,7 @@ void SwitchInputMapper::process(const RawEvent* rawEvent) { } void SwitchInputMapper::processSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) { - uint32_t policyFlags = 0; - int32_t policyActions = getPolicy()->interceptSwitch( - when, switchCode, switchValue, policyFlags); - - applyStandardPolicyActions(when, policyActions); + getDispatcher()->notifySwitch(when, switchCode, switchValue, 0); } int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { @@ -983,29 +975,9 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, getContext()->updateGlobalMetaState(); } - applyPolicyAndDispatch(when, policyFlags, down, keyCode, scanCode, newMetaState, downTime); -} - -void KeyboardInputMapper::applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags, bool down, - int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) { - int32_t policyActions = getPolicy()->interceptKey(when, - getDeviceId(), down, keyCode, scanCode, policyFlags); - - if (! applyStandardPolicyActions(when, policyActions)) { - return; // event dropped - } - - int32_t keyEventAction = down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP; - int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM; - if (policyFlags & POLICY_FLAG_WOKE_HERE) { - keyEventFlags |= AKEY_EVENT_FLAG_WOKE_HERE; - } - if (policyFlags & POLICY_FLAG_VIRTUAL) { - keyEventFlags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; - } - getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, - keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); + down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, + AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime); } ssize_t KeyboardInputMapper::findKeyDownLocked(int32_t scanCode) { @@ -1215,26 +1187,13 @@ void TrackballInputMapper::sync(nsecs_t when) { } } // release lock - applyPolicyAndDispatch(when, motionEventAction, & pointerCoords, downTime); - - mAccumulator.clear(); -} - -void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction, - PointerCoords* pointerCoords, nsecs_t downTime) { - uint32_t policyFlags = 0; - int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags); - - if (! applyStandardPolicyActions(when, policyActions)) { - return; // event dropped - } - int32_t metaState = mContext->getGlobalMetaState(); int32_t pointerId = 0; - - getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, policyFlags, + getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, 0, motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, - 1, & pointerId, pointerCoords, mXPrecision, mYPrecision, downTime); + 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); + + mAccumulator.clear(); } int32_t TrackballInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { @@ -2012,15 +1971,7 @@ void TouchInputMapper::reset() { } void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { - // Apply generic policy actions. - uint32_t policyFlags = 0; - int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags); - - if (! applyStandardPolicyActions(when, policyActions)) { - mLastTouch.clear(); - return; // event dropped - } // Preprocess pointer data. @@ -2160,24 +2111,11 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( } // release lock // Dispatch virtual key. - applyPolicyAndDispatchVirtualKey(when, policyFlags, keyEventAction, keyEventFlags, - keyCode, scanCode, downTime); - return touchResult; -} - -void TouchInputMapper::applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags, - int32_t keyCode, int32_t scanCode, nsecs_t downTime) { int32_t metaState = mContext->getGlobalMetaState(); - policyFlags |= POLICY_FLAG_VIRTUAL; - int32_t policyActions = getPolicy()->interceptKey(when, getDeviceId(), - keyEventAction == AKEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags); - - if (applyStandardPolicyActions(when, policyActions)) { - getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, - keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); - } + getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, + keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); + return touchResult; } void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {