InputDispatcher分发事件
我知道在Input系统初始化时InputManager会调用InputDispatcher的start方法,我们从这个方法入手开始分析分发逻辑
status_t InputDispatcher::start() {
if (mThread) {
return ALREADY_EXISTS;
}
mThread = std::make_unique<InputThread>(
"InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
return OK;
}
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
//将事件加入mInboundQueue
needWake = enqueueInboundEventLocked(newEntry);
//唤起dispatchOnce
if (needWake) {
mLooper->wake();
}
}
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
//从mInboundQueue队列中取出一个事件
mPendingEvent = mInboundQueue.front();
switch (mPendingEvent->type) {
...
case EventEntry::Type::KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
...
//Key事件调用dispatchKeyLocked
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::Type::MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
...
//Motion事件调用dispatchMotionLocked
done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
}
...
}
}
在start方法中开启一个InputDispatcher的线程执行dispatchOnce这个方法,在InputReader调用到InputDispatcher的notifyKey方法除了入队事件,还会唤醒线程,线程只要mLooper->wake触发就会执行这个方法,dispatchOnce方法从mInboundQueue取出一个事件,然后调用dispatchOnceInnerLocked,不同类型调用的方法不一样,比如
- Key事件调用dispatchKeyLocked
- Motion事件调用dispatchMotionLocked
但大致逻辑是一样的,这里我们看Key的处理流程
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
...
std::vector<InputTarget> inputTargets;
//找到当前处在focus状态的Window窗口,并将其加入到inputTargets中
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
//找到需要监听全局按键的InputChannel,封装成InputTarget,加入到inputTargets中
addMonitoringTargetsLocked(inputTargets);
//将按键分发到上面inputTargets的InputChannel中
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
const std::vector<InputTarget>& inputTargets) {
//遍历InputTarget,获取connection
for (const InputTarget& inputTarget : inputTargets) {
//从mConnectionsByFd中获取
sp<Connection> connection =
getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
if (connection != nullptr) {
prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
}
}
}
}
这里涉及系统中对于按键事件的策略逻辑:简单来说就是当前获取焦点的Window接收到事件,方法findFocusedWindowTargetsLocked,而触摸事件就不太一样,会根据当前触摸的位置,判断触碰点是否在目标Window内,然后根据Z进行排序,方法findTouchedWindowTargetsLocked,这些find的目标信息都会保存在inputTargets内。然后调到dispatchEventLocked方法,这里会依次取出inputTargets中的InputTarget,根据InputTarget的InputChannel找到保存在mConnectionByFd中的Connection对象,调用prepareDispatchCycleLocked函数进行分发
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget) {
//各种检查
//调用enqueueDispatchEntriesLocked排队
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget) {
bool wasEmpty = connection->outboundQueue.empty();
// 将不同调度模式的event事件排队
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);
}
}
void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget,
int32_t dispatchMode) {
//生成dispatchEntry
std::unique_ptr<DispatchEntry> dispatchEntry =
createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);
// 加入connection的outboundQueue队列里
connection->outboundQueue.push_back(dispatchEntry.release());
traceOutboundQueueLength(connection);
}
这个函数首先获取以前的connection的outboundQueue是否为空,然后调用enqueueDispatchEntryLocked将事件加入到outboundQueue中。
如果队列以前为空,现在不为空,则调用startDispatchCycleLocked开始分发。
如果以前不为空,说明当前的Activity正在处理前面的按键,则不需要再调用startDispatchCycleLocked。
这里 startDispatchCycleLocked的代码实现如下:
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::Type::KEY: {
const KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
std::array<uint8_t, 32> hmac = getSignature(*keyEntry, *dispatchEntry);
// 发布按键事件
status =
connection->inputPublisher
.publishKeyEvent(dispatchEntry->seq, dispatchEntry->resolvedEventId,
keyEntry->deviceId, keyEntry->source,
...
keyEntry->eventTime);
break;
}
case EventEntry::Type::MOTION: {
MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
// 发布触摸事件
status = connection->inputPublisher
.publishMotionEvent(dispatchEntry->seq,
dispatchEntry->resolvedEventId,
motionEntry->deviceId, motionEntry->source,
...
motionEntry->pointerProperties, usingCoords);
reportTouchEventForStatistics(*motionEntry);
break;
}
}
//从outboundQueue移除已经发布的事件,加入waitQueue中
connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
connection->outboundQueue.end(),
dispatchEntry));
connection->waitQueue.push_back(dispatchEntry);
}
}
从outboundQueue中取出需要处理的事件,交给connection的inputPublisher去分发,将事件加入到connection的waitQueue中。这里分发事件是通过InputPublisher的publishKeyEvent/publishMotionEvent来完成
status_t InputPublisher::publishKeyEvent() {
InputMessage msg;
msg.header.type = InputMessage::Type::KEY;
msg.body.key.seq = seq;
msg.body.key.eventId = eventId;
msg.body.key.deviceId = deviceId;
msg.body.key.source = source;
...
return mChannel->sendMessage(&msg);
}
这里的mChannel就是InputChannel对象,代码在:
native/libs/input/InputTransport.cpp
InputChannel::InputChannel(const std::string& name, android::base::unique_fd fd, sp<IBinder> token)
: mName(name), mFd(std::move(fd)), mToken(token) {
}
status_t InputChannel::sendMessage(const InputMessage* msg) {
const size_t msgLength = msg->size();
InputMessage cleanMsg;
msg->getSanitizedCopy(&cleanMsg);
ssize_t nWrite;
do {
nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
return OK;
}
InputDispatcher是运行在system_process上,而APP是运行在各自APP的进程上的,通信的桥梁就是InputChannel,内部保存两个socket,server_socket和client_socket,这里通过send函数往socket的server端写入InputMessage对象,应用程序正睡眠在client端的fd上,此时client端就会收到该InputMessage,client被唤醒后会进行按键事件的分发。最后dispatcher线程通过connection对象和APP之间建立连接。因为使用的是socket,所以能实现了Input事件的跨进程通信。
还记得上面说过已经发布的事件会移到connection->waitQueue中去,其实这边也是一个很重要的对已分发事件的处理逻辑,我们知道事件分发的socket是异步通信,InputDispatcher线程将Input事件发送之后就直接返回了,对于APP端具体执行结果其实是不知道的,待APP端事件处理完之后是会反馈给InputDispatcher的,入口就是handleReceiveCallback方法
int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
InputDispatcher* d = static_cast<InputDispatcher*>(data);
{
sp<Connection> connection = d->mConnectionsByFd[fd];
for (;;) {
uint32_t seq;
bool handled;
//接收窗口处理完成的消息
status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
if (status) {
break;
}
// 这里post一个command,其实就是调用doDispatchCycleFinishedLockedInterruptible方法
d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
gotOne = true;
}
if (gotOne) {
//执行command
d->runCommandsLockedInterruptible();
if (status == WOULD_BLOCK) {
return 1;
}
}
}
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) {
sp<Connection> connection = commandEntry->connection;
dispatchEntryIt = connection->findWaitQueueEntry(seq);
// 从waitQueue中将当前entry移除
if (dispatchEntryIt != connection->waitQueue.end()) {
dispatchEntry = *dispatchEntryIt;
connection->waitQueue.erase(dispatchEntryIt);
}
//如果当前connection的outBoundQueque里还有Event,则继续下一轮的Dispatch周期
startDispatchCycleLocked(now(), connection);
}
APP侧处理完事件之后,会发送一个反馈信息给到InputDispatcher,InputDispatcher的handleReceiveCallback方法接收到这个反馈,通过一个CommandEntry将事件从waitQueue中移除
简单总结下InputDispatcher分发事件流程:
-
InputReader唤醒InputDispacher执行分发处理。
InputReader主要是将EventHub中的input_event转换成具体的EventEntry,并添加到InputDispatcher的mInboundQueue里,然后唤醒InputDispacher线程。InputDispacher线程有自己的Looper,被唤醒后会执行dispatchOnce方法,InputDispatcher处理的事件主要分两种:一种是command命令(Command是mPolicy处理的具体事务,这个mPolicy就是NativeInputManager,最终对应的上层是InputManagerService),一种是input event。每次dispatchOnce,会优先执行前者。 -
InboundQueue队头取出事件,匹配焦点窗口,传递eventEntry。
从mInboundQueue队列头部取出一个事件,寻找与之匹配的焦点窗口的inputTargets,这里先通过InputWindowHandle找到InputWindowInfo,再找到InputChannel,最终找到Connection,每个焦点窗口在InputDispacher里都有一个对应的Connection,通过这个Connection可以跟InputDispacher通信。然后会将eventEntry转为DispatchEntry放入Connection的outboundQueue。通过InputPublisher通过 InputChannel::sendMessage将DispatchEntry发送给窗口,再将dispatchEntry从outboundQueue移到waitQueue里。该通信过程是异步的,也就是说当InputDispatcher将Input事件发送给目标窗口后会立即返回,并不会等待窗口的处理结果。 -
窗口处理完又将处理结果返回给InputDispatcher
当窗口处理完事件后,会通过handleReceiveCallback()回调函数通知InputDispatcher。回调主要是post一个command,从waitQueue中将当前DispatchEntry移除,如果当前connection的outBoundQueque里还有DispatchEntry,则继续下一轮的Dispatch周期。