Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b5e70b7 authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Add support for throttling motion events." into gingerbread

parents c278f33a 542412c8
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -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;
};


@@ -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.
@@ -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 {
+77 −5
Original line number Diff line number Diff line
@@ -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>

@@ -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;
}

@@ -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 =
@@ -179,6 +239,8 @@ void InputDispatcher::dispatchOnce() {
                mInboundQueue.dequeue(entry);
                mAllocator.releaseEventEntry(entry);
                skipPoll = true;

            Throttle: ;
            }
        }

@@ -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);
}
@@ -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) :