InputDispatcher将事件分发给应用程序后,将该event放入connection的wq队列中,APP处理完之后,需要发送一个完成的信号给InputDispatcher,以供InputDispatcher来将该event从wq队列中移除。我们来分析这个过程。
我们知道,事件在应用端的的处理过程是经过一系列的InputStage处理,当这些InputStage都处理完毕(不消费也算处理完毕)后,就会调用finishInputEvent来通知InputDispatcher。从finishInputEvent开始分析
//frameworks/base/core/java/android/view/ViewRootImpl.java
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);//1
} else {
q.mEvent.recycleIfNeededAfterDispatch();
}
recycleQueuedInputEvent(q);
}
注释1处, q.mReceiver为InputEventReceiver对象,调用其finishInputEvent方法
//frameworks/base/core/java/android/view/InputEventReceiver.java
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);//取出seq
mSeqMap.removeAt(index);
nativeFinishInputEvent(mReceiverPtr, seq, handled);//1,native方法
}
}
event.recycleIfNeededAfterDispatch();
}
先取出seq,这个seq是之前InputDispatcher发送事件的时候传递过来的的,后续可以通过seq在InputDispatcher中找到对应的event。注释1处调用native方法
//frameworks/base/core/jni/android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
//省略
status_t status = mInputConsumer.sendFinishedSignal(seq, handled);//发送完成的信号
//省略
return status;
}
通过sendFinishedSignal来向InputDispatcher发送事件处理完毕的消息
//frameworks/native/libs/input/InputTransport.cpp
status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
//省略
// Send finished signal for the last message in the batch.
return sendUnchainedFinishedSignal(seq, handled);
}
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);
}
可以看出,通过InputChanel发送消息
//frameworks/base/core/jni/android_view_InputEventReceiver.cpp
status_t InputChannel::sendMessage(const InputMessage* msg) {
size_t msgLength = msg->size();
ssize_t nWrite;
do {
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
向fd写入数据,那么InputDispatcher那边的fd就能接收到数据了,然后调用handleReceiveCallback。关于这部分,Android 11 输入系统之InputDispatcher和应用窗口建立联系一文中已经分析过了
//frameworks/native/services/inputflinger/InputDispatcher.cpp
int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
InputDispatcher* d = static_cast<InputDispatcher*>(data);//取出InputDispatcher对象
{ // acquire lock
AutoMutex _l(d->mLock);
ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);//根据fd取出index
if (connectionIndex < 0) {
ALOGE("Received spurious receive callback for unknown input channel. "
"fd=%d, events=0x%x", fd, events);
return 0; // remove the callback
}
bool notify;
sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);//取出connection
if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
//省略
nsecs_t currentTime = now();
bool gotOne = false;
status_t status;
for (;;) {
uint32_t seq;
bool handled;
status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);//1
if (status) {
break;
}
d->finishDispatchCycleLocked(currentTime, connection, seq, handled);//2
gotOne = true;
}
if (gotOne) {
d->runCommandsLockedInterruptible();
if (status == WOULD_BLOCK) {
return 1;
}
}
notify = status != DEAD_OBJECT || !connection->monitor;
if (notify) {
ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
connection->getInputChannelName().c_str(), status);
}
} else {
// Monitor channels are never explicitly unregistered.
// We do it automatically when the remote endpoint is closed so don't warn
// about them.
notify = !connection->monitor;
if (notify) {
ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. "
"events=0x%x", connection->getInputChannelName().c_str(), events);
}
}
// Unregister the channel.
d->unregisterInputChannelLocked(connection->inputChannel, notify);
return 0; // remove the callback
} // release lock
}
注释1处接收消息,得到seq。注释2处会调用onDispatchCycleFinishedLocked,向Commands队列中放入命令
//frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::onDispatchCycleFinishedLocked(
nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
commandEntry->connection = connection;
commandEntry->eventTime = currentTime;
commandEntry->seq = seq;
commandEntry->handled = handled;
}
队列执行时调用doDispatchCycleFinishedLockedInterruptible方法
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
CommandEntry* commandEntry) {
sp<Connection> connection = commandEntry->connection;
nsecs_t finishTime = commandEntry->eventTime;
uint32_t seq = commandEntry->seq;//得到seq
bool handled = commandEntry->handled;
// Handle post-event policy actions.
DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);//根据seq从wq中找出之前分发的事件
if (dispatchEntry) {
//省略
bool restartEvent;
if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
restartEvent = afterKeyEventLockedInterruptible(connection,
dispatchEntry, keyEntry, handled);
} else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
restartEvent = afterMotionEventLockedInterruptible(connection,
dispatchEntry, motionEntry, handled);//这个方法也是直接返回false
} else {
restartEvent = false;
}
// Dequeue the event and start the next cycle.
// Note that 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.
if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
connection->waitQueue.dequeue(dispatchEntry);//从wq队列中将事件移除
traceWaitQueueLengthLocked(connection);
//省略
// Start the next dispatch cycle for this connection.
startDispatchCycleLocked(now(), connection);//下一轮的派发
}
}
可以看出,当应用端事件处理完毕之后,需要告知InputDispatcher,InputDispatcher收到完成的消息后,会将该事件从wq队列中移除,然后进行下一轮事件的派发
总结
finishInputEvent的工作原理