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进行连接。

你可能感兴趣的:(Android中InputManagerService里的InputReader和inputDispatcher)