Android中InputManagerService里的InputReader和inputDispatcher

    最近工作中遇到InputManagerService相关的问题,所以将InputReader和InputDispatcher看了一遍,水平有限,有的也没有理解。

    这是input的中重要的两个类,这两个类由对应的两个线程来管理InputReaderThread和InputDispatcherThread,他们都是使用C++实现的。 首先简单介绍下InputManagerService的实现。

InputReaderThread    InputDispatcherThread    Binder(InputManagerService)…    Proxy…

负责从/dev/input/下读取输入事件,之后将input_event进入队列,

通知inputDispatcherThread 处理    得到输入事件后,根据当前inputChannel情况,进行发送    负责对InputReader和InputDispatcher的管理, 提供接口供其他进程访问,如插入一个输入事件,注册一个inputChannel灯    外部调用,如果input作为一个模块的话,这个接口是真正对外开放的

1 俩线程的启动

   JAVA: InputManagerService.nativeInt () ->C++:NativeInputManager()->C++:InputManager()->C++:InputManager->initialize():如下代码所示:

48:void InputManager::initialize() {

49:    mReaderThread = new InputReaderThread(mReader);

50:    mDispatcherThread = new InputDispatcherThread(mDispatcher);

51:}

注意在本文之后inputReaderThread简称R线程,inputDispatcherThread简称D线程。

2 InputReader的执行

   重要的函数:InputReader->loopOnce();,R线程是不断地在这个函数里循环。下面就看这个函数做了什么,首先介绍几个不重要的成员变量:

mGeneration:这个变量是标识输入设备的变化的,也就是说当设备新建,添加,删除时就会执行loopOnce()中的这段代码:

        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);

    }

 

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

 

当调用这个函数时,如果有事件发生,count>0, 事件存储在mEventBuffer中。

mEventBuffer:这是存储时间的缓冲。

下面就是重要级的函数,对事件的处理processEventsLocked(mEventBuffer, count);

processEventsLocked->processEventsForDeviceLocked->device->process(rawEvents, count)->mapper->process(rawEvent);

mDevices: 每个输入设备的对象,每个输入设备对应一个process去处理它自己的事件。

    mMappers:每个输入设备可能对应不同输入类型,这就需要要mMappers去处理,在mMapers->process中通过notify机制去通知D线程处理输入。

3 InputDispatcher:

     InputDispatcher->dispatchOnce()->dispatchOnceInnerLocked:

   mPendingEvent:当前需要处理的的事件,如果没有就从mInboundQueue中取。

   mInboundQueue:InputDispatcher的事件队列,R线程负责进队列,D进程出队列处理事件。

   mTouchState: 表示当前时间处理的状态。

    当mPendingEvent的事件需要派发时,如下代码所示:

switch (mPendingEvent->type) {

    case EventEntry::TYPE_CONFIGURATION_CHANGED: {

        ConfigurationChangedEntry* typedEntry =

                static_cast<ConfigurationChangedEntry*>(mPendingEvent);

        done = dispatchConfigurationChangedLocked(currentTime, typedEntry);

        dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped

        break;

    }

    case EventEntry::TYPE_DEVICE_RESET: {

        DeviceResetEntry* typedEntry =

                static_cast<DeviceResetEntry*>(mPendingEvent);

        done = dispatchDeviceResetLocked(currentTime, typedEntry);

        dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped

        break;

    }

    case EventEntry::TYPE_KEY: {

        KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);

        if (isAppSwitchDue) {

            if (isAppSwitchKeyEventLocked(typedEntry)) {

                resetPendingAppSwitchLocked(true);

                isAppSwitchDue = false;

            } else if (dropReason == DROP_REASON_NOT_DROPPED) {

                dropReason = DROP_REASON_APP_SWITCH;

            }

        }

        if (dropReason == DROP_REASON_NOT_DROPPED

                && isStaleEventLocked(currentTime, typedEntry)) {

            dropReason = DROP_REASON_STALE;

        }

        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {

            dropReason = DROP_REASON_BLOCKED;

        }

        done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);

        break;

    }

    case EventEntry::TYPE_MOTION: {

        MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);

        if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {

            dropReason = DROP_REASON_APP_SWITCH;

        }

        if (dropReason == DROP_REASON_NOT_DROPPED

                && isStaleEventLocked(currentTime, typedEntry)) {

            dropReason = DROP_REASON_STALE;

        }

        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {

            dropReason = DROP_REASON_BLOCKED;

        }

        done = dispatchMotionLocked(currentTime, typedEntry,

                &dropReason, nextWakeupTime);

        break;

    }

    default:

        ALOG_ASSERT(false);

        break;

    }

    if (done) {

        if (dropReason != DROP_REASON_NOT_DROPPED) {

            dropInboundEventLocked(mPendingEvent, dropReason);

        }

        releasePendingEventLocked();

        *nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately

    }

}

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {

    bool needWake = mInboundQueue.isEmpty();

    mInboundQueue.enqueueAtTail(entry);

    traceInboundQueueLengthLocked();

    switch (entry->type) {

    case EventEntry::TYPE_KEY: {

        // Optimize app switch latency.

        // If the application takes too long to catch up then we drop all events preceding

        // the app switch key.

        KeyEntry* keyEntry = static_cast<KeyEntry*>(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

                    ALOGD(“App switch is pending!”);

#endif

                    mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;

                    mAppSwitchSawKeyDown = false;

                    needWake = true;

                }

            }

        }

        break;

    }

    case EventEntry::TYPE_MOTION: {

        // Optimize case where the current application is unresponsive and the user

        // decides to touch a window in a different application.

        // If the application takes too long to catch up then we drop all events preceding

        // the touch into the other window.

        MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);

        if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN

                && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)

                && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY

                && mInputTargetWaitApplicationHandle != NULL) {

            int32_t x = int32_t(motionEntry->pointerCoords[0].

                    getAxisValue(AMOTION_EVENT_AXIS_X));

            int32_t y = int32_t(motionEntry->pointerCoords[0].

                    getAxisValue(AMOTION_EVENT_AXIS_Y));

            sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(x, y);

            if (touchedWindowHandle != NULL

                    && touchedWindowHandle->inputApplicationHandle

                            != mInputTargetWaitApplicationHandle) {

                // User touched a different application than the one we are waiting on.

                // Flag the event, and start pruning the input queue.

                mNextUnblockedEvent = motionEntry;

                needWake = true;

            }

        }

        break;

    }

这些是处理事件的核心,我们就拿TYPE_MOTION举例,

dispatchMotionLocked->

                      findTouchedWindowTargetsLocked //填充inputTargets,是否有touchedWindowTarget需要事件

                      addMonitoringTargetsLocked //加入monitoringTarget

                      dispatchEventLocked -> //对inputTarget中的每个window进行派发事件

                                          prepareDispatchCycleLocked->

                                                                                                                                            enqueueDispatchEntriesLocked->

                                                                                                                                                                                                        connection->outboundQueue.enqueueAtTail(dispatchEntry);

 dispatchMotionLocked还是蛮复杂的,很多地方我也没弄明白。看代码话说windowmanagerService通过setInputWindows去填充InputDispacther的mWindowHandles,这是和所有window交流的根源,之后InputDispatcher填充inputTarget, 创建mConntionFd, 与需要input的window进行连接。

    原文作者:vastyh
    原文地址: https://blog.csdn.net/vastyh/article/details/8902162
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞