美文网首页
android 按键事件响应流程(三)InputDispatch

android 按键事件响应流程(三)InputDispatch

作者: Ed_Lannister | 来源:发表于2019-12-10 14:57 被阅读0次
    5982616-0829faeca0627ce7.png 图片.png

    InputReader封装好KeyEntries,通知InputDispatch处理事件,先看看Dispatcher的构建函数,新建了一个looper,来做dispatcher的分发循环,并获取了一下Dispatcher的配置信息,这里的配置信息的default值有key的超时和延迟时间,更多的配置在ViewConfiguration中,这些配置都是在input dispatcher初始化的时候加载进来的。

    InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
        mPolicy(policy),
        mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
        mNextUnblockedEvent(NULL),
        mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
        mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE), mIsPredumping(false) {
        mLooper = new Looper(false);
        mKeyRepeatState.lastKeyEntry = NULL;
        policy->getDispatcherConfiguration(&mConfig);
    }
    

    InputManager在start InputReaderThread之后,同时也启动了InputDispatchThread,这里looper循环里就只有一个dispatchOnce方法,mDispatch是一个InputDispatcherInterface对象,这个接口使用来异步通知系统input reader上报上来的input event事件。

    InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
            Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {}
    InputDispatcherThread::~InputDispatcherThread() {}
    bool InputDispatcherThread::threadLoop() {
        mDispatcher->dispatchOnce();
        return true;
    }
    }
    

    首先定义了一个超长的下次唤醒时间,然后去获取锁,检查命令队列里面有没有还没有执行的命令,如果有命令的话就会执行dispatchOnceInnerLocked,如果命令列表为空的话就会入队命令继续运行;

    Queue<CommandEntry> mCommandQueue;
    ···
    void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
        nsecs_t currentTime = now();
        //如果设备处于非交互状态,Dispatch被disable了,就去重置key的repeat计时器,保证当设备刚唤醒的时候抛弃key repeat事件
        if (!mDispatchEnabled) {
            resetKeyRepeatLocked();
        }
        //如果dispatch被冻结,就不处理超时唤醒或者任何新的事件
        if (mDispatchFrozen) {
            return;
        }
        // 当发生app切换,比如home键或者挂断键按下,就把app切换的时间作为下一次唤醒的时间
        bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
        if (mAppSwitchDueTime < *nextWakeupTime) {
            *nextWakeupTime = mAppSwitchDueTime;
        }
    if (! mPendingEvent) {
            //命令队列为空
            if (mInboundQueue.isEmpty()) {
                if (isAppSwitchDue) {
                    //刚发生过一次app切换,但此时入站队列是空,所以等的切换事件就不会来,所以不再等待,并重置flag,
                    //这里的逻辑应该是,如果有事件,入站队列肯定不应为空
                    resetPendingAppSwitchLocked(false);
                    isAppSwitchDue = false;
                }
                //mKeyRepeatState是记录key repeat的结构体
                //如果repeat key的nexttime已经过了,就重新做了一个mPendingEvent去处理
                //如果没有nexttime没有过时,但是wakeup的time在repeat time之后,就得让唤醒时间提前。
                if (mKeyRepeatState.lastKeyEntry) {
                    if (currentTime >= mKeyRepeatState.nextRepeatTime) {
                        mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
                    } else {
                        if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
                            *nextWakeupTime = mKeyRepeatState.nextRepeatTime;
                        }
                    }
                }
    
                // 如果没有重新做一个mPendingEvent事件退出
                if (!mPendingEvent) {
                    return;
                }
            } else {
                // 入站队列至少有一条item,就将事件出队列赋值到当前的处理对象上去
                mPendingEvent = mInboundQueue.dequeueAtHead();
                traceInboundQueueLengthLocked();
            }
    
            // 对比flag看要不要把这一次生成的mPendingEvent捅给用户进程
            if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
                pokeUserActivityLocked(mPendingEvent);
            }
    
            // 准备分发数据
            resetANRTimeoutsLocked();
        }
    
    

    mPendingEvent是EventEntry对象

    struct EventEntry : Link<EventEntry> {
            enum {
                TYPE_CONFIGURATION_CHANGED,
                TYPE_DEVICE_RESET,
                TYPE_KEY,
                TYPE_MOTION
            };
            mutable int32_t refCount;
            int32_t type;
            nsecs_t eventTime;
            uint32_t policyFlags;
            InjectionState* injectionState;
            bool dispatchInProgress; // initially false, set to true while dispatching
            inline bool isInjected() const { return injectionState != NULL; }
            void release();
            virtual void appendDescription(String8& msg) const = 0;
        protected:
            EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags);
            virtual ~EventEntry();
            void releaseInjectionState();
        };
    

    再看看他是怎么往window manager那里捅的

    sp<InputWindowHandle> mFocusedWindowHandle;
    //InputWindowHandle是window用来接收InputDispatcher传来的input事件,并且能够使InputDispatcher
    //间接的操作到window manager的window state
    void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
        //这个功能可以被window manager 禁用掉
        if (mFocusedWindowHandle != NULL) {
            const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
            if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {
                return;
            }
        }
    
        int32_t eventType = USER_ACTIVITY_EVENT_OTHER;
        switch (eventEntry->type) {
        case EventEntry::TYPE_MOTION: 
        case EventEntry::TYPE_KEY: {
            const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry);
            if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) {
                return;
            }
            eventType = USER_ACTIVITY_EVENT_BUTTON;
            break;
        }
        }
    
        CommandEntry* commandEntry = postCommandLocked(
                & InputDispatcher::doPokeUserActivityLockedInterruptible);
        commandEntry->eventTime = eventEntry->eventTime;
        commandEntry->userActivityEventType = eventType;
    }
    

    postCommandLocked是新建了一个CommandEntry对象,并把对应的command入到队尾。

    InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
        CommandEntry* commandEntry = new CommandEntry(command);
        mCommandQueue.enqueueAtTail(commandEntry);
        return commandEntry;
    }
    

    CommandEntry 是这样一个东西

    struct CommandEntry : Link<CommandEntry> {
            CommandEntry(Command command);
            ~CommandEntry();
            Command command;
            sp<Connection> connection;
            nsecs_t eventTime;
            KeyEntry* keyEntry;
            sp<InputApplicationHandle> inputApplicationHandle;
            sp<InputWindowHandle> inputWindowHandle;
            String8 reason;
            int32_t userActivityEventType;
            uint32_t seq;
            bool handled;
        };
    

    运行存在的所有命令,如果有命令执行就立马唤醒下一个poll;
    释放锁之后,就开始等待回调、超时唤醒、唤醒

    void InputDispatcher::dispatchOnce() {
        nsecs_t nextWakeupTime = LONG_LONG_MAX;
        { // acquire lock
            AutoMutex _l(mLock);
            mDispatcherIsAliveCondition.broadcast();
    
            if (!haveCommandsLocked()) {
                dispatchOnceInnerLocked(&nextWakeupTime);
            }
    
            if (runCommandsLockedInterruptible()) {
                nextWakeupTime = LONG_LONG_MIN;
            }
        } // release lock
    
        nsecs_t currentTime = now();
        int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
        mLooper->pollOnce(timeoutMillis);
    }
    

    准备好一次EventEntry事件之后,就开始针对type针对性的处理各种类型的事件,前面说的是入队事件的流程,即使一个事件需要丢弃,也是会走这样的一个流程。这里就以dispatchKeyLocked来看看做了哪些操作。

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

    dispatchKeyLocked的实现,首先是一个处理中的flag判断,如果没有处理,就开始看当前keyevent repeatCount是不是等于0,按键是不是down的状态,策略flag是不是可信的,且没有disable掉重复按键逻辑,如果这一次的keyEvent的按键code是和上一次按键的相同,就认为是一次设备驱动生成的重复按键事件,然后更新当前keyevent的repeat count,为前一次的+1,同时释放前一次按键,由当前按键作为下一次按键事件的lastevent,因为是自己生成的repeat key所以,next repeat time设置成超长的时间间隔;如果本次key event 传过来的是新值,就需要设置新的重复按键计时,并将本次key event更新为last keyevent,refcount+1.repeatCount==1的时候就会设置长按的flag到key event的flag里面,然后修改标记为正在处理。

    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) {
                    entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1;
                    resetKeyRepeatLocked();
                    mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves
                } else {
                    resetKeyRepeatLocked();
                    mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout;
                }
                mKeyRepeatState.lastKeyEntry = entry;
                entry->refCount += 1;
            } else if (! entry->syntheticRepeat) {
                resetKeyRepeatLocked();
            }
            if (entry->repeatCount == 1) {
                entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
            } else {
                entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS;
            }
    
            entry->dispatchInProgress = true;
    

    dispatch policy可以控制处理延迟,可以将本次事件延迟到下一次解决;后续还有允许policy中断keyevent的逻辑,drop的逻辑。
    我们关注最重要的这一部分
    1.首先是new了一个inputTargets对象,然后通过findFocusedWindowTargetsLocked,找到当前focus的window,这一步里面会检查权限,以及是否有focus的window,以及这个window是否可以接受新的input了,都成功后,会通过addWindowTargetLocked将mFocusedWindowHandle保存的window信息放入到InputTarget对象当中去并将结果setInjectionResultLocked设置进entry中
    2.addMonitoringTargetsLocked()是将input target做一个备份,InputChannel会接受所有input的事件的拷贝。

        Vector<sp<InputChannel> > mMonitoringChannels;
    
    

    3.做好这些工作后,就准备分发key了dispatchEventLocked

        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);
    
        dispatchEventLocked(currentTime, entry, inputTargets);
    

    dispatchEventLocked这里也做了一个把eventEntry处理一下,发送到command队列里面等待执行。然后针对每个input target,在dispatcher里面,所有的dispatch的事件都通过input target里面指定的一个inputchannel进行连接;所有注册过后的连接,都会通过input channel的文件描述符进行map。
    找到connection之后,将eventEntry,currentTime,还有inputTarget一起塞进prepareDispatchCycleLocked。

    void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
            EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
        pokeUserActivityLocked(eventEntry);
    
        for (size_t i = 0; i < inputTargets.size(); i++) {
            const InputTarget& inputTarget = inputTargets.itemAt(i);
    
            ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
            if (connectionIndex >= 0) {
                sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
                prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
            } else {
                //drop已经不再注册表里特定channel的事件
            }
        }
    }
    

    prepareDispatchCycleLocked这里是转了一道

    void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
            const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
        //如果连接状态不是normal就不处理event
        if (connection->status != Connection::STATUS_NORMAL) {
            return;
        }
        //如果有需求就可以分离出motion事件处理
        if (inputTarget->flags & InputTarget::FLAG_SPLIT) {
            MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry);
            if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) {
                MotionEntry* splitMotionEntry = splitMotionEvent(
                        originalMotionEntry, inputTarget->pointerIds);
                if (!splitMotionEntry) {
                    return; // split event was dropped
                }
                enqueueDispatchEntriesLocked(currentTime, connection,
                        splitMotionEntry, inputTarget);
                splitMotionEntry->release();
                return;
            }
        }
    
        // 如果没有motion分离的需求,直接将事件入队列
        enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
    }
    

    enqueueDispatchEntriesLocked为实际工作对象,这里暂不清楚为什么要将本次eventEntry通过全模式入队出站队列。

    
    void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
            const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
        bool wasEmpty = connection->outboundQueue.isEmpty();
    
        //根据要求的模式,入队事件。
        enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
        enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
        enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
        enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                InputTarget::FLAG_DISPATCH_AS_IS);
        enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
        enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
    
        // 如果出站的队列为空,就启动循环
        if (wasEmpty && !connection->outboundQueue.isEmpty()) {
            startDispatchCycleLocked(currentTime, connection);
        }
    }
    

    如果当前出站队列为空的话,就如如下处理,channel通过socket向远端发送eventEntry

    switch (eventEntry->type) {
            case EventEntry::TYPE_KEY: {
                KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
    
                // 封装keyevent消息
                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;
            }
            connection->outboundQueue.dequeue(dispatchEntry);
            connection->waitQueue.enqueueAtTail(dispatchEntry);
    }
    
    //将keyevent事件通过mChannel->sendMessage(&msg);发送到出站队列内
    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) {
        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);
    }
    

    如果出站队列不为空的话enqueueDispatchEntryLocked就处理了一下connection的input state然后就更新了一下,connection的outboundQueue

    connection->outboundQueue.enqueueAtTail(dispatchEntry);
    

    至此,我们看到处理逻辑全部都被发送到command队列中去了。

    bool InputDispatcher::runCommandsLockedInterruptible() {
        if (mCommandQueue.isEmpty()) {
            return false;
        }
    
        do {
            CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
    
            Command command = commandEntry->command;
            (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
    
            commandEntry->connection.clear();
            delete commandEntry;
        } while (! mCommandQueue.isEmpty());
        return true;
    }
    

    viewRootImpl的setView方法中,新建了InputChannel,mWindowSession.addToDisplay最后会传递到WindowManagerService的addWindow方法,把InputChannel传输到WindowManagerService中,建立传输通道,然后又新建了WindowInputEventReceiver,

                    if ((mWindowAttributes.inputFeatures
                            & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                        mInputChannel = new InputChannel();
                    }
    ···
    mOrigWindowType = mWindowAttributes.type;
                        mAttachInfo.mRecomputeGlobalAttributes = true;
                        collectViewAttributes();
                        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                                getHostVisibility(), mDisplay.getDisplayId(),
                                mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
    ···
    if (mInputChannel != null) {
                        if (mInputQueueCallback != null) {
                            mInputQueue = new InputQueue();
                            mInputQueueCallback.onInputQueueCreated(mInputQueue);
                        }
                        mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                                Looper.myLooper());
                    }
    ···
    

    WMS中的addWindow,注册了inputChannel,设定了channel对,数据流向是有InputPublisher和InputConsumer在组合了InputChannel后决定的

                mPolicy.adjustWindowParamsLw(win.mAttrs);
                win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
    
                res = mPolicy.prepareAddWindowLw(win, attrs);
                if (res != WindowManagerGlobal.ADD_OKAY) {
                    return res;
                }
    
                if (outInputChannel != null && (attrs.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                     try {
                        String name = win.makeInputChannelName();
                        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
                        win.setInputChannel(inputChannels[0]);
                        inputChannels[1].transferTo(outInputChannel);
    mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
                    } catch (IllegalArgumentException e) {
                        Slog.w(TAG, "handle Input channel erorr", e);
                        return WindowManagerGlobal.ADD_INPUTCHANNEL_NOT_ALLOWED;
                    }
                }
    

    相关文章

      网友评论

          本文标题:android 按键事件响应流程(三)InputDispatch

          本文链接:https://www.haomeiwen.com/subject/tkxdgctx.html