AndroidR Input子系统(9)UI线程对Input事件的分发与结束处理

上一篇文章分析到应用程序和InputDispatcher分别属于两个不同进程,他们之间的连接需要依靠InputChannel(内部通过一对socket实现)来建立,连接建立之后,InputDispatcher就可以将Input事件发送到应用程序的UI线程,而应用程序处理完事件之后也可以通过InputChannel通知到InputDispatcher。

整个过程总结如下:

  1. 首先当一个APP启动时,会将自己的Window添加到WMS,并传递一个空InputChannel过去。
  2. WMS端,通过openInputChannel方法会创建一对InputChannel,是在native层完成的,这对InputChannel被分为“client”端和“server”端,其内部又会创建一对socket,和这对InputChannel一一对应。
  3. “server”端InputChannel会被注册到InputDispatcher中去,注册的原理就是将InputChannel内部的socket添加到其Looper进行监听,注册过程中还会创建一个Connection对象,Connection用来描述InputDispatcher与此次注册InputChannel的窗口的连接。
  4. "client"端InputChannel会被设置到APP进程中,接着通过InputEventReceiver注册到APP UI线程,同样是将InputChannel内部的socket添加到UI线程的Looper进行监听。
  5. 对于InputDispatcher线程,在接收到"client"端socket的消息时会回调其handleReceiveCallback函数,对于APP UI线程,在接收到"server"端socket的消息时会回调InputEventReceiver对应的native层对象NativeInputEventReceiverhandleEvent函数。

本篇我们来看看事件发送到应用程序的UI线程之后,应用程序对事件的后续处理流程。

InputDispatcher将事件发送出去依靠的是Looper监听了InputChannel内部一对socket的server端和client端,InputDispatcher向server端写入数据,对面client端就能收到消息并回调对应函数,对面指的就是应用程序的UI线程,回调函数则是NativeInputEventReceiverhandleEvent函数,我们以此函数为入口开始深入:

NativeInputEventReceiver::handleEvent

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
    if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
        //异常情况
        return 0; // remove the callback
    }

    if (events & ALOOPER_EVENT_INPUT) {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
        mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
        return status == OK || status == NO_MEMORY ? 1 : 0;
    }

    if (events & ALOOPER_EVENT_OUTPUT) {
        .....
        .....
        return 1;
    }

    ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
            "events=0x%x", getInputChannelName().c_str(), events);
    return 1;
}

这个函数分为两部分,对应两种Looper事件类型,ALOOPER_EVENT_INPUT表示应用程序准备开始分发并处理输入事件,ALOOPER_EVENT_OUTPUT表示应用程序已经完成输入事件的处理,我们首先来看第一部分,这里调用了consumeEvents函数:

NativeInputEventReceiver::consumeEvents

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
   //status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
    
    ...
    
    ScopedLocalRef<jobject> receiverObj(env, nullptr);
    bool skipCallbacks = false;
    //死循环
    for (;;) {
        uint32_t seq;
        InputEvent* inputEvent;
        //获取输入事件
        status_t status = mInputConsumer.consume(&mInputEventFactory,
                consumeBatches, frameTime, &seq, &inputEvent);
        if (status != OK && status != WOULD_BLOCK) {
            ALOGE("channel '%s' ~ Failed to consume input event.  status=%d",
                  getInputChannelName().c_str(), status);
            return status;
        }
        if (status == WOULD_BLOCK) {
            if (!skipCallbacks && !mBatchedInputEventPending && mInputConsumer.hasPendingBatch()) {
                // There is a pending batch.  Come back later.
                if (!receiverObj.get()) {
                        //异常情况
                        return DEAD_OBJECT;
                    }
                }

                mBatchedInputEventPending = true;
                //回调java层InputEventReceiver.java的onBatchedInputEventPending方法
                env->CallVoidMethod(receiverObj.get(),
                                    gInputEventReceiverClassInfo.onBatchedInputEventPending,
                                    mInputConsumer.getPendingBatchSource());
                if (env->ExceptionCheck()) {
                    ALOGE("Exception dispatching batched input events.");
                    mBatchedInputEventPending = false; // try again later
                }
            }
            return OK;
        }
        assert(inputEvent);

        if (!skipCallbacks) {
            if (!receiverObj.get()) {
                    //异常
                    return DEAD_OBJECT;
                }
            }

            jobject inputEventObj;
            switch (inputEvent->getType()) {
            //按键事件
            case AINPUT_EVENT_TYPE_KEY:
                //将native层KeyEvent转换为java层KeyEvent
                inputEventObj = android_view_KeyEvent_fromNative(env,
                        static_cast<KeyEvent*>(inputEvent));
                break;
            //触摸事件....
            ...
            default:
                assert(false); // InputConsumer should prevent this from ever happening
                inputEventObj = nullptr;
            }
            //输入事件不为空
            if (inputEventObj) {
                //调到java层InputEventReceiver.java的dispatchInputEvent方法
                env->CallVoidMethod(receiverObj.get(),
                        gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
                ...
                env->DeleteLocalRef(inputEventObj);
            } else {
                ALOGW("channel '%s' ~ Failed to obtain event object.",
                        getInputChannelName().c_str());
                skipCallbacks = true;
            }
        }

        if (skipCallbacks) {
            //异常情况,发送完成信号
            mInputConsumer.sendFinishedSignal(seq, false);
        }
    }
}

此函数首先调用InputConsumerconsume函数来获得InputEvent,对于按键类型事件的处理就非常简单了,然后将native层KeyEvent转换为java层KeyEvent,并调用java层InputEventReceiver.javadispatchInputEvent方法将Input事件分发到java层。

接着来看看InputConsumerconsume函数:

InputConsumer::consume

status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches,
                                nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
    

    *outSeq = 0;
    *outEvent = nullptr;

    //如果outEvent为空
    while (!*outEvent) {
        //mMsgDeferred默认值为false
        if (mMsgDeferred) {
            // mMsg contains a valid input message from the previous call to consume
            // that has not yet been processed.
            mMsgDeferred = false;
        } else {
            //获取InputDispatcher发送过来的InputMessage,InputMessage封装了Input事件
            //的各种信息,通过sendMessage发送
            status_t result = mChannel->receiveMessage(&mMsg);
            //如果result不为OK
            if (result) {
                 ...
                }
                return result;
            }
        }
        //Input事件类型
        switch (mMsg.header.type) {
            case InputMessage::Type::KEY: {
                //创建一个KeyEvent空对象
                KeyEvent* keyEvent = factory->createKeyEvent();
                if (!keyEvent) return NO_MEMORY;
                //用InputMessage中的信息填充此空KeyEvent
                initializeKeyEvent(keyEvent, &mMsg);
                *outSeq = mMsg.body.key.seq;
                *outEvent = keyEvent;
                if (DEBUG_TRANSPORT_ACTIONS) {
                    ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
                          mChannel->getName().c_str(), *outSeq);
                }
            break;
            }
           .....
           .....
           //触摸事件及其他事件,省略
            
        }
    }
    return OK;
}

对于按键事件,此函数流程很简单,通过receiveMessage函数读取到InputDispatcher发送过来的InputMessageInputMessage封装了Input事件的各种信息,用这些信息填充了一个空的KeyEvent
因为我们分析的是按键事件,相对触摸事件,细节会简单很多,但流程是差不多的。

回到consumeEvents函数,KeyEvent得到之后就会调用InputEventReceiver.javadispatchInputEvent方法将事件发送到java层:

InputEventReceiver.dispatchInputEvent

 // Called from native code.
    @SuppressWarnings("unused")
    @UnsupportedAppUsage
    private void dispatchInputEvent(int seq, InputEvent event) {
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event);
    }

接着调用其子类WindowInputEventReceiver(ViewRootImpl的内部类)重写的onInputEvent方法,此方法就是java层事件分发的起点。

WindowInputEventReceiver.onInputEvent

@Override
        public void onInputEvent(InputEvent event) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
            List<InputEvent> processedEvents;
            try {
                //做一些兼容性处理,在大于M的版本直接返回null
                processedEvents =
                    mInputCompatProcessor.processInputEventForCompatibility(event);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
            if (processedEvents != null) {
               ....
            } else {
                enqueueInputEvent(event, this, 0, true);
            }
        }

ViewRootImpl.enqueueInputEvent

    @UnsupportedAppUsage
    void enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {
        //构造一个QueuedInputEvent对象,使用obtainQueuedInputEvent构造对象,类似
        //Message.obtain,通过池的形式保存回收对象,内部使用链表
        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
        //mPendingInputEventTail代表QueuedInputEvent链表尾节点
        QueuedInputEvent last = mPendingInputEventTail;
        if (last == null) {
           //如果是首次进入,头尾节点都指向第一个构造的QueuedInputEvent
            mPendingInputEventHead = q;
            mPendingInputEventTail = q;
        } else {
            //否则,将QueuedInputEvent添加到链表尾部
            last.mNext = q;
            //尾节点重新指向新添加的QueuedInputEvent
            mPendingInputEventTail = q;
        }
        //QueuedInputEvent数量加1
        mPendingInputEventCount += 1;
        Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                mPendingInputEventCount);

        if (processImmediately) {
            doProcessInputEvents();
        } else {
            scheduleProcessInputEvents();
        }
    }

ViewRootImpl中对QueuedInputEvent的构造以类似Message.obtain,内部用池的形式回收利用QueuedInputEvent,以提高效率,池的最大数量为MAX_QUEUED_INPUT_EVENT_POOL_SIZE等于10,池的数据结构就是链表,并表明了输入事件在ViewRootImpl的保存顺序,始终将新添加的输入事件保存在链表末尾。

方法最后processImmediately代表是否立即分发事件,前面参数传的true,所以接着看doProcessInputEvents方法:

ViewRootImpl.doProcessInputEvents

void doProcessInputEvents() {
        //头节点不为空,代表链表中有事件处理
        while (mPendingInputEventHead != null) {
            //按顺序取出
            QueuedInputEvent q = mPendingInputEventHead;
            //头节点后移
            mPendingInputEventHead = q.mNext;
            if (mPendingInputEventHead == null) {
                mPendingInputEventTail = null;
            }
            //将取出来的QueuedInputEvent的mNext置空
            q.mNext = null;
            //QueuedInputEvent链表数量减一
            mPendingInputEventCount -= 1;
           
            //此事件发生的时间
            long eventTime = q.mEvent.getEventTimeNano();
            long oldestEventTime = eventTime;
            //如果是触摸事件
            if (q.mEvent instanceof MotionEvent) {
                ....
            }
            mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
            //分发事件
            deliverInputEvent(q);
        }

        // We are done processing all input events that we can process right now
        // so we can clear the pending flag immediately.
        if (mProcessInputEventsScheduled) {
            mProcessInputEventsScheduled = false;
            mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
        }
    }

此方法就是遍历链表,将所有事件取出来调用deliverInputEvent进一步分发:

ViewRootImpl.deliverInputEvent

    private void deliverInputEvent(QueuedInputEvent q) {
     
        try {
            if (mInputEventConsistencyVerifier != null) {
                
                try {
                    mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
                } finally {
                    
                }
            }

            InputStage stage;
            if (q.shouldSendToSynthesizer()) {
                //如果事件中带有FLAG_UNHANDLED的flag
                stage = mSyntheticInputStage;
            } else {
                //shouldSkipIme代表事件是否传递给输入法,对于按键事件,
                //仅仅在主动设置了FLAG_DELIVER_POST_IME时返回true,
                //触摸事件则是判断其事件来源,一般情况的触摸事件都是返回true
                stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
            }
           //如果是按键事件
            if (q.mEvent instanceof KeyEvent) {
               
                try {
                    mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                }
            }

            if (stage != null) {
                handleWindowFocusChanged();
                //分发事件
                stage.deliver(q);
            } else {
                finishInputEvent(q);
            }
        } finally {
            
        }
    }

shouldSendToSynthesizer一般都是false,仅在主动添加了FLAG_UNHANDLED时为true,shouldSkipIme判断事件是否传给输入法,对于按键事件,
仅仅在主动设置了FLAG_DELIVER_POST_IME时返回true,
触摸事件则是判断其事件来源,一般情况的触摸事件都是返回true。这两个方法的返回结果决定了InputStage的类型,InputStage是一个顶级父类,采用责任链模式分发事件,每一个InputStage的实现类中都含有一个mNext变量,指向下一个InputStage的实现类,类似链表,当某个InputStage的实现类得到事件并分发完成之后,可以选择结束,或者继续分发给mNext,通过deliver方法分发。

InputStage的一众实现类在ViewRootImplsetView中初始化:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
            ......
            ......
                // Set up the input pipeline.
                CharSequence counterSuffix = attrs.getTitle();
                mSyntheticInputStage = new SyntheticInputStage();
                InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
                InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                        "aq:native-post-ime:" + counterSuffix);
                InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
                InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                        "aq:ime:" + counterSuffix);
                InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
                InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                        "aq:native-pre-ime:" + counterSuffix);

                mFirstInputStage = nativePreImeStage;
                mFirstPostImeInputStage = earlyPostImeStage;
                ......
     }

这几个InputStage的实现类通过mNext单向连接在了一起,像注释说的一样,这些就是输入事件的管道,输入事件可通过头部流到尾部,如下图:
在这里插入图片描述

我们回到前面的deliverInputEvent方法,对于按键事件,shouldSkipIme返回false,所以得到的InputStagemFirstInputStagemFirstInputStage对应上图中的nativePreImeStage,所以此次事件会从输入管道的最顶部开始分发。

NativePreImeInputStage并没有重写deliver方法,我们到父类来看:

InputStage.deliver

         /**
         * Delivers an event to be processed.
         */
        public final void deliver(QueuedInputEvent q) {
            //是否带有FLAG_FINISHED的flag,如有则将事件分发给mNext
            if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
                forward(q);
                //是否应该丢弃事件
            } else if (shouldDropInputEvent(q)) {
                finish(q, false);
            } else {
                traceEvent(q, Trace.TRACE_TAG_VIEW);
                final int result;
                try {
                    //实际处理事件
                    result = onProcess(q);
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                }
                //拿到处理事件的结果后决定进一步行动
                apply(q, result);
            }
        }

如果此事件没有QueuedInputEvent.FLAG_FINISHED的flag,并且没有被丢弃则会调用NativePreImeInputStageonProcess方法,做具体的事件处理:

NativePreImeInputStage.onProcess

 final class NativePreImeInputStage extends AsyncInputStage
            implements InputQueue.FinishedInputEventCallback {
        ...
        @Override
        protected int onProcess(QueuedInputEvent q) {
            if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
                mInputQueue.sendInputEvent(q.mEvent, q, true, this);
                return DEFER;
            }
            return FORWARD;
        }
        ......
    }

我们可以发现NativePreImeInputStage只会处理按键类型事件,如果是触摸事件,会直接返回FORWARD

不管是按键事件,还是触摸事件都是通过InputStage的各个实现类分发到对应窗口的,按键事件对应方法processKeyEvent,触摸事件对应方法processPointerEvent,这两个方法之后的逻辑就是Android开发者很熟悉的View的事件分发机制了,不是本篇重点,暂时跳过。

UI线程对Input事件的分发到此就结束了,接着我们要来看看应用程序处理完事件之后的逻辑了。

InputStageonDeliverToNext方法用于将事件分发给下一个InputStage

InputStage.onDeliverToNext

/**
         * Called when an event is being delivered to the next stage.
         */
        protected void onDeliverToNext(QueuedInputEvent q) {
            
            if (mNext != null) {
                mNext.deliver(q);
            } else {
                finishInputEvent(q);
            }
        }

当没有下一个InputStage时便会调用finishInputEvent方法结束此次分发:

ViewRootImpl.finishInputEvent

private void finishInputEvent(QueuedInputEvent q) {
        //mReceiver指向InputEventReceiver
        if (q.mReceiver != null) {
            //代表事件是否处理完成,处理完成之后会添加
            //QueuedInputEvent.FLAG_FINISHED_HANDLED的flag
            boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
            //兼容性相关的flag,Android M之后不会再添加
            boolean modified = (q.mFlags & QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY) != 0;
            if (modified) {
                ...
            } else {
                q.mReceiver.finishInputEvent(q.mEvent, handled);
            }
        } else {
            q.mEvent.recycleIfNeededAfterDispatch();
        }

        recycleQueuedInputEvent(q);
    }

此方法关键两步,其一调用InputEventReceiverfinishInputEvent方法,其二调用recycleQueuedInputEvent方法,recycleQueuedInputEvent比较简单,看名字都知道,这个方法主要做QueuedInputEvent的回收工作:

ViewRootImpl.recycleQueuedInputEvent

   private void recycleQueuedInputEvent(QueuedInputEvent q) {
        q.mEvent = null;
        q.mReceiver = null;

        if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
            mQueuedInputEventPoolSize += 1;
            q.mNext = mQueuedInputEventPool;
            mQueuedInputEventPool = q;
        }
    }

前面我们提到过QueuedInputEvent的创建类似Message.obtain,采用对象池的方式进行回收利用,这里首先将QueuedInputEvent重要成员变量置空,之后如果QueuedInputEvent池未满,则将此对象加入对象池(对象池以链表形式保存回收的对象)。

接着重点来看InputEventReceiverfinishInputEvent方法,此方法接收两个参数,一个是此次完成的事件,另一个是此次事件是否被处理,InputStage及其子类AsyncInputStage中定义了四个状态,用来描述输入事件的处理结果,分别是DEFER(延迟处理),FORWARD(交给mNext处理),FINISH_HANDLED(完成处理),FINISH_NOT_HANDLED(未处理),这里假定事件已经成功处理,即状态为FINISH_HANDLED

InputEventReceiver.finishInputEvent

   public final void finishInputEvent(InputEvent event, boolean handled) {
        if (event == null) {
            throw new IllegalArgumentException("event must not be null");
        }
        if (mReceiverPtr == 0) {
            Log.w(TAG, "Attempted to finish an input event but the input event "
                    + "receiver has already been disposed.");
        } else {
            int index = mSeqMap.indexOfKey(event.getSequenceNumber());
            if (index < 0) {
                Log.w(TAG, "Attempted to finish an input event that is not in progress.");
            } else {
                int seq = mSeqMap.valueAt(index);
                mSeqMap.removeAt(index);
                nativeFinishInputEvent(mReceiverPtr, seq, handled);
            }
        }
        event.recycleIfNeededAfterDispatch();
    }

通过nativeFinishInputEvent调到native层处理:

android_view_InputEventReceiver::nativeFinishInputEvent

static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr,
        jint seq, jboolean handled) {
    sp<NativeInputEventReceiver> receiver =
            reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
    status_t status = receiver->finishInputEvent(seq, handled);
    ......
}

NativeInputEventReceiver::finishInputEvent

status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
   

    status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
    if (status) {
        if (status == WOULD_BLOCK) {
            ...
            Finish finish;
            finish.seq = seq;
            finish.handled = handled;
            mFinishQueue.add(finish);
            if (mFinishQueue.size() == 1) {
                setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT);
            }
            return OK;
        }
        
    }
    return status;
}

此函数分为两部分,首先会执行sendFinishedSignal函数,顾名思义,发送完成的信号,向谁发送?当然是InputDispatcher。接着会根据sendFinishedSignal函数的返回结果决定是否向Looper注册ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT事件,WOULD_BLOCK这个状态意味socket传输发生错误,当socket发生错误,InputDispatcher就无法得知应用程序处理是否处理完此次输入事件,所以需要为此次事件创建一个Finish结构体,并添加ALOOPER_EVENT_OUTPUT事件作为监听,那么什么时候处理ALOOPER_EVENT_OUTPUT事件呢?答案就是下一次InputDispatcher发送输入事件给应用程序时。

还记得文章开头分析的InputDispatcher发送输入事件给应用程序之后会回调NativeInputEventReceiverhandleEvent函数吗?我们再回头来看看此函数:

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
      ......
    //处理ALOOPER_EVENT_INPUT类型事件
    if (events & ALOOPER_EVENT_INPUT) {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
        mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
        return status == OK || status == NO_MEMORY ? 1 : 0;
    }
    //处理ALOOPER_EVENT_OUTPUT类型事件
    if (events & ALOOPER_EVENT_OUTPUT) {
        for (size_t i = 0; i < mFinishQueue.size(); i++) {
            const Finish& finish = mFinishQueue.itemAt(i);
            status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
            if (status) {//如果status大于0,说明此次
                         //sendFinishedSignal依然失败了
                mFinishQueue.removeItemsAt(0, i);

                if (status == WOULD_BLOCK) {
                     ...
                     //返回1,此次Looper回调会再次被执行
                    return 1; later
                }

               ...
 				...
 				//返回0,Looper会移除此次回调
                return 0;
            }
        }
       //正常情况,成功通知到InputDispatcher,清空mFinishQueue
        mFinishQueue.clear();
        //移除ALOOPER_EVENT_OUTPUT类型事件监听
        setFdEvents(ALOOPER_EVENT_INPUT);
        return 1;
    }
    return 1;
}

当时我们分析的函数第一部分,即处理ALOOPER_EVENT_INPUT事件的部分,现在我们来看看第二部分,处理ALOOPER_EVENT_OUTPUT事件的部分,首先遍历mFinishQueue,取出每一个Finish结构体,并调用InputConsumersendFinishedSignal,可以看到,就算之前的finishInputEvent函数中,向InputDispatcher发送事件处理完成的信号失败,也会将输入事件信息保存下来,待下一次应用程序处理输入事件时,会再次调用InputConsumersendFinishedSignal函数通知InputDispatcher,最后成功通知到InputDispatcher便会清空mFinishQueue,并移除ALOOPER_EVENT_OUTPUT类型事件监听。

接着继续分析InputConsumersendFinishedSignal函数:

InputConsumer::sendFinishedSignal

status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
    ...

    // Send finished signal for the last message in the batch.
    return sendUnchainedFinishedSignal(seq, handled);
}

这函数里面的一些细节我就省略了,这里接着调用了sendUnchainedFinishedSignal函数:

InputConsumer::sendUnchainedFinishedSignal

status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
    InputMessage msg;
    msg.header.type = InputMessage::Type::FINISHED;
    msg.body.finished.seq = seq;
    msg.body.finished.handled = handled ? 1 : 0;
    return mChannel->sendMessage(&msg);
}

这里通过InputChannelsendMessage函数将消息发送给InputDispatcher,上述InputMessage中的type为FINISHED
handled
按照我们前面的假设,为1,意味这输入事件成功处理。
前面InputDispatcher发送消息给应用程序也是同样的方式,所以说InputChannel是连接应用程序和InputDispatcher的纽带。

我们来到InputDispatcher,看看收到消息之后的逻辑:

InputDispatcher::handleReceiveCallback

int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
    InputDispatcher* d = static_cast<InputDispatcher*>(data);

    { // acquire lock
        std::scoped_lock _l(d->mLock);
        //注册过的InputChannel都会被保存到mConnectionsByFd
        //这个map中,以InputChannel的fd为key,Connection为value
        if (d->mConnectionsByFd.find(fd) == d->mConnectionsByFd.end()) {
            //异常情况,mConnectionsByFd中没有对应fd
            return 0; // 移除此Looper回调
        }
        
        bool notify;
        sp<Connection> connection = d->mConnectionsByFd[fd];
        if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
            if (!(events & ALOOPER_EVENT_INPUT)) {
                 //异常情况
                return 1;
            }

            nsecs_t currentTime = now();
            bool gotOne = false;
            status_t status;
            //核心部分
            for (;;) {
                uint32_t seq;
                bool handled;
                status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
                if (status) {
                    break;
                }
                d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
                gotOne = true;
            }
            if (gotOne) {
                d->runCommandsLockedInterruptible();
                if (status == WOULD_BLOCK) {
                    return 1;
                }
            }
            ...
        } else {
            //Looper发生异常的情况,不考虑
            ....
        }
        //注销inputChannel
        d->unregisterInputChannelLocked(connection->inputChannel, notify);
        return 0; //移除Looper回调
    }             // release lock
}

此函数的核心有三个函数,receiveFinishedSignalfinishDispatchCycleLockedrunCommandsLockedInterruptible,我们依次来分析:

InputPublisher::receiveFinishedSignal

status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
    InputMessage msg;
    status_t result = mChannel->receiveMessage(&msg);
    if (result) {
        *outSeq = 0;
        *outHandled = false;
        return result;
    }
    if (msg.header.type != InputMessage::Type::FINISHED) {
        //异常情况
        return UNKNOWN_ERROR;
    }
    *outSeq = msg.body.finished.seq;
    *outHandled = msg.body.finished.handled == 1;
    return OK;
}

这个函数很简单,就是获取前面应用程序通过sendMessage发送给InputDispatcherInputMessage对象,主要获取的是seqhandled这两个值。

InputDispatcher::finishDispatchCycleLocked

void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
                                                const sp<Connection>& connection, uint32_t seq,
                                                bool handled) {
    ...

    if (connection->status == Connection::STATUS_BROKEN ||
        connection->status == Connection::STATUS_ZOMBIE) {
        //异常情况
        return;
    }

    // Notify other system components and prepare to start the next dispatch cycle.
    onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
}

InputDispatcher::onDispatchCycleFinishedLocked

void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
                                                    const sp<Connection>& connection, uint32_t seq,
                                                    bool handled) {
    std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
            &InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
    commandEntry->connection = connection;
    commandEntry->eventTime = currentTime;
    commandEntry->seq = seq;
    commandEntry->handled = handled;
    postCommandLocked(std::move(commandEntry));
}

CommandEntry描述了一条指令,在InputDispatcher中,函数的调度很多都是以指令的形式,其用法大致为:首先构造一个CommandEntry结构体,向其中传入一个函数指针以及其他信息,然后通过函数postCommandLockedCommandEntry加入指令队列mCommandQueue,这个队列会在runCommandsLockedInterruptible函数中遍历并执行其函数指针指向的函数,这里即是doDispatchCycleFinishedLockedInterruptible函数。

InputDispatcher::runCommandsLockedInterruptible

bool InputDispatcher::runCommandsLockedInterruptible() {
    if (mCommandQueue.empty()) {
        return false;
    }

    do {
        std::unique_ptr<CommandEntry> commandEntry = std::move(mCommandQueue.front());
        mCommandQueue.pop_front();
        Command command = commandEntry->command;
        command(*this, commandEntry.get()); // commands are implicitly 'LockedInterruptible'

        commandEntry->connection.clear();
    } while (!mCommandQueue.empty());
    return true;
}

可以看到,这里会取出所有的CommandEntrycommand类型为std::function<void(InputDispatcher&, CommandEntry*),调用command就相当于执行构造CommandEntry时传入的函数指针,即doDispatchCycleFinishedLockedInterruptible函数。

InputDispatcher::doDispatchCycleFinishedLockedInterruptible

void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) {
    sp<Connection> connection = commandEntry->connection;
    const nsecs_t finishTime = commandEntry->eventTime;
    uint32_t seq = commandEntry->seq;
    const bool handled = commandEntry->handled;

    //遍历waitQueue,找到此次完成处理的输入事件,waitQueue用来存储待应用程序处理的输入事件
    std::deque<DispatchEntry*>::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq);
    if (dispatchEntryIt == connection->waitQueue.end()) {
        //如果waitQueue中没有此次完成处理的输入事件,直接return
        return;
    }
    DispatchEntry* dispatchEntry = *dispatchEntryIt;
    //用输入事件处理完成的时间减去此事件分发的时间就得到了处理此次事件的总耗时
    const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
    if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
        //SLOW_EVENT_PROCESSING_WARNING_TIMEOUT为2s,这里会打印耗时超过2s的窗口与事件信息
        ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(),
              ns2ms(eventDuration), dispatchEntry->eventEntry->getDescription().c_str());
    }
    //待实现的函数
    reportDispatchStatistics(std::chrono::nanoseconds(eventDuration), *connection, handled);

    bool restartEvent;
   //restartEvent决定是否将事件再次分发
    if (dispatchEntry->eventEntry->type == EventEntry::Type::KEY) {
        KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
         //对于KEY或者MOTION是否需要再次分发给应用程序
        restartEvent =
                afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled);
    } else if (dispatchEntry->eventEntry->type == EventEntry::Type::MOTION) {
        MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
         //对于KEY或者MOTION是否需要再次分发给应用程序
        restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry,
                                                           handled);
    } else {
        restartEvent = false;
    }

    // Dequeue the event and start the next cycle.
    // Because the lock might have been released, it is possible that the
    // contents of the wait queue to have been drained, so we need to double-check
    // a few things.
    dispatchEntryIt = connection->findWaitQueueEntry(seq);
    if (dispatchEntryIt != connection->waitQueue.end()) {
        dispatchEntry = *dispatchEntryIt;
        //将输入事件从waitQueue中移除
        connection->waitQueue.erase(dispatchEntryIt);
        //重置ANR时间
        mAnrTracker.erase(dispatchEntry->timeoutTime,
                          connection->inputChannel->getConnectionToken());
         ...
        if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
            //需要再次分发,则重新将此输入事件加入outboundQueue
            connection->outboundQueue.push_front(dispatchEntry);
        } else {
            //释放事件
            releaseDispatchEntry(dispatchEntry);
        }
    }

    //开始下一轮事件分发
    startDispatchCycleLocked(now(), connection);
}

此函数主要做了这么几件事:

  1. 对于处理超过2s的事件,打印log信息。
  2. 对于KEY或者MOTION需要判断是否再次分发给应用程序。
  3. 将输入事件从waitQueue移除并重置ANR时间。
  4. 对于步骤2结果,如果需要再次分发,则重新将此事件加入outboundQueue
  5. 调用startDispatchCycleLocked开始下一轮事件分发。

限于篇幅,对于步骤2,就不去分析了,另外,startDispatchCycleLocked函数是已经在
AndroidR Input子系统(7)InputDispatcher线程分发输入事件
详细分析过了。

最后对整个流程进行一下总结:

  1. 首先InputDispatcher通过server端InputChannel将输入事件发送给应用程序的client端。
  2. client端收到输入事件,会在UI线程中调用向Looper注册的回调handleEventhandleEvent主要是通过consumeEvents进一步处理事件。
  3. 输入事件在native层被转换为KeyEvent或者MotionEvent后会发送到java层InputEventReceiverdispatchInputEvent方法,实际上最终是送到其子类WindowInputEventReceiveronInputEvent方法来处理。
  4. ViewRootImpl作为Android上层事件分发的起点,其中定义了多种InputStage来将事件分类处理,采用责任链模式,将每个InputStage实现类通过mNext变量连接起来,InputStage通过deliver分发事件,通过onProcess处理事件,通过forwardmNext传递事件.
  5. mNext指向null时则会调用finishInputEvent结束事件,之后会调到native层的InputConsumersendFinishedSignal函数,最终还是通过client端InputChannelsendMessage通知InputDispatcher事件已经处理完成。
  6. InputDispatcher这边的收尾工作主要就是将此事件从waitQueue移除并重置ANR时间。
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值