入口 dispatchOnce
整体 touch 事件的分发都由 InputDispatcher 的 dispatchOnce() 开始(InputReader 负责读事件,不负责分发)
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
// 判断 mCommandQueue 中是否有值,如果有就先执行 command
if (!haveCommandsLocked()) {
// 真正分发
dispatchOnceInnerLocked(&nextWakeupTime);
}
// If we are still waiting for ack on some events,
// we might have to wake up earlier to check if an app is anr'ing.
// 计算应用被阻塞多久。这与 java 层 Handler 原理一样
// 没有当前要处理的消息时,会被阻塞。阻塞的时长由最近一个要处理的消息时间决定
const nsecs_t nextAnrCheck = processAnrsLocked();
nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);
// We are about to enter an infinitely long sleep, because we have no commands or
// pending or queued events
if (nextWakeupTime == LONG_LONG_MAX) {
mDispatcherEnteredIdle.notify_all();
}
} // release lock
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
// 通过 epoll 机制阻塞当前线程若干时间。如果中途有别的事件,会主动唤醒
mLooper->pollOnce(timeoutMillis);
}
涉及到两个很重要的方法 dispatchOnceInnerLocked 与 processAnrsLocked,前者负责分发,后者会在超时时处理 anr。
分发
dispatchOnceInnerLocked
会首先从 mInboundQueue 取出一个事件(该 queue 中的事件由 InputReader 放入),同时使用 mPendingEvent 记录下该事件。随后根据事件类型调用不同的方法进行分发。此处以 key 事件为例,调用 dispatchKeyLocked
dispatchKeyLocked
首先调用 findFocusedWindowTargetsLocked 找到可以处理的窗口,然后调用 dispatchEventLocked 再进行分发,后者最主要是调用 prepareDispatchCycleLocked,然后到 enqueueDispatchEntriesLocked
enqueueDispatchEntriesLocked
主要是将事件添加至 connection 的 outboundQueue 中,然后调用 startDispatchCycleLocked
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection,
std::shared_ptr<EventEntry> eventEntry,
const InputTarget& inputTarget) {
// 通过 connection,Ims 可以将事件发送给应用进程
bool wasEmpty = connection->outboundQueue.empty();
// Enqueue dispatch entries for the requested modes.
// 将 eventEntry 添加到 connection->outboundQueue 中
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.empty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
startDispatchCycleLocked
该方法会真正通过 connection 将事件发给应用端,同时会将事件记录到 waitQueue 中。
// Re-enqueue the event on the wait queue.
// 从 outboundQueue 中删除
connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
connection->outboundQueue.end(),
dispatchEntry));
traceOutboundQueueLength(*connection);
// 加入到 waitQueue 中
connection->waitQueue.push_back(dispatchEntry);
if (connection->responsive) {
// 将事件添加至 mAnrTracker 中
mAnrTracker.insert(dispatchEntry->timeoutTime,
connection->inputChannel->getConnectionToken());
}
三个队列
touch 事件的整个流程中涉及到三个 queue:
mInboundQueue:由InputReader添加,由InputDispatcher消费。存储的是InputDispatcher需要分发出去的事件outboundQueue:由InputDispatcher添加,由connection消费,它会将这里面的事件依次发给应用进程waitQueue:connection将事件分发给应用进程后,会将事件暂存在该队列中,只有当应用端处理完成后才会从该队列中移除。
anr
关于这部分源码分析可看 gityuan 的文章
它的触发逻辑也在 dispatchOnce 中,它会调用 processAnrsLocked
nsecs_t InputDispatcher::processAnrsLocked() {
const nsecs_t currentTime = now();
nsecs_t nextAnrCheck = LONG_LONG_MAX;
// Check if we are waiting for a focused window to appear. Raise ANR if waited too long
// Check if any connection ANRs are due
// 获取 mAnrTracker 记录的第一个事件的过时时间
nextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout());
// 如果没有过时,就意味着并没有 anr 发生
// 所以 InputDispatcher 就可以休息一段时间
if (currentTime < nextAnrCheck) { // most likely scenario
return nextAnrCheck; // everything is normal. Let's check again at nextAnrCheck
}
// If we reached here, we have an unresponsive connection.
sp<Connection> connection = getConnectionLocked(mAnrTracker.firstToken());
connection->responsive = false;
// Stop waking up for this unresponsive connection
mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());
// 触发 anr 逻辑
onAnrLocked(connection);
return LONG_LONG_MIN;
}
onAnrLocked
最核心的逻辑
// dump anr 相关的日志
updateLastAnrStateLocked(getWindowHandleLocked(connectionToken), reason);
// 最关键的是调用 sendWindowUnresponsiveCommandLocked
processConnectionUnresponsiveLocked(*connection, std::move(reason));
processConnectionUnresponsiveLocked
构建一个 command,然后调用 postCommandLocked
void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp<IBinder>& token,
std::optional<int32_t> pid,
std::string reason) {
auto command = [this, token, pid, reason = std::move(reason)]() REQUIRES(mLock) {
scoped_unlock unlock(mLock);
// command 的主要执行逻辑。
// 它是调用 NativeInputManager::notifyWindowUnresponsive
mPolicy->notifyWindowUnresponsive(token, pid, reason);
};
// 它会将 command 放到 mCommandQueue 中
postCommandLocked(std::move(command));
}
回到最上面的 dispatchOnce 中,可以发现该 command 会先于事件执行。
现在流程到了 com_android_server_input_InputManagerService#notifyWindowUnresponsive,它里面会通过 Jni 调用到 java 层的 InputManagerService 的 notifyWindowUnresponsive
private void notifyWindowUnresponsive(IBinder token, int pid, boolean isPidValid,
String reason) {
// mWindowManagerCallbacks 只有 IMS#setWindowManagerCallbacks() 中被赋值
mWindowManagerCallbacks.notifyWindowUnresponsive(token,
isPidValid ? OptionalInt.of(pid) : OptionalInt.empty(), reason);
}
// SystemServer 中
// IMS 的初始化在 SystemServer 中,setWindowManagerCallbacks 也在 SystemServer 中调用
// wm 是 WindowManagerService 对象,返回的就是 InputManagerCallback 对象
inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
所以 anr 的处理到 InputManagerCallback 的 notifyWindowUnresponsive 中,最终到 AMS 的 inputDispatchingTimedOut 中。新版本中再经过各种辗转到 ProcessErrorStateRecord 的 appNotResponding,这里面的主要逻辑与 gityuan 类似。
应用端的回传
应用端通过
NativeInputEventReceiver::finishInputEvent告知 ims 事件已消费
应用端在处理完 touch 事件后,需要通知到 ims,把事件从 waitQueue 中删除。现在就看一下应用端是如何处理的。
我们知道 ViewRootImpl 的 setView 会调用到 WMS,由 WMS 构建一个 socketpair,其中一个 fd 传给应用端,另一个传给 ims。当 ims 中有消息需要处理时,就是通过 socketpair 传递给应用端的,也就是第一部分中 connection 内部的实现方式。
// ViewRootImpl#setView
// 此时 inputChannel 已经被填充了 socketpair 中的一个 fd
mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
Looper.myLooper());
构建一个 WindowInputEventReceiver 对象,它继承于 InputEventReceiver。后者在构造函数中会调用 nativeInit,然后在 native 层构造一个 NativeInputEventReceiver 对象,接着调用它的 initialize 方法。
status_t NativeInputEventReceiver::initialize() {
// 向 native 层的 looper 添加一个 fd
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
// mInputConsumer 就是 InputChannel,所以这里是将 wms 生成的 socketpair 中的 fd 注册到本进程的 looper 中
// 当 ims 有消息传来时,就会执行到自己的 handleEvent() 方法
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
// 将 callback 注册成自己,所以事件到来时会调用自己的 handleEvent()
mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}
NativeInputEventReceiver 的 handleEvent 会调用 consumeEvents,该方法的具体分析见链接,最终到 java 层 InputEventReceiver 的 dispatchInputEvent,后面经过各种 stage 到具体的 view 处理。
touch 事件经过中间的各种处理后,最终会到 InputEventReceiver 的 finishInputEvent,然后到 NativeInputEventReceiver::finishInputEvent
status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
Finish finish{
.seq = seq,
.handled = handled,
};
mOutboundQueue.push_back(finish);
// 会遍历 mOutboundQueue,如果是 Finish,就会调用
// mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
return processOutboundEvents();
}
status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
// Send finished signals for the batch sequence chain first.
size_t seqChainCount = mSeqChains.size();
if (seqChainCount) {
uint32_t currentSeq = seq;
uint32_t chainSeqs[seqChainCount];
size_t chainIndex = 0;
for (size_t i = seqChainCount; i > 0; ) {
i--;
const SeqChain& seqChain = mSeqChains[i];
if (seqChain.seq == currentSeq) {
currentSeq = seqChain.chain;
chainSeqs[chainIndex++] = currentSeq;
mSeqChains.erase(mSeqChains.begin() + i);
}
}
status_t status = OK;
while (!status && chainIndex > 0) {
chainIndex--;
status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
}
if (status) {
// An error occurred so at least one signal was not sent, reconstruct the chain.
for (;;) {
SeqChain seqChain;
seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
seqChain.chain = chainSeqs[chainIndex];
mSeqChains.push_back(seqChain);
if (!chainIndex) break;
chainIndex--;
}
return status;
}
}
// Send finished signal for the last message in the batch.
return sendUnchainedFinishedSignal(seq, handled);
}
InputConsumer::sendFinishedSignal 最核心的一点就是调用 sendUnchainedFinishedSignal
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);
// 通过 channel 发送,最终到 InputDispatcher 中
status_t result = mChannel->sendMessage(&msg);
return result;
}
InputDispatcher 中经历最终到 InputDispatcher::handleReceiveCallback,后者调用 finishDispatchCycleLocked,它又会构建一个 command。在 handleReceiveCallback 中还会调用 runCommandsLockedInterruptable() 这个方法就会触发上面构建的 command 的执行
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, uint32_t seq,
bool handled, nsecs_t consumeTime) {
// Notify other system components and prepare to start the next dispatch cycle.
// 构建 command
auto command = [this, currentTime, connection, seq, handled, consumeTime]() REQUIRES(mLock) {
doDispatchCycleFinishedCommand(currentTime, connection, seq, handled, consumeTime);
};
postCommandLocked(std::move(command));
}
所以最终事件从 waitQueue 中移除是调用 doDispatchCycleFinishedCommand
void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime,
const sp<Connection>& connection, uint32_t seq,
bool handled, nsecs_t consumeTime) {
DispatchEntry* dispatchEntry = *dispatchEntryIt;
const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
// 打印出处理时间超过 2s 的事件
if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(),
ns2ms(eventDuration), dispatchEntry->eventEntry->getDescription().c_str());
}
// 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);
const sp<IBinder>& connectionToken = connection->inputChannel->getConnectionToken();
mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken);
}
// Start the next dispatch cycle for this connection.
// 开始下一次处理
startDispatchCycleLocked(now(), connection);
}