上一篇文章分析到应用程序和InputDispatcher分别属于两个不同进程,他们之间的连接需要依靠InputChannel(内部通过一对socket实现)来建立,连接建立之后,InputDispatcher就可以将Input事件发送到应用程序的UI线程,而应用程序处理完事件之后也可以通过InputChannel通知到InputDispatcher。
整个过程总结如下:
- 首先当一个APP启动时,会将自己的
Window
添加到WMS,并传递一个空InputChannel
过去。 - WMS端,通过
openInputChannel
方法会创建一对InputChannel
,是在native层完成的,这对InputChannel
被分为“client”端和“server”端,其内部又会创建一对socket,和这对InputChannel
一一对应。 - “server”端
InputChannel
会被注册到InputDispatcher
中去,注册的原理就是将InputChannel
内部的socket添加到其Looper进行监听,注册过程中还会创建一个Connection
对象,Connection
用来描述InputDispatcher
与此次注册InputChannel
的窗口的连接。 - "client"端
InputChannel
会被设置到APP进程中,接着通过InputEventReceiver
注册到APP UI线程,同样是将InputChannel
内部的socket添加到UI线程的Looper进行监听。 - 对于
InputDispatcher
线程,在接收到"client"端socket的消息时会回调其handleReceiveCallback
函数,对于APP UI线程,在接收到"server"端socket的消息时会回调InputEventReceiver
对应的native层对象NativeInputEventReceiver
的handleEvent
函数。
本篇我们来看看事件发送到应用程序的UI线程之后,应用程序对事件的后续处理流程。
InputDispatcher
将事件发送出去依靠的是Looper监听了InputChannel
内部一对socket的server端和client端,InputDispatcher
向server端写入数据,对面client端就能收到消息并回调对应函数,对面指的就是应用程序的UI线程,回调函数则是NativeInputEventReceiver
的handleEvent
函数,我们以此函数为入口开始深入:
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);
}
}
}
此函数首先调用InputConsumer
的consume
函数来获得InputEvent
,对于按键类型事件的处理就非常简单了,然后将native层KeyEvent
转换为java层KeyEvent
,并调用java层InputEventReceiver.java
的dispatchInputEvent
方法将Input事件分发到java层。
接着来看看InputConsumer
的consume
函数:
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
发送过来的InputMessage
,InputMessage
封装了Input事件的各种信息,用这些信息填充了一个空的KeyEvent
。
因为我们分析的是按键事件,相对触摸事件,细节会简单很多,但流程是差不多的。
回到consumeEvents
函数,KeyEvent
得到之后就会调用InputEventReceiver.java
的dispatchInputEvent
方法将事件发送到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
的一众实现类在ViewRootImpl
的setView
中初始化:
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,所以得到的InputStage
为mFirstInputStage
,mFirstInputStage
对应上图中的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,并且没有被丢弃则会调用NativePreImeInputStage
的onProcess
方法,做具体的事件处理:
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事件的分发到此就结束了,接着我们要来看看应用程序处理完事件之后的逻辑了。
InputStage
的onDeliverToNext
方法用于将事件分发给下一个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);
}
此方法关键两步,其一调用InputEventReceiver
的finishInputEvent
方法,其二调用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
池未满,则将此对象加入对象池(对象池以链表形式保存回收的对象)。
接着重点来看InputEventReceiver
的finishInputEvent
方法,此方法接收两个参数,一个是此次完成的事件,另一个是此次事件是否被处理,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
发送输入事件给应用程序之后会回调NativeInputEventReceiver
的handleEvent
函数吗?我们再回头来看看此函数:
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
结构体,并调用InputConsumer
的sendFinishedSignal
,可以看到,就算之前的finishInputEvent
函数中,向InputDispatcher
发送事件处理完成的信号失败,也会将输入事件信息保存下来,待下一次应用程序处理输入事件时,会再次调用InputConsumer
的sendFinishedSignal
函数通知InputDispatcher
,最后成功通知到InputDispatcher
便会清空mFinishQueue
,并移除ALOOPER_EVENT_OUTPUT
类型事件监听。
接着继续分析InputConsumer
的sendFinishedSignal
函数:
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);
}
这里通过InputChannel
的sendMessage
函数将消息发送给InputDispatcher
,上述InputMessage
中的type为FINISHED
,
按照我们前面的假设,为1,意味这输入事件成功处理。
handled
前面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
}
此函数的核心有三个函数,receiveFinishedSignal
,finishDispatchCycleLocked
,runCommandsLockedInterruptible
,我们依次来分析:
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
发送给InputDispatcher
的InputMessage
对象,主要获取的是seq
和handled
这两个值。
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
结构体,向其中传入一个函数指针以及其他信息,然后通过函数postCommandLocked
将CommandEntry
加入指令队列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;
}
可以看到,这里会取出所有的CommandEntry
,command
类型为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);
}
此函数主要做了这么几件事:
- 对于处理超过2s的事件,打印log信息。
- 对于KEY或者MOTION需要判断是否再次分发给应用程序。
- 将输入事件从
waitQueue
移除并重置ANR时间。 - 对于步骤2结果,如果需要再次分发,则重新将此事件加入
outboundQueue
。 - 调用
startDispatchCycleLocked
开始下一轮事件分发。
限于篇幅,对于步骤2,就不去分析了,另外,startDispatchCycleLocked
函数是已经在
AndroidR Input子系统(7)InputDispatcher线程分发输入事件
详细分析过了。
最后对整个流程进行一下总结:
- 首先
InputDispatcher
通过server端InputChannel
将输入事件发送给应用程序的client端。 - client端收到输入事件,会在UI线程中调用向Looper注册的回调
handleEvent
,handleEvent
主要是通过consumeEvents
进一步处理事件。 - 输入事件在native层被转换为
KeyEvent
或者MotionEvent
后会发送到java层InputEventReceiver
的dispatchInputEvent
方法,实际上最终是送到其子类WindowInputEventReceiver
的onInputEvent
方法来处理。 - ViewRootImpl作为Android上层事件分发的起点,其中定义了多种
InputStage
来将事件分类处理,采用责任链模式,将每个InputStage
实现类通过mNext
变量连接起来,InputStage
通过deliver
分发事件,通过onProcess
处理事件,通过forward
向mNext
传递事件. - 当
mNext
指向null时则会调用finishInputEvent
结束事件,之后会调到native层的InputConsumer
的sendFinishedSignal
函数,最终还是通过client端InputChannel
的sendMessage
通知InputDispatcher
事件已经处理完成。 InputDispatcher
这边的收尾工作主要就是将此事件从waitQueue
移除并重置ANR时间。