概述:
????????本文主要描述View對InputEvent事件pipeline處理過程。
本文涉及的源碼路徑
frameworks/base/core/java/android/view/ViewRootImpl.java
InputEvent事件處理
View處理input事件是調用doProcessInputEvents方法,如下所示:
void doProcessInputEvents() {// Deliver all pending input events in the queue.while (mPendingInputEventHead != null) {QueuedInputEvent q = mPendingInputEventHead;/* 更新事件處理的位置 */mPendingInputEventHead = q.mNext;/* 處理到了隊列的尾部 */if (mPendingInputEventHead == null) {mPendingInputEventTail = null;}q.mNext = null;......deliverInputEvent(q);}......}
該方法的核心實現邏輯如下:
1、從事件隊列中取出一個待處理的Input事件;
2、調用deliverInputEvent()進行處理;
3、處理完所有事件后,退出循環體;
我們繼續講解deliverInputEvent方法,實現如下:
private void deliverInputEvent(QueuedInputEvent q) {......InputStage stage;if (q.shouldSendToSynthesizer()) {stage = mSyntheticInputStage;} else {stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;}/* 開啟事件分發 */if (stage != null) {stage.deliver(q);} else {finishInputEvent(q);}}
該方法,根據事件q設置的flag,從InputStage Pipeline的不同起點,開始處理input事件,為了簡化敘述,我們從點擊觸摸屏輸入事件的處理講起。我跳過輸入法相關,流水線的處理起點為mFirstPostImeInputStage,也就是earlyPostImeStage。
InputEvent事件處理Pipeline
承接上文,我們開始將入inputEvent事件的處理Pipeline,前面的文章我們已經講述了InputStage的處理模型,因此不再詳解講述每一個pipeline被調用到的過程,我們只講述每一級中核心方法onProcess。 為了簡化講述的過程,我們跳過與輸入法相關的,流水線起點為earlyPostImeStage
1、EarlyPostImeStage
調用EarlyPostImeInputStage類中的process方法,如下所示:
protected int onProcess(QueuedInputEvent q) {if (q.mEvent instanceof KeyEvent) {return processKeyEvent(q);} else {final int source = q.mEvent.getSource();if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {return processPointerEvent(q);}}return FORWARD;}
我們只關注觸摸事件,因此直接調用processPointerEvent()進行處理,這部分代碼不再展開詳細描述,當EarlyPostImeInputStage處理完inputEvent后,返回FORWARD,表示將該inputEvent事件傳遞給下一級的流水線進行處理,也就是NativePostImeInputStage處理。
2、NativePostImeInputStage
調用NativePostImeInputStage中的onProcess方法,如下所示:
protected int onProcess(QueuedInputEvent q) {if (mInputQueue != null && q.mEvent instanceof KeyEvent) {mInputQueue.sendInputEvent(q.mEvent, q, true, this);return DEFER;}return FORWARD;}
該方法只處理按鍵事件,其他事件直接轉發,事件傳遞給下一級的流水線進行處理,也就是ViewPostImeInputStage
3、ViewPostImeInputStage
調用ViewPostImeInputStage中的onProcess方法,如下所示:
protected int onProcess(QueuedInputEvent q) {if (q.mEvent instanceof KeyEvent) {return processKeyEvent(q);} else {final int source = q.mEvent.getSource();if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {return processPointerEvent(q);} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {return processTrackballEvent(q);} else {return processGenericMotionEvent(q);}}}
我們只關注觸摸事件,直接調用processPointerEvent進行處理,如下所示:
private int processPointerEvent(QueuedInputEvent q) {final MotionEvent event = (MotionEvent)q.mEvent;mAttachInfo.mUnbufferedDispatchRequested = false;final View eventTarget =(event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?mCapturingView : mView;mAttachInfo.mHandlingPointerEvent = true;boolean handled = eventTarget.dispatchPointerEvent(event);maybeUpdatePointerIcon(event);mAttachInfo.mHandlingPointerEvent = false;if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {mUnbufferedInputDispatch = true;if (mConsumeBatchedInputScheduled) {scheduleConsumeBatchedInputImmediately();}}return handled ? FINISH_HANDLED : FORWARD;}
該方法的核心邏輯如下:
1、找到傳遞事件的Viw視圖入口。這里事件在Android UI窗口處理的起點是Activity。我們下一章進行講解,這里先暫時跳過;
2、根據處理結果,如果事件被處理了,返回FINISH_HANDLED,不再向下一級的流水線傳遞,如果沒有處理,則直接轉發到下一級的流水線處理,也就是SyntheticInputStage,為了簡化敘述,我們這里假設input事件被處理了,則apply的對返回結果的處理如下所示:
protected void apply(QueuedInputEvent q, int result) {if (result == FORWARD) {forward(q);} else if (result == FINISH_HANDLED) {finish(q, true);} else if (result == FINISH_NOT_HANDLED) {finish(q, false);} else {throw new IllegalArgumentException("Invalid result: " + result);}}
由于事件已經被處理,所以直接調用finish,如下所示:
protected void finish(QueuedInputEvent q, boolean handled) {q.mFlags |= QueuedInputEvent.FLAG_FINISHED;if (handled) {q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;}// 當前InputStage不再處理,直接轉發forward(q);}
finish中標記inputEvent事件被處理標記,然后再次調用forward,最終調用到了onDeliverToNext接口,如下所示:
protected void onDeliverToNext(QueuedInputEvent q) {if (DEBUG_INPUT_STAGES) {Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);}if (mNext != null) {mNext.deliver(q);} else {finishInputEvent(q);}}
最終調用的是SyntheticInputStage中onDeliverToNext方法,如下所示:
protected void onDeliverToNext(QueuedInputEvent q) {......super.onDeliverToNext(q);}
然后有調用到了父類的onDeliverToNext,也就是InputStage中的onDeliverToNext方法,此時流水線已經到達了末端,然后進入到finishInputEvent方法如下所示:
private void finishInputEvent(QueuedInputEvent q) {Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",q.mEvent.getSequenceNumber());if (q.mReceiver != null) {boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;q.mReceiver.finishInputEvent(q.mEvent, handled);} else {q.mEvent.recycleIfNeededAfterDispatch();}recycleQueuedInputEvent(q);}
核心邏輯就是調用finishInputEvent進行收尾工作,方法如下所示:
public final void finishInputEvent(InputEvent event, boolean handled) {......} 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();}
核心就是調用JNI層中的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);if (status && status != DEAD_OBJECT) {String8 message;message.appendFormat("Failed to finish input event. status=%d", status);jniThrowRuntimeException(env, message.string());}
}
繼續調用finishInputEvent方法,我們進一步追蹤,最終調用到了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;return mChannel->sendMessage(&msg);
}
????????這里又看到了熟悉的InputChannel的東西,最后將結束處理的信息通過夸進程通知到了InputDispatcher;然后觸發epoll事件,調用到handleReceiveCallback方法進行處理完事件的清理工作,這里不再展開描述;
總結
????????本文描述了Android系統中View對輸入事件的處理流程,也就是pipeline事件的處理過程。然后最終將處理結果通過跨進程傳遞給了InputDispatcher。下一章,我們講述View UI的事件分發流程;