在 Android11 InputReader分析 一文中分析到,InputReader将数据放入iq队列后,唤醒InputDispatcher线程,执行InputDispatcher的dispatchOnce方法
//frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
std::scoped_lock _l(mLock);
mDispatcherIsAlive.notify_all();
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
if (!haveCommandsLocked()) {//此时mCommandQueue中没有命令
dispatchOnceInnerLocked(&nextWakeupTime);//1
}
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible()) {//执行mCommandQueue中的命令
nextWakeupTime = LONG_LONG_MIN;
}
//省略
}
继续调用注释1处的dispatchOnceInnerLocked进行处理
//frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
//省略
if (!mPendingEvent) {
//省略
}else {
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.front();//1
mInboundQueue.pop_front();
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(*mPendingEvent);//这个方法会向mCommandQueue中放入命令,后面在dispatchOnce中,调用 runCommandsLockedInterruptible执行这个命令,通过JNI调用,调用PowerManagerService的userActivityFromNative方法
}
ALOG_ASSERT(mPendingEvent != nullptr);
bool done = false;
DropReason dropReason = DropReason::NOT_DROPPED;//标记事件是否需要抛弃掉,不传给应用窗口
if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
dropReason = DropReason::POLICY;
} else if (!mDispatchEnabled) {
dropReason = DropReason::DISABLED;
}
if (mNextUnblockedEvent == mPendingEvent) {
mNextUnblockedEvent = nullptr;
}
switch (mPendingEvent->type) {
//省略
case EventEntry::Type::MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
dropReason = DropReason::APP_SWITCH;
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);//2
break;
}
//省略
|
注释1处,先从iq队列中取出事件,对于触摸事件,调用注释2处的dispatchMotionLocked继续处理
//frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
//省略
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
injectionResult =findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,
&conflictingPointerActions);//1
}
//省略
dispatchEventLocked(currentTime, entry, inputTargets);//2
return true;
}
注释1处,InputDispatcher需要知道,输入事件应该派发给哪个窗口,所以需要找到目标窗口,将其放入inputTargets中,这个流程在文章的后面再分析。注释2处,查找到目标窗口后,调用dispatchEventLocked继续处理
//frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
const std::vector<InputTarget>& inputTargets) {
pokeUserActivityLocked(*eventEntry);
for (const InputTarget& inputTarget : inputTargets) {//遍历
sp<Connection> connection =
getConnectionLocked(inputTarget.inputChannel->getConnectionToken());//根据token取出connection
if (connection != nullptr) {
prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);//继续处理
} else {
if (DEBUG_FOCUS) {
ALOGD("Dropping event delivery to target with channel '%s' because it "
"is no longer registered with the input dispatcher.",
inputTarget.inputChannel->getName().c_str());
}
}
}
}
遍历inputTargets查找到对应的connection ,然后使用prepareDispatchCycleLocked继续处理,在prepareDispatchCycleLocked方法中,对于支持触摸事件分离的窗口,则是直接调用enqueueDispatchEntriesLocked来处理
//frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
bool wasEmpty = connection->outboundQueue.empty();
// Enqueue dispatch entries for the requested modes.
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);//分发
}
}
首先是将事件放入oq队列,然后调用startDispatchCycleLocked继续处理
放入队列:
//frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget,
int32_t dispatchMode) {
//省略
// Enqueue the dispatch entry.
connection->outboundQueue.push_back(dispatchEntry.release());//放入队列
traceOutboundQueueLength(connection);//这里就是能在trace中看到oq的原因
}
startDispatchCycleLocked
//frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
//省略
while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.front();//从oq中取出事件
dispatchEntry->deliveryTime = currentTime;
const nsecs_t timeout =
getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
dispatchEntry->timeoutTime = currentTime + timeout;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
//省略
case EventEntry::Type::MOTION: {
// Publish the motion event.
status = connection->inputPublisher
.publishMotionEvent(dispatchEntry->seq,
dispatchEntry->resolvedEventId,
motionEntry->deviceId, motionEntry->source,
motionEntry->displayId, std::move(hmac),
dispatchEntry->resolvedAction,
motionEntry->actionButton,
dispatchEntry->resolvedFlags,
motionEntry->edgeFlags, motionEntry->metaState,
motionEntry->buttonState,
motionEntry->classification, xScale, yScale,
xOffset, yOffset, motionEntry->xPrecision,
motionEntry->yPrecision,
motionEntry->xCursorPosition,
motionEntry->yCursorPosition,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount,
motionEntry->pointerProperties, usingCoords);//1
reportTouchEventForStatistics(*motionEntry);
break;
}
//省略
// Re-enqueue the event on the wait queue.
connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
connection->outboundQueue.end(),
dispatchEntry));
traceOutboundQueueLength(connection);
connection->waitQueue.push_back(dispatchEntry);//放入wq队列
traceWaitQueueLength(connection);//这就是trace中可以看到wq的原因
}
}
可以看出,该方法主要是从oq队列中取出事件,然后调用connection->inputPublisher的publishMotionEvent方法继续处理,处理完成后,将事件从oq队列中删除,并又添加到wq队列中。
connection的inputPublisher成员指向的是inputChannel,在Android 11 输入系统之InputDispatcher和应用窗口建立联系一文中分析到,使用inputChannel构造connection对象
//frameworks\native\services\inputflinger\dispatcher\Connection.cpp
Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor,
const IdGenerator& idGenerator)
: status(STATUS_NORMAL),
inputChannel(inputChannel),
monitor(monitor),
inputPublisher(inputChannel),//初始化inputPublisher
inputState(idGenerator) {}
继续来看InputChannel的publishMotionEvent方法
//frameworks\native\libs\input\InputTransport.cpp
status_t InputPublisher::publishMotionEvent(
uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags,
int32_t edgeFlags, int32_t metaState, int32_t buttonState,
MotionClassification classification, float xScale, float yScale, float xOffset,
float yOffset, float xPrecision, float yPrecision, float xCursorPosition,
float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) {
//省略
InputMessage msg;
msg.header.type = InputMessage::Type::MOTION;
msg.body.motion.seq = seq;
msg.body.motion.eventId = eventId;
msg.body.motion.deviceId = deviceId;
msg.body.motion.source = source;
msg.body.motion.displayId = displayId;
msg.body.motion.hmac = std::move(hmac);
msg.body.motion.action = action;
msg.body.motion.actionButton = actionButton;
msg.body.motion.flags = flags;
msg.body.motion.edgeFlags = edgeFlags;
msg.body.motion.metaState = metaState;
msg.body.motion.buttonState = buttonState;
msg.body.motion.classification = classification;
msg.body.motion.xScale = xScale;
msg.body.motion.yScale = yScale;
msg.body.motion.xOffset = xOffset;
msg.body.motion.yOffset = yOffset;
msg.body.motion.xPrecision = xPrecision;
msg.body.motion.yPrecision = yPrecision;
msg.body.motion.xCursorPosition = xCursorPosition;
msg.body.motion.yCursorPosition = yCursorPosition;
msg.body.motion.downTime = downTime;
msg.body.motion.eventTime = eventTime;
msg.body.motion.pointerCount = pointerCount;
for (uint32_t i = 0; i < pointerCount; i++) {
msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
}
return mChannel->sendMessage(&msg);
}
构建InputMessage ,然后调用其sendMessage方法,将数据发送出去
//frameworks\native\libs\input\InputTransport.cpp
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);//1
} while (nWrite == -1 && errno == EINTR);
//省略
注释1处,向fd中写入数据,InputDispatcher就将数据分发出去了。
查找目标窗口的过程
前面提到,InputDispatcher通过findTouchedWindowTargetsLocked方法,来查找到目标窗口,从而决定事件应该分发给谁
//frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
const MotionEntry& entry,
std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime,
bool* outConflictingPointerActions) {
//省略
bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN ||
maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction);//有新手指触摸
const bool isFromMouse = entry.source == AINPUT_SOURCE_MOUSE;
bool wrongDevice = false;
if (newGesture) {
//省略
tempTouchState.reset();//先清空tempTouchState,然后重新赋值
tempTouchState.down = down;
tempTouchState.deviceId = entry.deviceId;
tempTouchState.source = entry.source;
tempTouchState.displayId = displayId;
isSplit = false;
}
//省略
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
//省略
sp<InputWindowHandle> newTouchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
isDown /*addOutsideTargets*/, true /*addPortalWindows*/);//1
//省略
if (newTouchedWindowHandle != nullptr) {
// Set target flags.
int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS;
if (isSplit) {
targetFlags |= InputTarget::FLAG_SPLIT;
}
if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
} else if (isWindowObscuredLocked(newTouchedWindowHandle)) {
targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
}
//省略
tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);//2
}
//省略
for (const TouchedWindow& touchedWindow : tempTouchState.windows) {//3
addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
touchedWindow.pointerIds, inputTargets);
}
}
}
注释1处通过findTouchedWindowAtLocked方法查找到InputWindowHandle,注释2处将改InputWindowHandle添加到TouchedWindow中,并添加到tempTouchState的windows集合。上面省略了部分代码,还有其他的满足条件的InputWindowHandle,也会添加进来。注释3处遍历tempTouchState的windows,取出其中的TouchedWindow调用addWindowTargetLocked,来填充inputTargets集合。
先来看看findTouchedWindowAtLocked方法是怎么查找到符合条件的InputWindowHandle
//frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x,
int32_t y, TouchState* touchState,
bool addOutsideTargets,
bool addPortalWindows) {
//省略
// Traverse windows from front to back to find touched window.
const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);//1
for (const sp<InputWindowHandle>& windowHandle : windowHandles) {//2
const InputWindowInfo* windowInfo = windowHandle->getInfo();
if (windowInfo->displayId == displayId) {
int32_t flags = windowInfo->layoutParamsFlags;
if (windowInfo->visible) {
if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
bool isTouchModal = (flags &
(InputWindowInfo::FLAG_NOT_FOCUSABLE |
InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
int32_t portalToDisplayId = windowInfo->portalToDisplayId;
//省略
return windowHandle;
//省略
注释1处返回的InputWindowHandle集合是根据displayID从mWindowHandlesByDisplay中取出来的,mWindowHandlesByDisplay中的元素是SurfaceFlinger中,调用 updateInputWindowInfo方法,最后调用到InputDispatcher的updateWindowHandlesForDisplayLocked添加的。
注释2处遍历前面得到的InputWindowHandle集合,判断触摸的区域是否是在该InputWindowHandle,如果是,则返回该InputWindowHandle。
查找到InputWindowHandle后,就会将其加入到tempTouchState的windows集合中
//frameworks\native\services\inputflinger\dispatcher\TouchState.cpp
void TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags,
BitSet32 pointerIds) {
//省略
TouchedWindow touchedWindow;//构建TouchedWindow
touchedWindow.windowHandle = windowHandle;
touchedWindow.targetFlags = targetFlags;
touchedWindow.pointerIds = pointerIds;
windows.push_back(touchedWindow);//添加进windows集合
}
最后就是遍历windows集合,根据InputWindowHandle信息来填充inputTargets集合了
//frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds,
std::vector<InputTarget>& inputTargets) {
//省略
if (it == inputTargets.end()) {
InputTarget inputTarget;
sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());//取出inputChannel
inputTarget.inputChannel = inputChannel;
inputTarget.flags = targetFlags;
inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
inputTargets.push_back(inputTarget);//添加进集合
it = inputTargets.end() - 1;
}
//省略
}
首先是根据windowHandle中的token,取出对应的inputChanel,然后根据inputChanel构造inputTarget并放入集合 中。这样inputTargets集合中就包含了一个个的inputTarget,而inputTarget就包含了窗口对应的inputChannel 信息。
总结
InputDispatcher所做的工作就是从iq队列中取出数据,然后找到目标窗口,进而找到目标窗口对应的connect,将数据放入connection的oq队列,后面取出oq队列的数据并将其通过fd发送出去。分发完成后,将数据移至wq队列。
流程图如下