Android 输入系统之InputDispatcher篇

原创 2015年11月19日 17:13:03

InputDispatcher.cpp位置:framework/base/service/input/InputDispatcher.cpp

上一篇文章分析到args->notify(mInnerListener);

我们只分析key event类型

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

考虑到前面分析有点快,后面我会分析得更详细。

这里会调用InputDispatcher的notifyKey()函数。

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
    ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
            "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
            args->eventTime, args->deviceId, args->source, args->policyFlags,
            args->action, args->flags, args->keyCode, args->scanCode,
            args->metaState, args->downTime);
#endif

//如果不是down或者up事件,则判定为非法事件,不处理
    if (!validateKeyEvent(args->action)) {
        return;
    }


    uint32_t policyFlags = args->policyFlags;
    int32_t flags = args->flags;
    int32_t metaState = args->metaState;
    if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
        policyFlags |= POLICY_FLAG_VIRTUAL;
        flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
    }
    if (policyFlags & POLICY_FLAG_ALT) {
        metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON;
    }
    if (policyFlags & POLICY_FLAG_ALT_GR) {
        metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON;
    }
    if (policyFlags & POLICY_FLAG_SHIFT) {
        metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON;
    }
    if (policyFlags & POLICY_FLAG_CAPS_LOCK) {
        metaState |= AMETA_CAPS_LOCK_ON;
    }
    if (policyFlags & POLICY_FLAG_FUNCTION) {
        metaState |= AMETA_FUNCTION_ON;
    }

//从InputReader过来的事件加上POLICY_FLAG_TRUSTED标记
    policyFlags |= POLICY_FLAG_TRUSTED;
    KeyEvent event;

//将NotifyKeyArgs转换为KeyEvent 
    event.initialize(args->deviceId, args->source, args->action,
            flags, args->keyCode, args->scanCode, metaState, 0,
            args->downTime, args->eventTime);

//这个函数很重要,待会重点分析
    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
    if (policyFlags & POLICY_FLAG_WOKE_HERE) {
        flags |= AKEY_EVENT_FLAG_WOKE_HERE;
    }
    bool needWake;
    { // acquire lock
        mLock.lock();
        if (shouldSendKeyToInputFilterLocked(args)) {
            mLock.unlock();
            policyFlags |= POLICY_FLAG_FILTERED;
            if (!mPolicy->filterInputEvent(&event, policyFlags)) {
                return; // event was consumed by the filter
            }
            mLock.lock();
        }
        int32_t repeatCount = 0;
        KeyEntry* newEntry = new KeyEntry(args->eventTime,
                args->deviceId, args->source, policyFlags,
                args->action, flags, args->keyCode, args->scanCode,
                metaState, repeatCount, args->downTime);

//将newEntry即本次keyevent送到队列中
        needWake = enqueueInboundEventLocked(newEntry);
        mLock.unlock();
    } // release lock
    if (needWake) {

//如果需要唤醒mLooper则马上唤醒,唤醒后事件将立马进行分发
        mLooper->wake();
    }
}

基本上都做了注释,比较简单,我们重点看看mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);

这是个native函数,其实现在com_android_server_input_InputManagerService.cpp中

void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
        uint32_t& policyFlags) {

    // Policy:
    // - Ignore untrusted events and pass them along.
    // - Ask the window manager what to do with normal events and trusted injected events.
    // - For normal events wake and brighten the screen if currently off or dim.
    if ((policyFlags & POLICY_FLAG_TRUSTED)) {//前面说了,从inputreader过来的都会加上POLICY_FLAG_TRUSTED标记
        /// M:[SmartBook] Wake up SmartBook's screen @{
        if (gSmartBookPlugIn && !isSbScreenOn()) {
            ALOGD("Wake up SmartBook screen by key event");
            android_server_PowerManagerService_sbScreenControl(2,0);
            return;
        }
        /// @}
        nsecs_t when = keyEvent->getEventTime();
        bool isScreenOn = this->isScreenOn();
        bool isScreenBright = this->isScreenBright();
        JNIEnv* env = jniEnv();
        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
        jint wmActions;
        if (keyEventObj) {

//通过jni调用Java层的interceptKeyBeforeQueueing,其实现位于InputMonitor.java,然后又会调用PhoneWindowManager.java中的同名函数,这里的返回值wmActions非常重要,它将决定一部分事件的处理逻辑以及是否有必要有继续分发
            wmActions = env->CallIntMethod(mServiceObj,
                    gServiceClassInfo.interceptKeyBeforeQueueing,
                    keyEventObj, policyFlags, isScreenOn);
//异常处理
            if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
                wmActions = 0;
            }
            android_view_KeyEvent_recycle(env, keyEventObj);
            env->DeleteLocalRef(keyEventObj);
        } else {
            ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
            wmActions = 0;
        }

        if (!(policyFlags & POLICY_FLAG_INJECTED)) {
            if (!isScreenOn) {
                policyFlags |= POLICY_FLAG_WOKE_HERE;
            }

            if (!isScreenBright) {
                policyFlags |= POLICY_FLAG_BRIGHT_HERE;
            }
        }

        /// M: Power key UI monitor @{
        int powerKeyCode = KEYCODE_POWER;
        int keyDown = KEYEVENT_DOWN;
        int keyUp = KEYEVENT_UP;
        if (isScreenOn) {
            if (keyEvent->getKeyCode() == powerKeyCode) {
                if (keyEvent->getAction() == keyDown) {
                    ALOGD("Now is screen on, power down pressed: Disable monitor");
                    aee_ioctl_wdt_kick(WDT_SETBY_WMS_DISABLE_PWK_MONITOR);
                } else if (keyEvent->getAction() == keyUp && 
                        (wmActions & WM_ACTION_GO_TO_SLEEP)) {
                    ALOGD("Now is screen on, power up pressed and go suspend: Enable monitor");
                    aee_ioctl_wdt_kick(WDT_SETBY_WMS_ENABLE_PWK_MONITOR);
                }
            }
        }
        /// @}

        handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
    } else {
        policyFlags |= POLICY_FLAG_PASS_TO_USER;
    }
}

interceptKeyBeforeQueueing这个函数名字取得非常的恰到好处,就如其名字一样,执行完这个函数key event就立马被送入到了分发队列中,各位感兴趣的可以自行分析PhoneWindowManager.java的同名函数,其会对一些系统按键,比如volume+,volume-,power,endcall,media等按键进行处理,这些按键按键中的部分是不需要经过分发就可以执行对应功能的,同时也不会被ANR阻塞。

接下来我们看看handleInterceptActions(wmActions, when, /*byref*/ policyFlags);

void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
        uint32_t& policyFlags) {
    if (wmActions & WM_ACTION_GO_TO_SLEEP) {
#if DEBUG_INPUT_DISPATCHER_POLICY
        ALOGD("handleInterceptActions: Going to sleep.");
#endif
        android_server_PowerManagerService_goToSleep(when);
    }

    if (wmActions & WM_ACTION_WAKE_UP) {
#if DEBUG_INPUT_DISPATCHER_POLICY
        ALOGD("handleInterceptActions: Waking up.");
#endif
        android_server_PowerManagerService_wakeUp(when);
    }

    if (wmActions & WM_ACTION_PASS_TO_USER) {
        policyFlags |= POLICY_FLAG_PASS_TO_USER;
    } else {
#if DEBUG_INPUT_DISPATCHER_POLICY
        ALOGD("handleInterceptActions: Not passing key to user.");
#endif
    }
}

这个函数非常简单,根据返回值wmActions进行唤醒或者休眠操作,或者添加POLICY_FLAG_PASS_TO_USER标志,值得一提的是,wake up&sleep操作是通过JNI调用PMS相关函数实现的,不知道这么多JNI调来调去对性能有多少影响。

从这里可以看出,想要某个key具备唤醒或者休眠设备的操作实在太简单,只需要将返回值wmActions置位WM_ACTION_PASS_TO_USER或者WM_ACTION_WAKE_UP即可。

接下来我们看看enqueueInboundEventLocked(newEntry)实现

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {

//如果之前队列处于空置状态,则需要唤醒,否则分发线程的Looper肯定是处于工作中,无需再次唤醒
    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 displayId = motionEntry->displayId;
            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(displayId, 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;
    }
    }
    return needWake;
}

放入队列后分析就结束了,接下来我们看看分发线程是如何分发事件的

前面我们说过,C++层的Thread开启后会一直执行threadLoop()直到其返回false。

bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;
}

和InputReaderThread一样,一旦开启便永远不会结束

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        AutoMutex _l(mLock);
        mDispatcherIsAliveCondition.broadcast();
        // Run a dispatch loop if there are no pending commands.
        // The dispatch loop might enqueue commands to run afterwards.
        if (!haveCommandsLocked()) {
            dispatchOnceInnerLocked(&nextWakeupTime);
        }

        // Run all pending commands if there are any.
        // If any commands were run then force the next poll to wake up immediately.
        if (runCommandsLockedInterruptible()) {
            nextWakeupTime = LONG_LONG_MIN;
        }
    } // release lock

    // Wait for callback or timeout or wake.  (make sure we round up, not down)
    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis);
}

顺便提一下,mLooper->pollOnce实质上是个epoll_wait,这里有两种方法唤醒mLooper,一是前面提到的mLooper->wake(),二是nextWakeupTime时间到达后,这里的nextWakeupTime很有意思,设置成LONG_LONG_MAX即为永远休眠,设置成LONG_LONG_MIN则为立马唤醒。

真正分发函数是dispatchOnceInnerLocked(&nextWakeupTime);

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now();

    // Reset the key repeat timer whenever we disallow key events, even if the next event
    // is not a key.  This is to ensure that we abort a key repeat if the device is just coming
    // out of sleep.

//是否允许生成key repeat事件
    if (!mPolicy->isKeyRepeatEnabled()) {
        resetKeyRepeatLocked();
    }

    // If dispatching is frozen, do not process timeouts or try to deliver any new events.

//如果InputDispatcher处于冻结状态,则不予分发事件
    if (mDispatchFrozen) {
#if DEBUG_FOCUS
        ALOGD("Dispatch frozen.  Waiting some more.");
#endif
        return;
    }


    // Optimize latency of app switches.
    // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
    // been pressed.  When it expires, we preempt dispatch and drop all other pending events.

//为了保证HOME按键不受ANR影响的一种处理机制
    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
    if (mAppSwitchDueTime < *nextWakeupTime) {
        *nextWakeupTime = mAppSwitchDueTime;
    }

    // Ready to start a new event.
    // If we don't already have a pending event, go grab one.

    if (! mPendingEvent) {

//如果事件队列为空
        if (mInboundQueue.isEmpty()) {
            if (isAppSwitchDue) {
                // The inbound queue is empty so the app switch key we were waiting
                // for will never arrive.  Stop waiting for it.
                resetPendingAppSwitchLocked(false);
                isAppSwitchDue = false;
            }


            // Synthesize a key repeat if appropriate.


            if (mKeyRepeatState.lastKeyEntry) {
                if (currentTime >= mKeyRepeatState.nextRepeatTime) {

//生成key repeat
                    mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
                } else {
                    if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {

//将生成的key repeat进行分发
                        *nextWakeupTime = mKeyRepeatState.nextRepeatTime;
                    }
                }
            }

            // Nothing to do if there is no pending event.
            if (!mPendingEvent) {
                return;
            }
        } else {
            // Inbound queue has at least one entry.

//从事件队列中取出一个事件
            mPendingEvent = mInboundQueue.dequeueAtHead();
            traceInboundQueueLengthLocked();
        }

        // Poke user activity for this event.
        if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
            pokeUserActivityLocked(mPendingEvent);
        }

        // Get ready to dispatch the event.
        resetANRTimeoutsLocked();
    }

    // Now we have an event to dispatch.
    // All events are eventually dequeued and processed this way, even if we intend to drop them.
    ALOG_ASSERT(mPendingEvent != NULL);
    bool done = false;

//在分发前会判断事件是否需要丢弃,丢弃的原因有很多,下面一个个解释
    DropReason dropReason = DROP_REASON_NOT_DROPPED;
    if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {

//如果没有POLICY_FLAG_PASS_TO_USER标志会被丢弃,比如在PhoneWindowManager的interceptKeyBeforeQueueing中对于power key则去掉这个标志,所以power key会在这里直接被丢弃掉,不会进行分发
        dropReason = DROP_REASON_POLICY;
    } else if (!mDispatchEnabled) {

//InputDispatcher分发被禁止
        dropReason = DROP_REASON_DISABLED;
    }
    if (mNextUnblockedEvent == mPendingEvent) {
        mNextUnblockedEvent = NULL;
    }

    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;
    }
//我们只讨论key event事件
    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) {

//因为阻塞了HOME key,从而丢弃
                dropReason = DROP_REASON_APP_SWITCH;
            }
        }
        if (dropReason == DROP_REASON_NOT_DROPPED
                && isStaleEventLocked(currentTime, typedEntry)) {

//事件太老了,具体有多老可以看看isStaleEventLocked实现,10s后的事件认为是太老了,比如说产生一个事件,10后InputDispatcher才开始分发
            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;
    }
//如果分发成功需要清空mPendingEvent等操作
    if (done) {
        if (dropReason != DROP_REASON_NOT_DROPPED) {
            dropInboundEventLocked(mPendingEvent, dropReason);
        }

        releasePendingEventLocked();
        *nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
    }
}

我们继续看dispatchKeyLocked()

bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
        DropReason* dropReason, nsecs_t* nextWakeupTime) {
    // Preprocessing.
    if (! entry->dispatchInProgress) {
        if (entry->repeatCount == 0
                && entry->action == AKEY_EVENT_ACTION_DOWN
                && (entry->policyFlags & POLICY_FLAG_TRUSTED)
                && (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) {
            if (mKeyRepeatState.lastKeyEntry
                    && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
                // We have seen two identical key downs in a row which indicates that the device
                // driver is automatically generating key repeats itself.  We take note of the
                // repeat here, but we disable our own next key repeat timer since it is clear that
                // we will not need to synthesize key repeats ourselves.
                entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1;
                resetKeyRepeatLocked();
                mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves
            } else {

//为生成key repeat事件做准备
                // Not a repeat.  Save key down state in case we do see a repeat later.
                resetKeyRepeatLocked();
                mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout;
            }
            mKeyRepeatState.lastKeyEntry = entry;
            entry->refCount += 1;

        } else if (! entry->syntheticRepeat) {
            resetKeyRepeatLocked();
        }

//这样设置可以使第二生成的key repeat事件时KeyEvent.java的isLongPress()返回true
        if (entry->repeatCount == 1) {
            entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
        } else {
            entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS;
        }

        entry->dispatchInProgress = true;

        logOutboundKeyDetailsLocked("dispatchKey - ", entry);
    }

    // Handle case where the policy asked us to try again later last time.

//key event独有的机制,在分发前还会再进行一次策略检查
    if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) {
        if (currentTime < entry->interceptKeyWakeupTime) {
            if (entry->interceptKeyWakeupTime < *nextWakeupTime) {
                *nextWakeupTime = entry->interceptKeyWakeupTime;
            }
            return false; // wait until next wakeup
        }
        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
        entry->interceptKeyWakeupTime = 0;
    }

    // Give the policy a chance to intercept the key.
    if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
        if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
            CommandEntry* commandEntry = postCommandLocked(
                    & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);//run phonewindowmanager interceptKeyBeforeDispatching
            if (mFocusedWindowHandle != NULL) {
                commandEntry->inputWindowHandle = mFocusedWindowHandle;
            }
            commandEntry->keyEntry = entry;
            entry->refCount += 1;
            return false; // wait for the command to run
        } else {
            entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
        }
    } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
        if (*dropReason == DROP_REASON_NOT_DROPPED) {
            *dropReason = DROP_REASON_POLICY;
        }
    }

    // Clean up if dropping the event.

//如果需要丢弃,则不进行分发
    if (*dropReason != DROP_REASON_NOT_DROPPED) {
        setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
                ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
        return true;
    }

    // Identify targets.
    Vector<InputTarget> inputTargets;

//搜索焦点窗口
    int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
            entry, inputTargets, nextWakeupTime);
    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
        return false;
    }

    setInjectionResultLocked(entry, injectionResult);
    if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
        return true;
    }

    addMonitoringTargetsLocked(inputTargets);

    // Dispatch the key.

//分发事件
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

这里我们重点分析key event独有的策略机制doInterceptKeyBeforeDispatchingLockedInterruptible()

void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
        CommandEntry* commandEntry) {
    KeyEntry* entry = commandEntry->keyEntry;


    KeyEvent event;
    initializeKeyEvent(&event, entry);


    mLock.unlock();


    nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
            &event, entry->policyFlags);


    mLock.lock();


    if (delay < 0) {
        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
    } else if (!delay) {
        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
    } else {
        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
        entry->interceptKeyWakeupTime = now() + delay;
    }
    entry->release();
}

这里会根据返回值不同,进行不同的处理,如果小于0则跳过分发,等于0则继续分发,大于0则等待delay后再分发

继续关注mPolicy->interceptKeyBeforeDispatching()

这里其实这里和前面的mPolicy->interceptMotionBeforeQueueing()是完全一样的流程,我就不详细分析了。


接下来要关注的就是dispatchEventLocked(currentTime, entry, inputTargets);了,不过这里涉及将key event事件通过InputChannel发送到ViewRootImpl中,中间很多地方还涉及WMS,比较偏Java层了,本系列文章不打算继续分析下去,以后有时间再分析吧。



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Android系统Recovery工作原理之使用update.zip升级过程---updater-script脚本语法简介以及执行流程

目前update-script脚本格式是edify,其与amend有何区别,暂不讨论,我们只分析其中主要的语法,以及脚本的流程控制。 一、update-script脚本语法简介:     ...

Android6.0 按键流程(三)InputDispatcher分发输入消息

上一篇博客分析了InputReader中扫描码与键盘码的转化,今天我们再来分析下InputDispatcher 一、InputDispatcher的notifyKey函数 接上一篇我们我们分析到I...

Android input处理机制(二)改键机制

本文主要总结一下Android平台的改键机制,从三个层次 驱动  键盘布局文件  InputReader 所涉及的类:    class EventHub;    struct Device;  ...

Android input处理机制(三)InputDispatcher

1.回顾 通过前两篇总结Android input处理机制(一)InputReader , Android input处理机制(二)改键机制,我们大致了解了InputReader和EventHub...

Android 输入系统之EventHub篇

做Android系统定制两年多了,受到别人启发,将自己的学习工作经历整理成博客,供以后重温,好了废话不多说,这段时间研究了下Android的输入系统,深深的感叹Android系统的庞大。。。。。。 ...

Consumer closed input channel or an error occurred. events=0x8

将代码移植到android的过程中出现了一个问题: 04-18 15:30:54.854: E/InputDispatcher(1568): channel '407d93b0 com.mobiap...

Android 4.0 事件输入(Event Input)系统

1. TouchScreen功能在Android4.0下不工作        原来在Android2.3.5下能正常工作的TouchScreen功能,移植到Android 4.0就不能正常工作了。凭...

Android4.4——InputManagerService之InputDispatcher线程

上篇博客《Android4.4——InputManagerService之InputReader线程》的最后已经进入到InputDispatcher线程中。现在接着InputReader开始着手分析I...

用 logcat 命令来查看 android 系统日志缓冲区的内容

*注:可以用 adb logcat> 路径/文件名 来保存,    此命令执行之时起的全部日志信息到一个文件里,ctrl+ C 结束日志输出;    后面不加 >路径/文件名 的话,则在 stdo...

Event分发源码分析(五)

4,分发Event 4.1 System分发 流程长而杂,仅分析关键点, dispatchOnceInnerLocked方法首先从mInboundQueue中取出KeyEntry,然后根据不同类...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)