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 246df8f89..6743d139f 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 @@ -416,6 +443,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); @@ -458,6 +487,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 @@ -471,7 +501,6 @@ private: struct KeyEntry : EventEntry { int32_t deviceId; int32_t source; - uint32_t policyFlags; int32_t action; int32_t flags; int32_t keyCode; @@ -500,7 +529,6 @@ private: struct MotionEntry : EventEntry { int32_t deviceId; int32_t source; - uint32_t policyFlags; int32_t action; int32_t flags; int32_t metaState; @@ -675,7 +703,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); }; @@ -696,21 +725,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); @@ -723,16 +750,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; @@ -756,6 +781,8 @@ private: Vector mKeyMementos; Vector mMotionMementos; + + static bool shouldCancelEvent(int32_t eventSource, CancelationOptions options); }; /* Manages the dispatch state associated with a single input channel. */ @@ -805,6 +832,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; @@ -824,12 +858,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. @@ -851,7 +889,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; @@ -886,7 +924,7 @@ private: void drainInboundQueueLocked(); void releasePendingEventLocked(); void releaseInboundEventLocked(EventEntry* entry); - bool isEventFromReliableSourceLocked(EventEntry* entry); + bool isEventFromTrustedSourceLocked(EventEntry* entry); // Dispatch state. bool mDispatchEnabled; @@ -995,11 +1033,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 75b2294f5..a796ef51e 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 @@ -2635,11 +2773,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"); @@ -2720,7 +2857,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 @@ -2901,11 +3038,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; } @@ -2919,7 +3057,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; } @@ -2928,11 +3066,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; @@ -2951,12 +3088,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; @@ -3103,8 +3239,7 @@ uint32_t InputDispatcher::MotionEntry::countSamples() const { // --- InputDispatcher::InputState --- -InputDispatcher::InputState::InputState() : - mIsOutOfSync(false) { +InputDispatcher::InputState::InputState() { } InputDispatcher::InputState::~InputState() { @@ -3114,20 +3249,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) { @@ -3154,9 +3275,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: @@ -3196,9 +3314,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: @@ -3256,30 +3371,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) {