前言:书接上回,上回梳理了SystemServer进程的输入管理服务(InputManagerService)的初始化,讲解了native层从接收到事件到分发事件到Java层的流程。本章节将从ViewRootImpl
的WindowInputEventReceiver
开始讲起,重点梳理客户端app进程内对于输入事件的分发与消费。
1. ViewRootImpl
在应用进程的Java层中,最先收到输入事件的Java类就是ViewRootImpl
的内部类WindowInputEventReceiver
,WindowInputEventReceiver
继承自抽象类InputEventReceiver
,上回说到客户端进程的native层调用了InputEventReceiver
对象的dispatchInputEvent
方法:
InputEventReceiver.java
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
@Override
public void onInputEvent(InputEvent event) {
...
//这个对象用于M版本以下的兼容,M版本及以上默认为null
if (processedEvents != null) {
...
} else {
enqueueInputEvent(event, this, 0, true);
}
}
}
enqueueInputEvent
是ViewRootImpl
这个类的方法,负责将新收到的输入事件插入一个待处理输入事件队列的队尾,并分别用mPendingInputEventHead
和mPendingInputEventTail
指向队头和队尾,如果没有待处理输入事件,则这个新收到的输入事件就同时是队头和队尾了:
ViewRootImpl.java
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
...
QueuedInputEvent last = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
mPendingInputEventCount += 1;
if (processImmediately) {
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}
void doProcessInputEvents() {
while (mPendingInputEventHead != null) {
//从待处理输入事件队列的队头取出输入事件
QueuedInputEvent q = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
if (mPendingInputEventHead == null) {
mPendingInputEventTail = null;
}
q.mNext = null;
mPendingInputEventCount -= 1;
mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent));
//继续传递输入事件
deliverInputEvent(q);
}
...
}
private void deliverInputEvent(QueuedInputEvent q) {
...
InputStage stage;
//是否不交由后续流程处理,而是直接内部处理
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
//正常流程走这里,判断是否需要优先传给输入法处理
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
...
if (stage != null) {
handleWindowFocusChanged();
stage.deliver(q);
} else {
finishInputEvent(q);
}
...
}
我们考虑正常的屏幕Touch事件传输流程,则不会优先传给输入法处理,而是使用mFirstPostImeInputStage
的deliver
方法进行处理。这一套处理流程是采用了类似责任链的设计模式,可以看一下是怎么设计的:
ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId)) {
...
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
通过将其自身作为另一个InputStage
构造函数的参数传进去,对于每个事件,依次流转看看哪个InputStage
能够消费该事件,所以事件的传递流程是:
EarlyPostImeInputStage
-> NativePostImeInputStage
-> ViewPostImeInputStage
-> SyntheticInputStage
。
其中每个环节如果没有自己消费掉事件,就会传递给下一环节进行处理,如果消费了,则不会给下一环节进行处理。
2. ViewRootImpl -> DecorView -> Activity
我们直接看ViewPostImeInputStage
的事件处理,因为我们熟悉的Activity、View等收到的输入事件就是从这个环节分发下去的:
ViewRootImpl.java
final class ViewPostImeInputStage extends InputStage {
@Override
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);
}
}
}
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
//先分发给手写模式处理,判断是否是手写区域的事件
boolean handled = mHandwritingInitiator.onTouchEvent(event);
if (handled) {
mLastClickToolType = event.getToolType(event.getActionIndex());
}
mAttachInfo.mUnbufferedDispatchRequested = false;
mAttachInfo.mHandlingPointerEvent = true;
//如果手写模式处理器没有消费该事件,则将事件分发给DecorView
handled = handled || mView.dispatchPointerEvent(event);
maybeUpdatePointerIcon(event);
maybeUpdateTooltip(event);
mAttachInfo.mHandlingPointerEvent = false;
if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
mUnbufferedInputDispatch = true;
if (mConsumeBatchedInputScheduled) {
scheduleConsumeBatchedInputImmediately();
}
}
//如果View选择消费,则事件分发到此为止,否则继续向下个环节分发。
return handled ? FINISH_HANDLED : FORWARD;
}
}
在ViewPostImeInputStage
中,会将事件分发给DecorView
的dispatchPointerEvent
,这是父类View
的方法,但DecorView
并没有重写,所以回到View
里看:
View.java
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
如果是touch输入事件,则传给dispatchTouchEvent
方法,这个方法DecorView
重写了:
DecorView.java
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
这个Window.CallBack
其实是Activty
对象,Activity
实现了这个接口,在Activity
启动时的attach
方法里,将自身作为Window.CallBack
传给PhoneWindow
:
Activity.java
final void attach(...) {
...
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
mWindow.setCallback(this);
...
}
所以紧接着我们看到Activity
的dispatchTouchEvent
方法:
Activity.java
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
Activity
收到输入事件后会优先将其传给PhoneWindow
的superDispatchTouchEvent
方法处理,其内部就是传回给DecorView
继续处理。
但如果都没消费该事件,则最后会交给Activity自己的onTouchEvent
里判断是否需要消费。
PhoneWindow.java
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
DecorView.java
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
这里事件重新回到了DecorView
里进一步进行分发,DecorView
继承自FrameLayout
,是Activity
布局的顶层View,本质就是一个ViewGroup
。
所以从这里开始,输入事件进入了从ViewGroup
-> View
的分发流程了。
3. ViewGroup -> View
DecorView
的父类FrameLayout
并没有重写dispatchTouchEvent
这个方法,所以我们继续向上追溯FrameLayout
的父类ViewGroup
。
ViewGroup
的dispatchTouchEvent
这个方法非常重要,建议想要熟悉事件分发的同学一定要一行行代码理解清楚,面试官想要问得深一点就会从这里面入手,所以我们这里就不省略代码了,而是详细带大家一起看看:
ViewGroup.java
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//调试用,检查输入事件序列的自洽性,忽略
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
}
//无障碍用
if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
ev.setTargetAccessibilityFocus(false);
}
boolean handled = false;
//判断触摸事件是否符合安全策略,该方法可重写以定制
if (onFilterTouchEventForSecurity(ev)) {
final int action = ev.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
//如果是Down事件,重置本地一些变量、状态
if (actionMasked == MotionEvent.ACTION_DOWN) {
cancelAndClearTouchTargets(ev);
resetTouchState();
}
//下面就是判断是否需要拦截该事件的代码块
final boolean intercepted;
//如果是Down事件或者之前已经有子View消费了触摸事件,则才进入拦截判断流程,否则直接进行拦截,不再传给子View
//所以如果之前没有child消费Down事件,则后续的非Down事件默认采取拦截策略
if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
//判断是否被设置了FLAG_DISALLOW_INTERCEPT这个标志位,外部可调用requestDisallowInterceptTouchEvent方法设置该标志位
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
//如果没有设置该标志位,则需要判断是否拦截,否则就跳过拦截步骤
if (!disallowIntercept) {
//在onInterceptTouchEvent中判断是否需要拦截,自定义ViewGroup可重写以定制
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action);//重设action以防在上述步骤中被修改
} else {
intercepted = false;
}
} else {
intercepted = true;
}
if (intercepted || mFirstTouchTarget != null) {
ev.setTargetAccessibilityFocus(false);
}
//检查该事件是否该取消,不再处理,比如处于detached状态或者本身就是取消事件
final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL;
final boolean isMouseEvent = ev.getSource() == InputDevice.SOURCE_MOUSE;
final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0 && !isMouseEvent;
//指向消费该事件的目标View
TouchTarget newTouchTarget = null;
boolean alreadyDispatchedToNewTouchTarget = false;
//当事件没有被取消并且并没有本Viewgroup没有选择拦截该事件,则下面考虑分发给子View
if (!canceled && !intercepted) {
//如果该事件是用来给无障碍焦点目标处理的,则我们会将其给具有无障碍焦点的View进行处理
View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
? findChildWithAccessibilityFocus() : null;
//这里我们重点关注Down事件的特殊处理
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
final int actionIndex = ev.getActionIndex();
final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex) : TouchTarget.ALL_POINTER_IDS;
removePointersFromTouchTargets(idBitsToAssign);
final int childrenCount = mChildrenCount;
if (newTouchTarget == null && childrenCount != 0) {
final float x = ev.getXDispatchLocation(actionIndex);
final float y = ev.getYDispatchLocation(actionIndex);
//ViewGroup支持自定义子View们的绘制顺序,这个顺序也会影响到事件分发的顺序
final ArrayList<View> preorderedList = buildTouchDispatchChildList();
final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled();
final View[] children = mChildren;
//从前往后扫描所有子View,找到能够接收到该事件的child
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
//如果优先传给无障碍焦点目标,则遍历一直找到该View,如果不是这按照正常的事件分发流程进行
if (childWithAccessibilityFocus != null) {
if (childWithAccessibilityFocus != child) {
continue;
}
childWithAccessibilityFocus = null;
i = childrenCount;
}
//判断该child是否无法接收该事件,比如不满足可见性要求、事件坐标不在该child显示区域内
if (!child.canReceivePointerEvents() || !isTransformedTouchPointInView(x, y, child, null)) {
ev.setTargetAccessibilityFocus(false);
continue;
}
//先找到上次消费了touch事件的child,如果有,则将newTouchTarget指向它,还是指定它去处理事件,并跳出遍历
newTouchTarget = getTouchTarget(child);
if (newTouchTarget != null) {
newTouchTarget.pointerIdBits |= idBitsToAssign;
break;
}
resetCancelNextUpFlag(child);
//将事件传给child的dispatchTouchEvent处理,如果返回true即代表child已消费
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
mLastTouchDownTime = ev.getDownTime();
if (preorderedList != null) {
for (int j = 0; j < childrenCount; j++) {
if (children[childIndex] == mChildren[j]) {
mLastTouchDownIndex = j;
break;
}
}
} else {
mLastTouchDownIndex = childIndex;
}
mLastTouchDownX = x;
mLastTouchDownY = y;
//将newTouchTarget指向消费该事件的child,并且mFirstTouchTarget也会指向该child
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
ev.setTargetAccessibilityFocus(false);
}
if (preorderedList != null) preorderedList.clear();
}
//如果本次Down事件没有child选择消费,则考虑传给之前消费过Down事件的child试试,多指触摸会存在这种情况
if (newTouchTarget == null && mFirstTouchTarget != null) {
newTouchTarget = mFirstTouchTarget;
while (newTouchTarget.next != null) {
newTouchTarget = newTouchTarget.next;
}
newTouchTarget.pointerIdBits |= idBitsToAssign;
}
}
}
//分发事件给目标View,上述的逻辑已经筛选出是否存在可以消费该事件的目标View了
if (mFirstTouchTarget == null) {
//没有任何可以消费该事件的child,则将本ViewGroup看作一个普通的View,传给super.dispatchTouchEvent处理
handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS);
} else {
//存在可以消费该事件的child,有可能已经消费了,也有可能还没消费
TouchTarget predecessor = null;
TouchTarget target = mFirstTouchTarget;
while (target != null) {
final TouchTarget next = target.next;
//在上面的代码块里child有可能已经消费该事件了
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted;
//将touch事件传给child的dispatchTouchEvent方法
if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) {
handled = true;
}
//如果本次拦截该事件,则将cancel事件传给之前所有消费过Down事件的child
if (cancelChild) {
if (predecessor == null) {
mFirstTouchTarget = next;
} else {
predecessor.next = next;
}
target.recycle();
target = next;
continue;
}
}
//如果不拦截该事件,则将本事件依次传给之前所有消费过Down事件的child,不管消不消费都进行分发
predecessor = target;
target = next;
}
}
//如果是取消事件、Up事件或者悬停移动事件,则清除掉之前保存的已消费事件的View列表
if (canceled
|| actionMasked == MotionEvent.ACTION_UP
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
resetTouchState();
} else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
final int actionIndex = ev.getActionIndex();
final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
removePointersFromTouchTargets(idBitsToRemove);
}
}
if (!handled && mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
}
return handled;
}
/**
* child为空,则将事件传给child的dispatchTouchEvent方法,否则就默认传给本ViewGroup的super.dispatchTouchEvent方法
*/
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, View child, int desiredPointerIdBits) {
final boolean handled;
final int oldAction = event.getAction();
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
return handled;
}
final int oldPointerIdBits = event.getPointerIdBits();
final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
if (newPointerIdBits == 0) {
return false;
}
final MotionEvent transformedEvent;
if (newPointerIdBits == oldPointerIdBits) {
if (child == null || child.hasIdentityMatrix()) {
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
final float offsetX = mScrollX - child.mLeft;
final float offsetY = mScrollY - child.mTop;
event.offsetLocation(offsetX, offsetY);
handled = child.dispatchTouchEvent(event);
event.offsetLocation(-offsetX, -offsetY);
}
return handled;
}
transformedEvent = MotionEvent.obtain(event);
} else {
transformedEvent = event.split(newPointerIdBits);
}
if (child == null) {
handled = super.dispatchTouchEvent(transformedEvent);
} else {
final float offsetX = mScrollX - child.mLeft;
final float offsetY = mScrollY - child.mTop;
transformedEvent.offsetLocation(offsetX, offsetY);
if (! child.hasIdentityMatrix()) {
transformedEvent.transform(child.getInverseMatrix());
}
handled = child.dispatchTouchEvent(transformedEvent);
}
transformedEvent.recycle();
return handled;
}
View.java
public boolean dispatchTouchEvent(MotionEvent event) {
...
//如果该View设置了mOnTouchListener,则优先传给onTouch,不选择消费才会传给onTouchEvent方法
if (onFilterTouchEventForSecurity(event)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
...
return result;
}
整个流程涉及到几个重要流转方法:
dispatchTouchEvent
。负责事件的分发,ViewGroup和View都有。onInterceptTouchEvent
。负责事件的拦截。只有ViewGroup有,返回true,代表该ViewGroup想要拦截该事件不流转给child,child可以调用requestDisallowInterceptTouchEvent(true)来请求parent跳过拦截方法。onTouchEvent
。负责事件的消费处理。返回true,代表该View消费该事件。
简单的分发流程图如下:
简单来说,首先ViewGroup
会在dispatchTouchEvent
中接收到事件,其中会调用onInterceptTouchEvent
方法判断是否需要拦截该事件,如果不拦截,则依次按照一定的顺序遍历child列表,根据手指触摸的坐标、child的可见性等等条件筛选,调用child的dispatchTouchEvent
进行下一级的事件分发,如果child是ViewGroup
,则会将上面的流程在走一遍,如果是View
,则在View
的dispatchTouchEvent
中会调用onTouchEvent
方法进行事件的消费,如果child返回true代表消费该事件,如果返回false则代表不消费,就会将该事件交给本ViewGroup
的onTouchEvent
中进行消费。
如果以上流程中,ViewGroup
和View
都不选择消费,就最后交给Activity
的onTouchEvent
方法进行消费的判断:
Activity.java
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
4. 事件分发的结束
不管是哪个ViewGroup
或View
选择了消费还是Activity
选择是否消费,最后执行完还是回到ViewPostImeInputStage
里进行后续的处理。
ViwRootImpl.java
final class ViewPostImeInputStage extends InputStage {
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
//handled代表该事件是否被消费了
handled = handled || mView.dispatchPointerEvent(event);
...
//如果被消费,则返回的状态为FINISH_HANDLED,否则是FORWARD,继续下一层的分发处理
return handled ? FINISH_HANDLED : FORWARD;
}
}
返回到父类的deliver
方法,走到apply
里:
ViwRootImpl.java
abstract class InputStage {
public final void deliver(QueuedInputEvent q) {
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);
}
}
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);
}
}
protected void finish(QueuedInputEvent q, boolean handled) {
q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
if (handled) {
q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
}
forward(q);
}
protected void forward(QueuedInputEvent q) {
onDeliverToNext(q);
}
protected void onDeliverToNext(QueuedInputEvent q) {
...
if (mNext != null) {
mNext.deliver(q);
} else {
finishInputEvent(q);
}
}
}
如果选择了消费,则会走到finish
方法,并往QueuedInputEvent
里添加FLAG_FINISHED
和FLAG_FINISHED_HANDLED
标志位,前者标志位代表事件分发流程的结束,后者标志位表示事件被消费。最后走到了finishInputEvent
方法:
ViewRootImpl.java
private void finishInputEvent(QueuedInputEvent q) {
if (q.mReceiver != null) {
boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
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);
}
InputEventReceiver.java
public final void finishInputEvent(InputEvent event, boolean handled) {
...
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();
}
接着就会调用native方法nativeFinishInputEvent
来通知native层事件分发已结束。
android_view_InputEventReceiver.cpp
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);
...
}
status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
...
Finish finish{
.seq = seq,
.handled = handled,
};
mOutboundQueue.push_back(finish);
return processOutboundEvents();
}
NativeInputEventReceiver
会将一个Finish
事件插入mOutboundQueue
中,
android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::processOutboundEvents() {
while (!mOutboundQueue.empty()) {
OutboundEvent& outbound = *mOutboundQueue.begin();
status_t status;
//判断是否是Finish事件
if (std::holds_alternative<Finish>(outbound)) {
const Finish& finish = std::get<Finish>(outbound);
status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
}
...
}
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
接下来就是调用mInputConsumer
的sendFinishedSignal
方法,内部还是通过InputChannel
的sendMessage
方法,依靠socketpair方式将事件结束的信号发送给服务端SystemServer进程,完成跨进程通信:
InputTransport.cpp
status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
InputMessage msg;
msg.header.type = InputMessage::Type::FINISHED;
msg.header.seq = seq;
msg.body.finished.handled = handled;
msg.body.finished.consumeTime = getConsumeTime(seq);
status_t result = mChannel->sendMessage(&msg);
if (result == OK) {
popConsumeTime(seq);
}
return result;
}
SystemServer端接收该消息的回调函数是:
InputDispatcher.cpp
int InputDispatcher::handleReceiveCallback(int events, sp<IBinder> connectionToken) {
...
bool notify;
if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
...
for (;;) {
//从inputPublisher中取出客户端发来的事件
Result<InputPublisher::ConsumerResponse> result =
connection->inputPublisher.receiveConsumerResponse();
if (!result.ok()) {
status = result.error().code();
break;
}
//如果是Finished事件
if (std::holds_alternative<InputPublisher::Finished>(*result)) {
const InputPublisher::Finished& finish =
std::get<InputPublisher::Finished>(*result);
finishDispatchCycleLocked(currentTime, connection, finish.seq, finish.handled,
finish.consumeTime);
}
...
}
...
}
...
}
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
const std::shared_ptr<Connection>& connection,
uint32_t seq, bool handled, nsecs_t consumeTime) {
...
auto command = [this, currentTime, connection, seq, handled, consumeTime]() REQUIRES(mLock) {
doDispatchCycleFinishedCommand(currentTime, connection, seq, handled, consumeTime);
};
postCommandLocked(std::move(command));
}
void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime,
const std::shared_ptr<Connection>& connection,
uint32_t seq, bool handled,
nsecs_t consumeTime) {
//从waitQueue中取出对应序列的事件,如果没找到,则直接返回,流程结束
std::deque<DispatchEntry*>::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq);
if (dispatchEntryIt == connection->waitQueue.end()) {
return;
}
...
dispatchEntryIt = connection->findWaitQueueEntry(seq);
//从waitQueue中找到了对应序列的事件
if (dispatchEntryIt != connection->waitQueue.end()) {
dispatchEntry = *dispatchEntryIt;
//从待结束队列waitQueue中删除该事件
connection->waitQueue.erase(dispatchEntryIt);
const sp<IBinder>& connectionToken = connection->inputChannel->getConnectionToken();
//从ANR追踪器中删除该事件
mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken);
...
}
//开始下一个事件分发的流程
startDispatchCycleLocked(now(), connection);
}
waitingQueue
是专门用来保存将事件分发给客户端并等待客户端回复的队列。在waitingQueue
中找到该事件后,就从该队列中删除掉该事件,并开始下一个待分发事件的分发流程。
就此,一个事件的分发流程梳理完成了。