KeyEvent分发原理一——native层事件分发流程

事件的分发主要是两个类InputReader.cpp和InputDispatcher.cpp.

1.SystemService会启动两个线程:InputReaderThread和InputDispatcherThread,一个负责读取事件,一个负责分发事件

SystemServer.java

/**
     * Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
*/
private void startOtherServices(){
    inputManager = new InputManagerService(context);
    inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
    inputManager.start();
}

com_android_server_input_InputManagerService.cpp

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}

InputManager.cpp

InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}
void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }

    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputReader thread due to error %d.", result);

        mDispatcherThread->requestExit();
        return result;
    }

    return OK;
}

 

在创建InputDispatcher和InputReader的时候,请注意mReader = new InputReader(eventHub, readerPolicy, mDispatcher);InputDispacher是传递给了InputReader的,所以InputReader在读取事件后可以操作InputDispatcher用来分发事件,这个很重要,有助于理解之后如何分发事件,下面是时序图:

2.InputReader读取事件

InputManager会启动两个线程,一个是InputReaderThread,一个是InputDispatcherThread, InputReaderThread持有InputReader, InputDispatcherThread持有InputDispatcher, 同时InputReader持有InputDispatcher,这是三者之间的关系。

InputReaderThread一旦启动就会执行threadLoop()方法,从而执行InputReader的loopOnce()

bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}
void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    Vector<InputDeviceInfo> inputDevices;
    { // acquire lock
        AutoMutex _l(mLock);

        oldGeneration = mGeneration;
        timeoutMillis = -1;

        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) {
            mConfigurationChangesToRefresh = 0;
            timeoutMillis = 0;
            refreshConfigurationLocked(changes);
        } else if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
        }
    } // release lock

    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();

        if (count) {
            processEventsLocked(mEventBuffer, count);
        }

        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
                ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
                mNextTimeout = LLONG_MAX;
                timeoutExpiredLocked(now);
            }
        }

        if (oldGeneration != mGeneration) {
            inputDevicesChanged = true;
            getInputDevicesLocked(inputDevices);
        }
    } // release lock

    // Send out a message that the describes the changed input devices.
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }

    // Flush queued events out to the listener.
    // This must happen outside of the lock because the listener could potentially call
    // back into the InputReader's methods, such as getScanCodeState, or become blocked
    // on another thread similarly waiting to acquire the InputReader lock thereby
    // resulting in a deadlock.  This situation is actually quite plausible because the
    // listener is actually the input dispatcher, which calls into the window manager,
    // which occasionally calls into the input reader.
    mQueuedListener->flush();
}

threadLoop是Thread(C++语言)中的循环机制,如果没有调用requestExit会不断执行threadLoop中的代码,所以InputReaderThread是一个一直存在不断读取事件的线程。

size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE)

这行会将事件转变成可识别的Event, 如何工作的,不是本篇文章讨论的内容。mQueuedListener->flush();是将事件分发出去。那么mQueuedListener是什么呢?是InputListener一个实例

InputListener.h

/*
 * An implementation of the listener interface that queues up and defers dispatch
 * of decoded events until flushed.
 */
class QueuedInputListener : public InputListenerInterface {
protected:
    virtual ~QueuedInputListener();

public:
    QueuedInputListener(const sp<InputListenerInterface>& innerListener);

    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
    virtual void notifyKey(const NotifyKeyArgs* args);
    virtual void notifyMotion(const NotifyMotionArgs* args);
    virtual void notifySwitch(const NotifySwitchArgs* args);
    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);

    void flush();

private:
    sp<InputListenerInterface> mInnerListener;
    Vector<NotifyArgs*> mArgsQueue;
};

InputListener.cpp

void QueuedInputListener::flush() {
    size_t count = mArgsQueue.size();
    for (size_t i = 0; i < count; i++) {
        NotifyArgs* args = mArgsQueue[i];
        args->notify(mInnerListener);
        delete args;
    }
    mArgsQueue.clear();
}

从方法来看这个flush()会将mArgsQueue中的事件分发出去,那么事件又是什么时候加入到这个队列里面的呢?让我们再回到InputReader的loopOnce方法。在调用mQueuedListener->flush()之前会调用processEventsLocked,再调用processEventsForDeviceLocked,

void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    if (deviceIndex < 0) {
        ALOGW("Discarding event for unknown deviceId %d.", deviceId);
        return;
    }

    InputDevice* device = mDevices.valueAt(deviceIndex);
    if (device->isIgnored()) {
        //ALOGD("Discarding event for ignored deviceId %d.", deviceId);
        return;
    }

    device->process(rawEvents, count);
}

再看这个方法device->process, 这里的device是什么呢,以keyevent为例,就是InputReader中的KeyboardInputMapper,这个类的定义在InputReader.h中,最终会执行processKey。

void KeyboardInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
    case EV_KEY: {
        int32_t scanCode = rawEvent->code;
        int32_t usageCode = mCurrentHidUsage;
        mCurrentHidUsage = 0;

        if (isKeyboardOrGamepadKey(scanCode)) {
            processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
        }
        break;
    }
    case EV_MSC: {
        if (rawEvent->code == MSC_SCAN) {
            mCurrentHidUsage = rawEvent->value;
        }
        break;
    }
    case EV_SYN: {
        if (rawEvent->code == SYN_REPORT) {
            mCurrentHidUsage = 0;
        }
    }
    }
}
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
        int32_t usageCode) {
    int32_t keyCode;
    int32_t keyMetaState;
    uint32_t policyFlags;

    if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
                              &keyCode, &keyMetaState, &policyFlags)) {
        keyCode = AKEYCODE_UNKNOWN;
        keyMetaState = mMetaState;
        policyFlags = 0;
    }

    if (down) {
        // Rotate key codes according to orientation if needed.
        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
            keyCode = rotateKeyCode(keyCode, mOrientation);
        }

        // Add key down.
        ssize_t keyDownIndex = findKeyDown(scanCode);
        if (keyDownIndex >= 0) {
            // key repeat, be sure to use same keycode as before in case of rotation
            keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
        } else {
            // key down
            if ((policyFlags & POLICY_FLAG_VIRTUAL)
                    && mContext->shouldDropVirtualKey(when,
                            getDevice(), keyCode, scanCode)) {
                return;
            }
            if (policyFlags & POLICY_FLAG_GESTURE) {
                mDevice->cancelTouch(when);
            }

            mKeyDowns.push();
            KeyDown& keyDown = mKeyDowns.editTop();
            keyDown.keyCode = keyCode;
            keyDown.scanCode = scanCode;
        }

        mDownTime = when;
    } else {
        // Remove key down.
        ssize_t keyDownIndex = findKeyDown(scanCode);
        if (keyDownIndex >= 0) {
            // key up, be sure to use same keycode as before in case of rotation
            keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
            mKeyDowns.removeAt(size_t(keyDownIndex));
        } else {
            // key was not actually down
            ALOGI("Dropping key up from device %s because the key was not down.  "
                    "keyCode=%d, scanCode=%d",
                    getDeviceName().string(), keyCode, scanCode);
            return;
        }
    }

    int32_t oldMetaState = mMetaState;
    int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);
    bool metaStateChanged = oldMetaState != newMetaState;
    if (metaStateChanged) {
        mMetaState = newMetaState;
        updateLedState(false);

        // If global meta state changed send it along with the key.
        // If it has not changed then we'll use what keymap gave us,
        // since key replacement logic might temporarily reset a few
        // meta bits for given key.
        keyMetaState = newMetaState;
    }

    nsecs_t downTime = mDownTime;

    // Key down on external an keyboard should wake the device.
    // We don't do this for internal keyboards to prevent them from waking up in your pocket.
    // For internal keyboards, the key layout file should specify the policy flags for
    // each wake key individually.
    // TODO: Use the input device configuration to control this behavior more finely.
    if (down && getDevice()->isExternal()) {
        policyFlags |= POLICY_FLAG_WAKE;
    }

    if (mParameters.handlesKeyRepeat) {
        policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
    }

    if (metaStateChanged) {
        getContext()->updateGlobalMetaState();
    }

    if (down && !isMetaKey(keyCode)) {
        getContext()->fadePointer();
    }

    NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
    getListener()->notifyKey(&args);
}

方法中最后一行getListener()->notifyKey,就是将事件放到InputListener的队列里,再看看InputListener的notifyKey

InputListener.cpp

void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
    mArgsQueue.push(new NotifyKeyArgs(*args));
}

到目前为止,事件已读取完毕,在InputReader中调用了InputListener.flush就会分发事件

3.InputDispatch分发事件

 我们再来看看flush这个方法

void QueuedInputListener::flush() {
    size_t count = mArgsQueue.size();
    for (size_t i = 0; i < count; i++) {
        NotifyArgs* args = mArgsQueue[i];
        args->notify(mInnerListener);
        delete args;
    }
    mArgsQueue.clear();
}

这里有两个疑问:一个是notify方法的函数体在哪里?二是mInnerListener是什么?要想找到答案我们得找到mQueuedListener初始化的地方,回到InputReader,在构造方法里面初始化了mQueuedListener

InputReader::InputReader(const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& policy,
        const sp<InputListenerInterface>& listener) :
        mContext(this), mEventHub(eventHub), mPolicy(policy),
        mGlobalMetaState(0), mGeneration(1),
        mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) {
    mQueuedListener = new QueuedInputListener(listener);

    { // acquire lock
        AutoMutex _l(mLock);

        refreshConfigurationLocked(0);
        updateGlobalMetaStateLocked();
    } // release lock
}

在初始化mQueuedListener时,传入了一个listener,并把这个listener赋值给了mInnerListener

QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
        mInnerListener(innerListener) {
}

而这个listener又是什么呢?从第一页InputManager构造里面来看,这个listener就是InputDispatch.

InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}

第二个问题解决了,notify的函数体就在InputListener中

void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyKey(this);
}

其实就是设用了InputDispatch中的notifyKey, 终于走到InputDispatch了,这里是真正处理事件分发的地方,看一下notifyKey都做了哪些事情

 1 void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
 2 #if DEBUG_INBOUND_EVENT_DETAILS
 3     ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
 4             "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
 5             args->eventTime, args->deviceId, args->source, args->policyFlags,
 6             args->action, args->flags, args->keyCode, args->scanCode,
 7             args->metaState, args->downTime);
 8 #endif
 9     if (!validateKeyEvent(args->action)) {
10         return;
11     }
12 
13     uint32_t policyFlags = args->policyFlags;
14     int32_t flags = args->flags;
15     int32_t metaState = args->metaState;
16     if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
17         policyFlags |= POLICY_FLAG_VIRTUAL;
18         flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
19     }
20     if (policyFlags & POLICY_FLAG_FUNCTION) {
21         metaState |= AMETA_FUNCTION_ON;
22     }
23 
24     policyFlags |= POLICY_FLAG_TRUSTED;
25 
26     int32_t keyCode = args->keyCode;
27     if (metaState & AMETA_META_ON && args->action == AKEY_EVENT_ACTION_DOWN) {
28         int32_t newKeyCode = AKEYCODE_UNKNOWN;
29         if (keyCode == AKEYCODE_DEL) {
30             newKeyCode = AKEYCODE_BACK;
31         } else if (keyCode == AKEYCODE_ENTER) {
32             newKeyCode = AKEYCODE_HOME;
33         }
34         if (newKeyCode != AKEYCODE_UNKNOWN) {
35             AutoMutex _l(mLock);
36             struct KeyReplacement replacement = {keyCode, args->deviceId};
37             mReplacedKeys.add(replacement, newKeyCode);
38             keyCode = newKeyCode;
39             metaState &= ~AMETA_META_ON;
40         }
41     } else if (args->action == AKEY_EVENT_ACTION_UP) {
42         // In order to maintain a consistent stream of up and down events, check to see if the key
43         // going up is one we've replaced in a down event and haven't yet replaced in an up event,
44         // even if the modifier was released between the down and the up events.
45         AutoMutex _l(mLock);
46         struct KeyReplacement replacement = {keyCode, args->deviceId};
47         ssize_t index = mReplacedKeys.indexOfKey(replacement);
48         if (index >= 0) {
49             keyCode = mReplacedKeys.valueAt(index);
50             mReplacedKeys.removeItemsAt(index);
51             metaState &= ~AMETA_META_ON;
52         }
53     }
54 
55     KeyEvent event;
56     event.initialize(args->deviceId, args->source, args->action,
57             flags, keyCode, args->scanCode, metaState, 0,
58             args->downTime, args->eventTime);
59 
60     mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
61 
62     bool needWake;
63     { // acquire lock
64         mLock.lock();
65 
66         if (shouldSendKeyToInputFilterLocked(args)) {
67             mLock.unlock();
68 
69             policyFlags |= POLICY_FLAG_FILTERED;
70             if (!mPolicy->filterInputEvent(&event, policyFlags)) {
71                 return; // event was consumed by the filter
72             }
73 
74             mLock.lock();
75         }
76 
77         int32_t repeatCount = 0;
78         KeyEntry* newEntry = new KeyEntry(args->eventTime,
79                 args->deviceId, args->source, policyFlags,
80                 args->action, flags, keyCode, args->scanCode,
81                 metaState, repeatCount, args->downTime);
82 
83         needWake = enqueueInboundEventLocked(newEntry);
84         mLock.unlock();
85     } // release lock
86 
87     if (needWake) {
88         mLooper->wake();
89     }
90 }

首先它会把事件包装成KeyEntry,再把keyentry放到队列里,再唤醒InputDispatchThread.同样的, InputDispatchThread也会执行theadLoop再执行dispatchOnce, 会不断的从队列里面拿事件分发出去。再看看InputDispatchThread中的ldispatch是怎么做的。

 1 void InputDispatcher::dispatchOnce() {
 2     nsecs_t nextWakeupTime = LONG_LONG_MAX;
 3     { // acquire lock
 4         AutoMutex _l(mLock);
 5         mDispatcherIsAliveCondition.broadcast();
 6 
 7         // Run a dispatch loop if there are no pending commands.
 8         // The dispatch loop might enqueue commands to run afterwards.
 9         if (!haveCommandsLocked()) {
10             dispatchOnceInnerLocked(&nextWakeupTime);
11         }
12 
13         // Run all pending commands if there are any.
14         // If any commands were run then force the next poll to wake up immediately.
15         if (runCommandsLockedInterruptible()) {
16             nextWakeupTime = LONG_LONG_MIN;
17         }
18     } // release lock
19 
20     // Wait for callback or timeout or wake.  (make sure we round up, not down)
21     nsecs_t currentTime = now();
22     int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
23     mLooper->pollOnce(timeoutMillis);
24 }

从方法dispatchOnceInnerLocked走到dispatchKeyLocked,再走到dispatchEventLocked,再走到prepareDispatchCycleLocked,还有许多方法,但最终走到startDispatchCycleLocked

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection) {
#if DEBUG_DISPATCH_CYCLE
    ALOGD("channel '%s' ~ startDispatchCycle",
            connection->getInputChannelName());
#endif

    while (connection->status == Connection::STATUS_NORMAL
            && !connection->outboundQueue.isEmpty()) {
        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
        dispatchEntry->deliveryTime = currentTime;

        // Publish the event.
        status_t status;
        EventEntry* eventEntry = dispatchEntry->eventEntry;
        switch (eventEntry->type) {
        case EventEntry::TYPE_KEY: {
            KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);

            // Publish the key event.
            status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
                    keyEntry->deviceId, keyEntry->source,
                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
                    keyEntry->keyCode, keyEntry->scanCode,
                    keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
                    keyEntry->eventTime);
            break;
        }

        case EventEntry::TYPE_MOTION: {
            MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);

            PointerCoords scaledCoords[MAX_POINTERS];
            const PointerCoords* usingCoords = motionEntry->pointerCoords;

            // Set the X and Y offset depending on the input source.
            float xOffset, yOffset, scaleFactor;
            if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                    && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
                scaleFactor = dispatchEntry->scaleFactor;
                xOffset = dispatchEntry->xOffset * scaleFactor;
                yOffset = dispatchEntry->yOffset * scaleFactor;
                if (scaleFactor != 1.0f) {
                    for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                        scaledCoords[i] = motionEntry->pointerCoords[i];
                        scaledCoords[i].scale(scaleFactor);
                    }
                    usingCoords = scaledCoords;
                }
            } else {
                xOffset = 0.0f;
                yOffset = 0.0f;
                scaleFactor = 1.0f;

                // We don't want the dispatch target to know.
                if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
                    for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                        scaledCoords[i].clear();
                    }
                    usingCoords = scaledCoords;
                }
            }

            // Publish the motion event.
            status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
                    motionEntry->deviceId, motionEntry->source,
                    dispatchEntry->resolvedAction, motionEntry->actionButton,
                    dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
                    motionEntry->metaState, motionEntry->buttonState,
                    xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
                    motionEntry->downTime, motionEntry->eventTime,
                    motionEntry->pointerCount, motionEntry->pointerProperties,
                    usingCoords, dispatchEntry->inThumbMode, scaleFactor);
            break;
        }

        default:
            ALOG_ASSERT(false);
            return;
        }

        // Check the result.
        if (status) {
            if (status == WOULD_BLOCK) {
                if (connection->waitQueue.isEmpty()) {
                    ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
                            "This is unexpected because the wait queue is empty, so the pipe "
                            "should be empty and we shouldn't have any problems writing an "
                            "event to it, status=%d", connection->getInputChannelName(), status);
                    abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
                } else {
                    // Pipe is full and we are waiting for the app to finish process some events
                    // before sending more events to it.
#if DEBUG_DISPATCH_CYCLE
                    ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
                            "waiting for the application to catch up",
                            connection->getInputChannelName());
#endif
                    connection->inputPublisherBlocked = true;
                }
            } else {
                ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
                        "status=%d", connection->getInputChannelName(), status);
                abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
            }
            return;
        }

        // Re-enqueue the event on the wait queue.
        connection->outboundQueue.dequeue(dispatchEntry);
        traceOutboundQueueLengthLocked(connection);
        connection->waitQueue.enqueueAtTail(dispatchEntry);
        traceWaitQueueLengthLocked(connection);
    }
}

 

看TYPE_KEY分支,最后是通过publicKeyEvent方法将事件分发出去的。那么这里的inputPublisher是会呢,这个是InputTransport

status_t InputPublisher::publishKeyEvent(
        uint32_t seq,
        int32_t deviceId,
        int32_t source,
        int32_t action,
        int32_t flags,
        int32_t keyCode,
        int32_t scanCode,
        int32_t metaState,
        int32_t repeatCount,
        nsecs_t downTime,
        nsecs_t eventTime) {
#if DEBUG_TRANSPORT_ACTIONS
    ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
            "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
            "downTime=%lld, eventTime=%lld",
            mChannel->getName().string(), seq,
            deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
            downTime, eventTime);
#endif

    if (!seq) {
        ALOGE("Attempted to publish a key event with sequence number 0.");
        return BAD_VALUE;
    }

    InputMessage msg;
    msg.header.type = InputMessage::TYPE_KEY;
    msg.body.key.seq = seq;
    msg.body.key.deviceId = deviceId;
    msg.body.key.source = source;
    msg.body.key.action = action;
    msg.body.key.flags = flags;
    msg.body.key.keyCode = keyCode;
    msg.body.key.scanCode = scanCode;
    msg.body.key.metaState = metaState;
    msg.body.key.repeatCount = repeatCount;
    msg.body.key.downTime = downTime;
    msg.body.key.eventTime = eventTime;
    return mChannel->sendMessage(&msg);
}
status_t InputChannel::sendMessage(const InputMessage* msg) {
    size_t msgLength = msg->size();
    ssize_t nWrite;
    do {
        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);

  

最终是通过调用了linux的多进程通信的方式将事件发送给主线程中的view, 这个机制不在本章讨论范围内,大概的实现就是要建立两个channel, 用来通信,我们这里的inputdispatch相当于一个channel用来分发事件,还有一个通来接收,在android_view_InputEventReceiver.cpp中。

4.Java层接受事件消息

我们先从Java层建立接收的receiver开始,在ViewRootImpl的setView方法中会看建立 InputChannel和WindowInputEventReceiver

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
				......

                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                requestLayout();
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    mInputChannel = new InputChannel();
                }
                ......
                if (mInputChannel != null) {
                    if (mInputQueueCallback != null) {
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());
                }
                ......
                InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                        "aq:native-post-ime:" + counterSuffix);
                InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
                InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                        "aq:ime:" + counterSuffix);
                InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
                InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                        "aq:native-pre-ime:" + counterSuffix);
            }
        }
    }

 

WindowInputEventReceiver是继承自InputEventReceiver,我们直接看InputEventReceiver在nativie层的实现,android_view_InputEventReceiver.cpp,这里有个addFd的机制,这个会不断的回调handleEvent,这人机制在以下文章有说明

https://segmentfault.com/a/1190000012860933

在向上走到java层最后调用的方法是android_view_InputEventReceiver中consumeEvents

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
		......
    for (;;) {
        uint32_t seq;
        InputEvent* inputEvent;
        status_t status = mInputConsumer.consume(&mInputEventFactory,
                consumeBatches, frameTime, &seq, &inputEvent);
		......

            if (inputEventObj) {
                if (kDebugDispatchCycle) {
                    ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName().c_str());
                }
                env->CallVoidMethod(receiverObj.get(),
                        gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
                if (env->ExceptionCheck()) {
                    ALOGE("Exception dispatching input event.");
                    skipCallbacks = true;
                }
                env->DeleteLocalRef(inputEventObj);
            } else {
                ALOGW("channel '%s' ~ Failed to obtain event object.",
                        getInputChannelName().c_str());
                skipCallbacks = true;
            }
        }
		......
    }
}

 

其中mInputConsumer.consume还是在InputTransport.cpp中

status_t InputConsumer::consume(InputEventFactoryInterface* factory,
        bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
    ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld",
            mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime);
#endif

    *outSeq = 0;
    *outEvent = NULL;

    // Fetch the next input message.
    // Loop until an event can be returned or no additional events are received.
    while (!*outEvent) {
        if (mMsgDeferred) {
            // mMsg contains a valid input message from the previous call to consume
            // that has not yet been processed.
            mMsgDeferred = false;
        } else {
            // Receive a fresh message.
            status_t result = mChannel->receiveMessage(&mMsg);
            if (result) {
                // Consume the next batched event unless batches are being held for later.
                if (consumeBatches || result != WOULD_BLOCK) {
                    result = consumeBatch(factory, frameTime, outSeq, outEvent);
                    if (*outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
                        ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
                                mChannel->getName().string(), *outSeq);
#endif
                        break;
                    }
                }
                return result;
            }
        }
......
}

  

会从InputChannelmChannel->receiveMessage(&mMsg);获取从linux传过来的事件消息,然后再调用env->CallVoidMethod(receiverObj.get(),gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj)(android_view_InputEventReceiver.cpp);回调给InputEventReceiver

InputEventReceiver.java

 // Called from native code.
    @SuppressWarnings("unused")
    @UnsupportedAppUsage
    private void dispatchInputEvent(int seq, InputEvent event) {
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event);
    }

 

至此,java层就收到事件消息,以下是涉及的所有类

 

 

 

 

 

 

 

 

 
posted @ 2021-04-05 20:50  雪舞~  阅读(758)  评论(0)    收藏  举报