概述:
本文主要描述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的事件分发流程;