Loading include/ui/InputDispatcher.h +19 −0 Original line number Diff line number Diff line Loading @@ -159,6 +159,12 @@ public: virtual int32_t waitForMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags, int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets) = 0; /* Gets the maximum suggested event delivery rate per second. * This value is used to throttle motion event movement actions on a per-device * basis. It is not intended to be a hard limit. */ virtual int32_t getMaxEventsPerSecond() = 0; }; Loading Loading @@ -332,6 +338,8 @@ private: // Linked list of motion samples associated with this motion event. MotionSample firstSample; MotionSample* lastSample; uint32_t countSamples() const; }; // Tracks the progress of dispatching a particular event to a particular connection. Loading Loading @@ -587,6 +595,17 @@ private: Condition mInjectionSyncFinishedCondition; void decrementPendingSyncDispatchesLocked(EventEntry* entry); // Throttling state. struct ThrottleState { nsecs_t minTimeBetweenEvents; nsecs_t lastEventTime; int32_t lastDeviceId; uint32_t lastSource; uint32_t originalSampleCount; // only collected during debugging } mThrottleState; // Key repeat tracking. // XXX Move this up to the input reader instead. struct KeyRepeatState { Loading libs/ui/InputDispatcher.cpp +77 −5 Original line number Diff line number Diff line Loading @@ -28,6 +28,9 @@ // Log debug messages about input event injection. #define DEBUG_INJECTION 0 // Log debug messages about input event throttling. #define DEBUG_THROTTLING 0 #include <cutils/log.h> #include <ui/InputDispatcher.h> Loading Loading @@ -66,6 +69,15 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mKeyRepeatState.lastKeyEntry = NULL; int32_t maxEventsPerSecond = policy->getMaxEventsPerSecond(); mThrottleState.minTimeBetweenEvents = 1000000000LL / maxEventsPerSecond; mThrottleState.lastDeviceId = -1; #if DEBUG_THROTTLING mThrottleState.originalSampleCount = 0; LOGD("Throttling - Max events per second = %d", maxEventsPerSecond); #endif mCurrentInputTargetsValid = false; } Loading Loading @@ -144,12 +156,60 @@ void InputDispatcher::dispatchOnce() { } } else { // Inbound queue has at least one entry. // Start processing it but leave it on the queue until later so that the EventEntry* entry = mInboundQueue.head.next; // Consider throttling the entry if it is a move event and there are no // other events behind it in the queue. Due to movement batching, additional // 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) { MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); int32_t deviceId = motionEntry->deviceId; uint32_t source = motionEntry->source; if (motionEntry->next == & mInboundQueue.tail && motionEntry->action == AMOTION_EVENT_ACTION_MOVE && deviceId == mThrottleState.lastDeviceId && source == mThrottleState.lastSource) { nsecs_t nextTime = mThrottleState.lastEventTime + mThrottleState.minTimeBetweenEvents; if (currentTime < nextTime) { // Throttle it! #if DEBUG_THROTTLING LOGD("Throttling - Delaying motion event for " "device 0x%x, source 0x%08x by up to %0.3fms.", deviceId, source, (nextTime - currentTime) * 0.000001); #endif if (nextTime < nextWakeupTime) { nextWakeupTime = nextTime; } if (mThrottleState.originalSampleCount == 0) { mThrottleState.originalSampleCount = motionEntry->countSamples(); } goto Throttle; } } #if DEBUG_THROTTLING if (mThrottleState.originalSampleCount != 0) { uint32_t count = motionEntry->countSamples(); LOGD("Throttling - Motion event sample count grew by %d from %d to %d.", count - mThrottleState.originalSampleCount, mThrottleState.originalSampleCount, count); mThrottleState.originalSampleCount = 0; } #endif mThrottleState.lastEventTime = currentTime; mThrottleState.lastDeviceId = deviceId; mThrottleState.lastSource = source; } // Start processing the entry but leave it on the queue until later so that the // input reader can keep appending samples onto a motion event between the // time we started processing it and the time we finally enqueue dispatch // entries for it. EventEntry* entry = mInboundQueue.head.next; switch (entry->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ConfigurationChangedEntry* typedEntry = Loading Loading @@ -179,6 +239,8 @@ void InputDispatcher::dispatchOnce() { mInboundQueue.dequeue(entry); mAllocator.releaseEventEntry(entry); skipPoll = true; Throttle: ; } } Loading @@ -192,8 +254,8 @@ void InputDispatcher::dispatchOnce() { return; } // Wait for callback or timeout or wake. nsecs_t timeout = nanoseconds_to_milliseconds(nextWakeupTime - currentTime); // Wait for callback or timeout or wake. (make sure we round up, not down) nsecs_t timeout = (nextWakeupTime - currentTime + 999999LL) / 1000000LL; int32_t timeoutMillis = timeout > INT_MAX ? -1 : timeout > 0 ? int32_t(timeout) : 0; mPollLoop->pollOnce(timeoutMillis); } Loading Loading @@ -1708,6 +1770,16 @@ void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry, motionEntry->lastSample = sample; } // --- InputDispatcher::MotionEntry --- uint32_t InputDispatcher::MotionEntry::countSamples() const { uint32_t count = 1; for (MotionSample* sample = firstSample.next; sample != NULL; sample = sample->next) { count += 1; } return count; } // --- InputDispatcher::Connection --- InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) : Loading Loading
include/ui/InputDispatcher.h +19 −0 Original line number Diff line number Diff line Loading @@ -159,6 +159,12 @@ public: virtual int32_t waitForMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags, int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets) = 0; /* Gets the maximum suggested event delivery rate per second. * This value is used to throttle motion event movement actions on a per-device * basis. It is not intended to be a hard limit. */ virtual int32_t getMaxEventsPerSecond() = 0; }; Loading Loading @@ -332,6 +338,8 @@ private: // Linked list of motion samples associated with this motion event. MotionSample firstSample; MotionSample* lastSample; uint32_t countSamples() const; }; // Tracks the progress of dispatching a particular event to a particular connection. Loading Loading @@ -587,6 +595,17 @@ private: Condition mInjectionSyncFinishedCondition; void decrementPendingSyncDispatchesLocked(EventEntry* entry); // Throttling state. struct ThrottleState { nsecs_t minTimeBetweenEvents; nsecs_t lastEventTime; int32_t lastDeviceId; uint32_t lastSource; uint32_t originalSampleCount; // only collected during debugging } mThrottleState; // Key repeat tracking. // XXX Move this up to the input reader instead. struct KeyRepeatState { Loading
libs/ui/InputDispatcher.cpp +77 −5 Original line number Diff line number Diff line Loading @@ -28,6 +28,9 @@ // Log debug messages about input event injection. #define DEBUG_INJECTION 0 // Log debug messages about input event throttling. #define DEBUG_THROTTLING 0 #include <cutils/log.h> #include <ui/InputDispatcher.h> Loading Loading @@ -66,6 +69,15 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mKeyRepeatState.lastKeyEntry = NULL; int32_t maxEventsPerSecond = policy->getMaxEventsPerSecond(); mThrottleState.minTimeBetweenEvents = 1000000000LL / maxEventsPerSecond; mThrottleState.lastDeviceId = -1; #if DEBUG_THROTTLING mThrottleState.originalSampleCount = 0; LOGD("Throttling - Max events per second = %d", maxEventsPerSecond); #endif mCurrentInputTargetsValid = false; } Loading Loading @@ -144,12 +156,60 @@ void InputDispatcher::dispatchOnce() { } } else { // Inbound queue has at least one entry. // Start processing it but leave it on the queue until later so that the EventEntry* entry = mInboundQueue.head.next; // Consider throttling the entry if it is a move event and there are no // other events behind it in the queue. Due to movement batching, additional // 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) { MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); int32_t deviceId = motionEntry->deviceId; uint32_t source = motionEntry->source; if (motionEntry->next == & mInboundQueue.tail && motionEntry->action == AMOTION_EVENT_ACTION_MOVE && deviceId == mThrottleState.lastDeviceId && source == mThrottleState.lastSource) { nsecs_t nextTime = mThrottleState.lastEventTime + mThrottleState.minTimeBetweenEvents; if (currentTime < nextTime) { // Throttle it! #if DEBUG_THROTTLING LOGD("Throttling - Delaying motion event for " "device 0x%x, source 0x%08x by up to %0.3fms.", deviceId, source, (nextTime - currentTime) * 0.000001); #endif if (nextTime < nextWakeupTime) { nextWakeupTime = nextTime; } if (mThrottleState.originalSampleCount == 0) { mThrottleState.originalSampleCount = motionEntry->countSamples(); } goto Throttle; } } #if DEBUG_THROTTLING if (mThrottleState.originalSampleCount != 0) { uint32_t count = motionEntry->countSamples(); LOGD("Throttling - Motion event sample count grew by %d from %d to %d.", count - mThrottleState.originalSampleCount, mThrottleState.originalSampleCount, count); mThrottleState.originalSampleCount = 0; } #endif mThrottleState.lastEventTime = currentTime; mThrottleState.lastDeviceId = deviceId; mThrottleState.lastSource = source; } // Start processing the entry but leave it on the queue until later so that the // input reader can keep appending samples onto a motion event between the // time we started processing it and the time we finally enqueue dispatch // entries for it. EventEntry* entry = mInboundQueue.head.next; switch (entry->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ConfigurationChangedEntry* typedEntry = Loading Loading @@ -179,6 +239,8 @@ void InputDispatcher::dispatchOnce() { mInboundQueue.dequeue(entry); mAllocator.releaseEventEntry(entry); skipPoll = true; Throttle: ; } } Loading @@ -192,8 +254,8 @@ void InputDispatcher::dispatchOnce() { return; } // Wait for callback or timeout or wake. nsecs_t timeout = nanoseconds_to_milliseconds(nextWakeupTime - currentTime); // Wait for callback or timeout or wake. (make sure we round up, not down) nsecs_t timeout = (nextWakeupTime - currentTime + 999999LL) / 1000000LL; int32_t timeoutMillis = timeout > INT_MAX ? -1 : timeout > 0 ? int32_t(timeout) : 0; mPollLoop->pollOnce(timeoutMillis); } Loading Loading @@ -1708,6 +1770,16 @@ void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry, motionEntry->lastSample = sample; } // --- InputDispatcher::MotionEntry --- uint32_t InputDispatcher::MotionEntry::countSamples() const { uint32_t count = 1; for (MotionSample* sample = firstSample.next; sample != NULL; sample = sample->next) { count += 1; } return count; } // --- InputDispatcher::Connection --- InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) : Loading