InputDispatcher线程分发事件-Android12
Posted xhBruce
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了InputDispatcher线程分发事件-Android12相关的知识,希望对你有一定的参考价值。
InputDispatcher线程分发事件-android12
android12-release
1. 唤醒InputDispatcher中InputThread
- InputManagerService启动-Android12 IMS.start时InputThread轮询执行
dispatchOnce()
- IMS:InputReader线程获取输入事件 NotifyArgs.notify通知到InputDispatcher,
mLooper->wake()
唤醒mThread;主要notifyKey
通知KeyEvent,notifyMotion
通知MotionEvent
1.1 例如notifyKey
通知唤醒InputDispatcher时将事件添加到mInboundQueue
KeyEvent event
初始化KeyEvent对象mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags)
最终调用到PhoneWindowManger.interceptKeyBeforeQueueing
方法是否拦截;mPolicy是com_android_server_input_InputManagerService.cpp中NativeInputManagermPolicy->filterInputEvent
是否开启辅助服务拦截std::unique_ptr<KeyEntry> newEntry
初始化KeyEntry对象enqueueInboundEventLocked()
将KeyEntry
加入到mInboundQueue
mLooper->wake()
唤醒InputDispatcher中mThread执行dispatchOnce()
void InputDispatcher::notifyKey(const NotifyKeyArgs* args)
// ... ...
KeyEvent event;
event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
args->action, flags, keyCode, args->scanCode, metaState, repeatCount,
args->downTime, args->eventTime);
android::base::Timer t;
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD)
ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
std::to_string(t.duration().count()).c_str());
bool needWake;
// acquire lock
mLock.lock();
if (shouldSendKeyToInputFilterLocked(args))
mLock.unlock();
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags))
return; // event was consumed by the filter
mLock.lock();
std::unique_ptr<KeyEntry> newEntry =
std::make_unique<KeyEntry>(args->id, args->eventTime, args->deviceId, args->source,
args->displayId, policyFlags, args->action, flags,
keyCode, args->scanCode, metaState, repeatCount,
args->downTime);
needWake = enqueueInboundEventLocked(std::move(newEntry));
mLock.unlock();
// release lock
if (needWake)
mLooper->wake();
2. 开始执行分发dispatchOnce()
haveCommandsLocked()
当mCommandQueue不为空时分发dispatchOnceInnerLocked(&nextWakeupTime)
runCommandsLockedInterruptible()
处理mCommandQueue中命令CommandEntrymLooper->pollOnce(timeoutMillis)
进入epoll_wait等待状态
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())
dispatchOnceInnerLocked(&nextWakeupTime);
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible())
nextWakeupTime = LONG_LONG_MIN;
// 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.
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);
mLooper->pollOnce(timeoutMillis);
2.1 dispatchOnceInnerLocked(&nextWakeupTime)
currentTime = now()
开始发送事件,计算ANR超时mPendingEvent
将要分发的事件,为空就取出mInboundQueue中EventEntry;若挂起事件mInboundQueue也没有退出不处理- 例如
EventEntry::Type::KEY
类型分发done = dispatchKeyLocked()
- 分发操作完成,
releasePendingEventLocked()
释放mPendingEvent,并强制在此唤醒*nextWakeupTime = LONG_LONG_MIN;
,立刻执行轮询
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime)
nsecs_t currentTime = now();
// ... ...
if (!mPendingEvent)
if (mInboundQueue.empty())
// ... ...
// Nothing to do if there is no pending event.
if (!mPendingEvent)
return;
else
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.front();
mInboundQueue.pop_front();
traceInboundQueueLengthLocked();
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)
pokeUserActivityLocked(*mPendingEvent);
// ... ...
switch (mPendingEvent->type)
// ... ...
case EventEntry::Type::KEY:
std::shared_ptr<KeyEntry> keyEntry = std::static_pointer_cast<KeyEntry>(mPendingEvent);
if (isAppSwitchDue)
if (isAppSwitchKeyEvent(*keyEntry))
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
else if (dropReason == DropReason::NOT_DROPPED)
dropReason = DropReason::APP_SWITCH;
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *keyEntry))
dropReason = DropReason::STALE;
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent)
dropReason = DropReason::BLOCKED;
done = dispatchKeyLocked(currentTime, keyEntry, &dropReason, nextWakeupTime);
break;
// ... ...
if (done)
if (dropReason != DropReason::NOT_DROPPED)
dropInboundEventLocked(*mPendingEvent, dropReason);
mLastDropReason = dropReason;
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
2.2 dispatchKeyLocked()分发KeyEvent事件
currentTime < entry->interceptKeyWakeupTime
当前事件小于唤醒时间不分发,返回falsepostCommandLocked(std::move(commandEntry))
执行命令CommandEntrydoInterceptKeyBeforeDispatchingLockedInterruptible
,policy分发前拦截事件的情况mPolicy->interceptKeyBeforeDispatching
,最终调用到PhoneWindowManger.interceptKeyBeforeDispatching
方法,并返回falsefindFocusedWindowTargetsLocked
寻找焦点窗口dispatchEventLocked()
继续
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,
DropReason* dropReason, nsecs_t* nextWakeupTime)
// ... ...
// Handle case where the policy asked us to try again later last time.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER)
if (currentTime < entry->interceptKeyWakeupTime)
if (entry->interceptKeyWakeupTime < *nextWakeupTime)
*nextWakeupTime = entry->interceptKeyWakeupTime;
return false; // wait until next wakeup
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
entry->interceptKeyWakeupTime = 0;
// Give the policy a chance to intercept the key.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN)
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER)
std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
&InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
sp<IBinder> focusedWindowToken =
mFocusResolver.getFocusedWindowToken(getTargetDisplayId(*entry));
commandEntry->connectionToken = focusedWindowToken;
commandEntry->keyEntry = entry;
postCommandLocked(std::move(commandEntry));
return false; // wait for the command to run
else
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP)
if (*dropReason == DropReason::NOT_DROPPED)
*dropReason = DropReason::POLICY;
// ... ...
InputEventInjectionResult injectionResult =
findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);
if (injectionResult == InputEventInjectionResult::PENDING)
return false;
// ... ...
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
2.3 继续dispatchEventLocked()
- 找到目标connection继续
prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget)
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
std::shared_ptr<EventEntry> eventEntry,
const std::vector<InputTarget>& inputTargets)
//... ...
pokeUserActivityLocked(*eventEntry);
for (const InputTarget& inputTarget : inputTargets)
sp<Connection> connection =
getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
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());
2.4 继续prepareDispatchCycleLocked()
connection->status != Connection::STATUS_NORMAL
当连接connection破坏丢弃事件- 继续
enqueueDispatchEntriesLocked
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection,
std::shared_ptr<EventEntry> eventEntry,
const InputTarget& inputTarget)
// ... ...
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
if (connection->status != Connection::STATUS_NORMAL)
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
connection->getInputChannelName().c_str(), connection->getStatusLabel());
#endif
return;
//... ...
// Not splitting. Enqueue dispatch entries for the event as is.
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
2.5 继续enqueueDispatchEntriesLocked()
enqueueDispatchEntryLocked()
根据dispatchMode来决定是否需要将dispatchEntry加入outboundQueue
队列- 当原先的outbound队列为空, 且当前outbound不为空的情况执行
startDispatchCycleLocked()
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection,
std::shared_ptr<EventEntry> eventEntry,
const InputTarget& inputTarget)
if (ATRACE_ENABLED())
std::string message =
StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, id=0x%" PRIx32 ")",
connection->getInputChannelName().c_str(), eventEntry->id);
ATRACE_NAME(message.c_str());
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);
2.5 继续startDispatchCycleLocked()
- 当Connection状态正常,且outboundQueue不为空,发送
connection->inputPublisher.publishKeyEvent()
,InputChannel通过socket向远端的socket发送消息。
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection)
// ... ...
while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty())
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
dispatchEntry->deliveryTime = currentTime;
const std::chrono::nanoseconds timeout =
getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
dispatchEntry->timeoutTime = currentTime + timeout.count();
// Publish the event.
status_t status;
const EventEntry& eventEntry = *(dispatchEntry->eventEntry);
switch (eventEntry.type)
case EventEntry::Type::KEY:
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry);
std::array<uint8_t, 32> hmac = getSignature(keyEntry, *dispatchEntry);
// Publish the key event.
status = connection->inputPublisher
.publishKeyEvent(dispatchEntry->seq,
dispatchEntry->resolvedEventId, keyEntry.deviceId,
keyEntry.source, keyEntry.displayId,
std::move(hmac), dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags, keyEntry.keyCode,
keyEntry.scanCode, keyEntry.metaState,
keyEntry.repeatCount, keyEntry.downTime,
keyEntry.eventTime);
break;
// ... ...
3. InputPublisher::publishKeyEvent
- InputDispatcher经过InputChannel通过socket向远端的socket发送消息给Window
status_t InputPublisher::publishKeyEvent(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 flags, int32_t keyCode, int32_t scanCode,
int32_t metaState, int32_t repeatCount, nsecs_t downTime,
nsecs_t eventTime)
if (ATRACE_ENABLED())
std::string message = StringPrintf("publishKeyEvent(inputChannel=%s, keyCode=%" PRId32 ")",
mChannel->getName().c_str(), keyCode);
ATRACE_NAME(message.c_str());
if (DEBUG_TRANSPORT_ACTIONS)
ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
"action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
"downTime=%" PRId64 ", eventTime=%" PRId64,
mChannel->getName()以上是关于InputDispatcher线程分发事件-Android12的主要内容,如果未能解决你的问题,请参考以下文章
InputManagerService实体按键及组合按键-Android12