Android input 系统之二:InputDispatcher线程

Android input 系统之二:InputDispatcher线程

touch事件处理流程:
touch事件数据获取处理后分发流程:

"InputDispatcher 线程"

InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
    //创建Looper对象
    mLooper = new Looper(false);

bool InputDispatcherThread::threadLoop()
    mDispatcher->dispatchOnce() //整个过程不断循环地调用InputDispatcher的dispatchOnce()来分发事件
    void InputDispatcher::dispatchOnce()  frameworks/native/services/inputflinger/InputDispatcher.cpp
        //唤醒等待线程,monitor()用于监控dispatcher是否发生死锁
        mDispatcherIsAliveCondition.broadcast();
        //当mCommandQueue不为空时处理
>>>>>>>>>>> dispatchOnceInnerLocked(&nextWakeupTime);
            nsecs_t currentTime = now(); //当前时间,也是后面ANR计时的起点

                if (!mDispatchEnabled) { //默认值为false
                    resetKeyRepeatLocked(); //重置操作
                }
                if (mDispatchFrozen) { //默认值为false
                    return; //当分发被冻结,则不再处理超时和分发事件的工作,直接返回
                }

               //优化app切换延迟,当切换超时,则抢占分发,丢弃其他所有即将要处理的事件。
               bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
               ...
 
               if (!mPendingEvent) {
                   if (mInboundQueue.isEmpty()) {
                        if (!mPendingEvent) {
                            return; //没有事件需要处理,则直接返回
                        }
                   } else {
                        //从mInboundQueue取出头部的事件
                         mPendingEvent = mInboundQueue.dequeueAtHead();
                   }
                  ...
            resetANRTimeoutsLocked(); //重置ANR信息
                 void InputDispatcher::resetANRTimeoutsLocked() {
                 // 重置等待超时cause和handle
                 mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
                 mInputTargetWaitApplicationHandle.clear(); 




            switch (mPendingEvent->type) 
                 case EventEntry::TYPE_MOTION: //触摸屏
                 done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); //开始touch 事件分发
                      bool InputDispatcher::dispatchMotionLocked
                          bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
                               if (isPointerEvent) //Pointer event
             >>>>>>>>>>>>>>>   injectionResult = findTouchedWindowTargetsLocked  //判断这个事件是点击事件(isPointEvent)还是其他事件--寻找目标窗口
                                   int32_t InputDispatcher::findTouchedWindowTargetsLocked    // Ensure all touched foreground windows are ready确保所有触摸的前台窗口都准备好进行新的                       
                                       // Check whether the window is ready  more input.
                                       String8 reason = checkWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, entry, "touched");
                                       if (!reason.isEmpty()) 
                                           injectionResult = handleTargetsNotReadyLocked  //如果这个window不能够继续处理事件,就是说这个window的主线程被某些耗时操作占据 
                                           int32_t InputDispatcher::handleTargetsNotReadyLocked                                  	
                                                mInputTargetWaitStartTime = currentTime; //当前时间
                                                ...
                                                timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; // 5s
                                                mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
                                                //这里的currentTime是指执行dispatchOnceInnerLocked方法体的起点
                                                mInputTargetWaitStartTime = currentTime;
                                                mInputTargetWaitTimeoutTime = currentTime + timeout;   //ANR 5s时间
                                                if (mInputTargetWaitTimeoutExpired) {
                                                    return INPUT_EVENT_INJECTION_TIMED_OUT; //等待超时已过期,则直接返回
                                                }
                                                //当超时5s则进入ANR流程
                                                if (currentTime >= mInputTargetWaitTimeoutTime)
                                                ...
                                                *nextWakeupTime = LONG_LONG_MIN; //强制立刻执行轮询来执行ANR策略
                                                            //  ANR超时时间点为mInputTargetWaitTimeoutTime,该值等于currentTime + 5s,  
                                                            //  这里的currentTime是指执行dispatchOnceInnerLocked方法体的起点。此处设置mInputTargetWaitCause
                                                            //  等于INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY(应用没有准备就绪),
                                                            //  而前面resetANRTimeoutsLocked()过程是唯一用于重置等待理由的地方。
                                                            //  可见,ANR时间区间是从dispatchOnceInnerLocked方法体的起点,
                                                            //  直到下次执行handleTargetsNotReadyLocked()方法的这段应用未准备就绪的时间段,该时间段是否超过5s来决定是否触发ANR。
                                                            //  当前这次的事件dispatch过程中执行findFocusedWindowTargetsLocked()方法到下一次执行resetANRTimeoutsLocked()的时间区间。

                                                            //handleTargetsNotReadyLocked()的判断过程:

                                                            当applicationHandle和windowHandle同时为空, 且system准备就绪的情况下
                                                                设置等待理由 INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY;
                                                                设置超时等待时长为无限大;
                                                                设置TimeoutExpired= false
                                                                清空等待队列;
                                                            当applicationHandle和windowHandle至少一个不为空, 且application准备就绪的情况下:
                                                            设置等待理由 INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
                                                            设置超时等待时长为5s;
                                                            设置TimeoutExpired= false
                                                            清空等待队列;

                                  //findTouchedWindowTargetsLocked,如果没有发生ANR,则addWindowTargetLocked()将该事件添加到inputTargets
                                  addWindowTargetLocked   
                                  void InputDispatcher::addWindowTargetLocked //将当前聚焦窗口mFocusedWindowHandle的inputChannel传递到inputTargets
           >>>>>>>>> dispatchEventLocked(currentTime, entry, inputTargets);
                         void InputDispatcher::dispatchEventLocked   
                              //向mCommandQueue队列添加doPokeUserActivityLockedInterruptible命令
                              pokeUserActivityLocked(eventEntry);  
                              void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry)
                                  CommandEntry* commandEntry = postCommandLocked
                                       // 将命令加入mCommandQueue队尾
                                       mCommandQueue.enqueueAtTail(commandEntry);
        
                              ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
                              ssize_t InputDispatcher::getConnectionIndexLocked  //根据inputChannel的fd从mConnectionsByFd队列中查询目标connection


                              //找到目标连接
                              prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); //该方法主要功能是将eventEntry发送到目标inputTargets
                                  void InputDispatcher::prepareDispatchCycleLocked
                                      if (connection->status != Connection::STATUS_NORMAL)
                                            return; //当连接已破坏,则直接返回
                                      enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
                                      void InputDispatcher::enqueueDispatchEntriesLocked
                                          enqueueDispatchEntryLocked...XXXX
                                              //生成新的事件, 加入connection的outbound队列  //添加到outboundQueue队尾
                                          if (wasEmpty && !connection->outboundQueue.isEmpty()) //当原先的outbound队列为空, 且当前outbound不为空的情况执行
                                             startDispatchCycleLocked(currentTime, connection);
                                             void InputDispatcher::startDispatchCycleLocked
                                                 switch (eventEntry->type) 
                                                     case EventEntry::TYPE_MOTION:
                                                         ...
                                                         status = connection->inputPublisher.publishMotionEvent // Publish the motion event.
                                                         //publishKeyEvent失败情况,从outboundQueue中取出事件,重新放入waitQueue队列// connection->outboundQueue.dequeue(dispatchEntry);
                                                                                                                                // connection->waitQueue.enqueueAtTail(dispatchEntry);
                                                              status_t InputPublisher::publishMotionEvent   //至此调用了connection的inputPublisher的publishMotionEvent方法将事件分发消耗。
                                                                                                            //InputChannel通过socket向远端的socket发送消息


        //分发操作完成,则进入该分支        
        if (done) 
            if (dropReason != DROP_REASON_NOT_DROPPED) 
                dropInboundEventLocked(mPendingEvent, dropReason);
                     switch (dropReason)
                          DROP_REASON_POLICY,DROP_REASON_DISABLED,DROP_REASON_APP_SWITCH,DROP_REASON_BLOCKED,DROP_REASON_STALE

                releasePendingEventLocked(); //释放pending事件
                    void InputDispatcher::releasePendingEventLocked()
                        resetANRTimeoutsLocked(); //重置ANR超时时间
                        releaseInboundEventLocked(mPendingEvent); //释放mPendingEvent对象,并记录到mRecentQueue队列
                        mPendingEvent = NULL; //置空mPendingEvent变量.

                *nextWakeupTime = LONG_LONG_MIN; //强制立刻执行轮询

            1.mDispatchFrozen用于决定是否冻结事件分发工作不再往下执行;
            2.当事件分发的时间点距离该事件加入mInboundQueue的时间超过500ms,则认为app切换过期,即isAppSwitchDue=true;   //在enqueueInboundEventLocked()的过程中已设置mAppSwitchDueTime等于eventTime加上500ms:
            3.mInboundQueue不为空,则取出头部的事件,放入mPendingEvent变量;并重置ANR时间;                              //mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
            4.根据EventEntry的type类型分别处理,比如按键调用dispatchMotionLocked分发事件;再根据分发结果来决定是否进入done;
            5.执行完成(done)的处理:
               根据dropReason(默认NOT_DROPPED不处理)来决定是否丢失事件; dropInboundEventLocked
               释放当前正在处理的事件(即mPendingEvent); releasePendingEventLocked

            关于dispatchMotionLocked分发事件,

            1.不会执行done过情况:
                当前Event时间小于唤醒时间;
                让policy有机会执行拦截操作;
                调用findFocusedWindowTargetsLocked方法的返回结果是INPUT_EVENT_INJECTION_PENDING, 即targets没有处于Ready状态;
             2.会执行done的情况:
                该事件需要丢弃, 即dropReason != DROP_REASON_NOT_DROPPED;
                findFocusedWindowTargetsLocked的返回结果不是INPUT_EVENT_INJECTION_PENDING(没有正在处理的事件);

>>>>>>>>>>> if (runCommandsLockedInterruptible())
                 nextWakeupTime = LONG_LONG_MIN;  //通过循环方式处理完mCommandQueue队列的所有命令,处理过程从mCommandQueue中取出CommandEntry.


>>>>>>>>>>> mLooper->pollOnce(timeoutMillis); //进入epoll_wait
             //线程执行Looper->pollOnce,进入epoll_wait等待状态,当发生以下任一情况则退出等待状态:

             //callback:通过回调方法来唤醒;
             //timeout:到达nextWakeupTime时间,超时唤醒;
             //wake: 主动调用Looper的wake()方法;

你可能感兴趣的:(Android)