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

Commit 50de30a5 authored by Jeff Brown's avatar Jeff Brown
Browse files

Native input event dispatching.

Target identification is now fully native.
Fixed a couple of minor issues related to input injection.
Native input enabled by default, can be disabled by setting
WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH to false.

Change-Id: I7edf66ed3e987cc9306ad4743ac57a116af452ff
parent a8468725
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -87,6 +87,9 @@ enum {
    // Indicates that the screen was dim when the event was received and the event
    // Indicates that the screen was dim when the event was received and the event
    // should brighten the device.
    // should brighten the device.
    POLICY_FLAG_BRIGHT_HERE = 0x20000000,
    POLICY_FLAG_BRIGHT_HERE = 0x20000000,

    // Indicates that the dispatcher should call back into the policy before dispatching. */
    POLICY_FLAG_INTERCEPT_DISPATCH = 0x40000000,
};
};


/*
/*
+16 −4
Original line number Original line Diff line number Diff line
@@ -126,21 +126,21 @@ public:
    /* Gets the key repeat timeout or -1 if automatic key repeating is disabled. */
    /* Gets the key repeat timeout or -1 if automatic key repeating is disabled. */
    virtual nsecs_t getKeyRepeatTimeout() = 0;
    virtual nsecs_t getKeyRepeatTimeout() = 0;


    /* Gets the input targets for a key event.
    /* Waits for key event input targets to become available.
     * If the event is being injected, injectorPid and injectorUid should specify the
     * If the event is being injected, injectorPid and injectorUid should specify the
     * process id and used id of the injecting application, otherwise they should both
     * process id and used id of the injecting application, otherwise they should both
     * be -1.
     * be -1.
     * Returns one of the INPUT_EVENT_INJECTION_XXX constants. */
     * Returns one of the INPUT_EVENT_INJECTION_XXX constants. */
    virtual int32_t getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
    virtual int32_t waitForKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
            int32_t injectorPid, int32_t injectorUid,
            int32_t injectorPid, int32_t injectorUid,
            Vector<InputTarget>& outTargets) = 0;
            Vector<InputTarget>& outTargets) = 0;


    /* Gets the input targets for a motion event.
    /* Waits for motion event targets to become available.
     * If the event is being injected, injectorPid and injectorUid should specify the
     * If the event is being injected, injectorPid and injectorUid should specify the
     * process id and used id of the injecting application, otherwise they should both
     * process id and used id of the injecting application, otherwise they should both
     * be -1.
     * be -1.
     * Returns one of the INPUT_EVENT_INJECTION_XXX constants. */
     * Returns one of the INPUT_EVENT_INJECTION_XXX constants. */
    virtual int32_t getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
    virtual int32_t waitForMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
            int32_t injectorPid, int32_t injectorUid,
            int32_t injectorPid, int32_t injectorUid,
            Vector<InputTarget>& outTargets) = 0;
            Vector<InputTarget>& outTargets) = 0;
};
};
@@ -186,6 +186,16 @@ public:
    virtual int32_t injectInputEvent(const InputEvent* event,
    virtual int32_t injectInputEvent(const InputEvent* event,
            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) = 0;
            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) = 0;


    /* Preempts input dispatch in progress by making pending synchronous
     * dispatches asynchronous instead.  This method is generally called during a focus
     * transition from one application to the next so as to enable the new application
     * to start receiving input as soon as possible without having to wait for the
     * old application to finish up.
     *
     * This method may be called on any thread (usually by the input manager).
     */
    virtual void preemptInputDispatch() = 0;

    /* Registers or unregister input channels that may be used as targets for input events.
    /* Registers or unregister input channels that may be used as targets for input events.
     *
     *
     * These methods may be called on any thread (usually by the input manager).
     * These methods may be called on any thread (usually by the input manager).
@@ -233,6 +243,8 @@ public:
    virtual int32_t injectInputEvent(const InputEvent* event,
    virtual int32_t injectInputEvent(const InputEvent* event,
            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis);
            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis);


    virtual void preemptInputDispatch();

    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel);
    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel);
    virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
    virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);


+10 −0
Original line number Original line Diff line number Diff line
@@ -87,6 +87,14 @@ public:
    virtual int32_t injectInputEvent(const InputEvent* event,
    virtual int32_t injectInputEvent(const InputEvent* event,
            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) = 0;
            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) = 0;


    /* Preempts input dispatch in progress by making pending synchronous
     * dispatches asynchronous instead.  This method is generally called during a focus
     * transition from one application to the next so as to enable the new application
     * to start receiving input as soon as possible without having to wait for the
     * old application to finish up.
     */
    virtual void preemptInputDispatch() = 0;

    /* Gets input device configuration. */
    /* Gets input device configuration. */
    virtual void getInputConfiguration(InputConfiguration* outConfiguration) const = 0;
    virtual void getInputConfiguration(InputConfiguration* outConfiguration) const = 0;


@@ -130,6 +138,8 @@ public:
    virtual int32_t injectInputEvent(const InputEvent* event,
    virtual int32_t injectInputEvent(const InputEvent* event,
            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis);
            int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis);


    virtual void preemptInputDispatch();

    virtual void getInputConfiguration(InputConfiguration* outConfiguration) const;
    virtual void getInputConfiguration(InputConfiguration* outConfiguration) const;
    virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses,
    virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses,
            int32_t scanCode) const;
            int32_t scanCode) const;
+5 −1
Original line number Original line Diff line number Diff line
@@ -361,7 +361,11 @@ public:


        // The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it
        // The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it
        // passes through the dispatch pipeline.
        // passes through the dispatch pipeline.
        ACTION_BRIGHT_HERE = 0x00000008
        ACTION_BRIGHT_HERE = 0x00000008,

        // The input dispatcher should add POLICY_FLAG_INTERCEPT_DISPATCH to the policy flags
        // it passed through the dispatch pipeline.
        ACTION_INTERCEPT_DISPATCH = 0x00000010
    };
    };


    /* Describes a virtual key. */
    /* Describes a virtual key. */
+63 −23
Original line number Original line Diff line number Diff line
@@ -8,25 +8,25 @@
//#define LOG_NDEBUG 0
//#define LOG_NDEBUG 0


// Log detailed debug messages about each inbound event notification to the dispatcher.
// Log detailed debug messages about each inbound event notification to the dispatcher.
#define DEBUG_INBOUND_EVENT_DETAILS 1
#define DEBUG_INBOUND_EVENT_DETAILS 0


// Log detailed debug messages about each outbound event processed by the dispatcher.
// Log detailed debug messages about each outbound event processed by the dispatcher.
#define DEBUG_OUTBOUND_EVENT_DETAILS 1
#define DEBUG_OUTBOUND_EVENT_DETAILS 0


// Log debug messages about batching.
// Log debug messages about batching.
#define DEBUG_BATCHING 1
#define DEBUG_BATCHING 0


// Log debug messages about the dispatch cycle.
// Log debug messages about the dispatch cycle.
#define DEBUG_DISPATCH_CYCLE 1
#define DEBUG_DISPATCH_CYCLE 0


// Log debug messages about registrations.
// Log debug messages about registrations.
#define DEBUG_REGISTRATION 1
#define DEBUG_REGISTRATION 0


// Log debug messages about performance statistics.
// Log debug messages about performance statistics.
#define DEBUG_PERFORMANCE_STATISTICS 1
#define DEBUG_PERFORMANCE_STATISTICS 0


// Log debug messages about input event injection.
// Log debug messages about input event injection.
#define DEBUG_INJECTION 1
#define DEBUG_INJECTION 0


#include <cutils/log.h>
#include <cutils/log.h>
#include <ui/InputDispatcher.h>
#include <ui/InputDispatcher.h>
@@ -249,9 +249,7 @@ void InputDispatcher::processKeyLockedInterruptible(
            entry->downTime);
            entry->downTime);
#endif
#endif


    // TODO: Poke user activity.
    if (entry->action == KEY_EVENT_ACTION_DOWN && ! entry->isInjected()) {

    if (entry->action == KEY_EVENT_ACTION_DOWN) {
        if (mKeyRepeatState.lastKeyEntry
        if (mKeyRepeatState.lastKeyEntry
                && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
                && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
            // We have seen two identical key downs in a row which indicates that the device
            // We have seen two identical key downs in a row which indicates that the device
@@ -277,14 +275,24 @@ void InputDispatcher::processKeyLockedInterruptible(


void InputDispatcher::processKeyRepeatLockedInterruptible(
void InputDispatcher::processKeyRepeatLockedInterruptible(
        nsecs_t currentTime, nsecs_t keyRepeatTimeout) {
        nsecs_t currentTime, nsecs_t keyRepeatTimeout) {
    // TODO Old WindowManagerServer code sniffs the input queue for following key up
    KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
    //      events and drops the repeat if one is found.  We should do something similar.

    //      One good place to do it is in notifyKey as soon as the key up enters the
    // Search the inbound queue for a key up corresponding to this device.
    //      inbound event queue.
    // It doesn't make sense to generate a key repeat event if the key is already up.
    for (EventEntry* queuedEntry = mInboundQueue.head.next;
            queuedEntry != & mInboundQueue.tail; queuedEntry = entry->next) {
        if (queuedEntry->type == EventEntry::TYPE_KEY) {
            KeyEntry* queuedKeyEntry = static_cast<KeyEntry*>(queuedEntry);
            if (queuedKeyEntry->deviceId == entry->deviceId
                    && entry->action == KEY_EVENT_ACTION_UP) {
                resetKeyRepeatLocked();
                return;
            }
        }
    }


    // Synthesize a key repeat after the repeat timeout expired.
    // Synthesize a key repeat after the repeat timeout expired.
    // We reuse the previous key entry if otherwise unreferenced.
    // Reuse the repeated key entry if it is otherwise unreferenced.
    KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
    uint32_t policyFlags = entry->policyFlags & POLICY_FLAG_RAW_MASK;
    uint32_t policyFlags = entry->policyFlags & POLICY_FLAG_RAW_MASK;
    if (entry->refCount == 1) {
    if (entry->refCount == 1) {
        entry->eventTime = currentTime;
        entry->eventTime = currentTime;
@@ -366,7 +374,7 @@ void InputDispatcher::identifyInputTargetsAndDispatchKeyLockedInterruptible(
            entry->downTime, entry->eventTime);
            entry->downTime, entry->eventTime);


    mCurrentInputTargets.clear();
    mCurrentInputTargets.clear();
    int32_t injectionResult = mPolicy->getKeyEventTargets(& mReusableKeyEvent,
    int32_t injectionResult = mPolicy->waitForKeyEventTargets(& mReusableKeyEvent,
            entry->policyFlags, entry->injectorPid, entry->injectorUid,
            entry->policyFlags, entry->injectorPid, entry->injectorUid,
            mCurrentInputTargets);
            mCurrentInputTargets);


@@ -375,8 +383,10 @@ void InputDispatcher::identifyInputTargetsAndDispatchKeyLockedInterruptible(


    setInjectionResultLocked(entry, injectionResult);
    setInjectionResultLocked(entry, injectionResult);


    if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED) {
        dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
        dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
    }
    }
}


void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(
void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(
        nsecs_t currentTime, MotionEntry* entry) {
        nsecs_t currentTime, MotionEntry* entry) {
@@ -395,7 +405,7 @@ void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(
            entry->firstSample.pointerCoords);
            entry->firstSample.pointerCoords);


    mCurrentInputTargets.clear();
    mCurrentInputTargets.clear();
    int32_t injectionResult = mPolicy->getMotionEventTargets(& mReusableMotionEvent,
    int32_t injectionResult = mPolicy->waitForMotionEventTargets(& mReusableMotionEvent,
            entry->policyFlags, entry->injectorPid, entry->injectorUid,
            entry->policyFlags, entry->injectorPid, entry->injectorUid,
            mCurrentInputTargets);
            mCurrentInputTargets);


@@ -404,8 +414,10 @@ void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(


    setInjectionResultLocked(entry, injectionResult);
    setInjectionResultLocked(entry, injectionResult);


    if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED) {
        dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
        dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
    }
    }
}


void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
        EventEntry* eventEntry, bool resumeWithAppendedMotionSample) {
        EventEntry* eventEntry, bool resumeWithAppendedMotionSample) {
@@ -1253,9 +1265,37 @@ void InputDispatcher::resetKeyRepeatLocked() {
    }
    }
}
}


void InputDispatcher::preemptInputDispatch() {
#if DEBUG_DISPATCH_CYCLE
    LOGD("preemptInputDispatch");
#endif

    bool preemptedOne = false;
    { // acquire lock
        AutoMutex _l(mLock);

        for (size_t i = 0; i < mActiveConnections.size(); i++) {
            Connection* connection = mActiveConnections[i];
            if (connection->hasPendingSyncTarget()) {
#if DEBUG_DISPATCH_CYCLE
                LOGD("channel '%s' ~ Preempted pending synchronous dispatch",
                        connection->getInputChannelName());
#endif
                connection->outboundQueue.tail.prev->targetFlags &= ~ InputTarget::FLAG_SYNC;
                preemptedOne = true;
            }
        }
    } // release lock

    if (preemptedOne) {
        // Wake up the poll loop so it can get a head start dispatching the next event.
        mPollLoop->wake();
    }
}

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
#if DEBUG_REGISTRATION
#if DEBUG_REGISTRATION
    LOGD("channel '%s' - Registered", inputChannel->getName().string());
    LOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().string());
#endif
#endif


    int receiveFd;
    int receiveFd;
@@ -1288,7 +1328,7 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan


status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
#if DEBUG_REGISTRATION
#if DEBUG_REGISTRATION
    LOGD("channel '%s' - Unregistered", inputChannel->getName().string());
    LOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string());
#endif
#endif


    int32_t receiveFd;
    int32_t receiveFd;
Loading