1.为什么在onclick方法中添加一个10s的延时点击一次不会anr呢?
答:上一次的事件的超时会被添加到anrTrack队列中,但是处理anr的源头调用还是inputDispatcher的looponce循环回调中,只有inputReader传递来新的触摸事件时才会,触发新一轮的anr检测。
2.iq、oq、wq分别是什么时候入对和出队的呢?还有anrTrack
iq:inputReader将事件传递到inputDispatch中时添加,在inputDispatch被唤醒后开始处理时间时移除
oq:inputDIspatch准备进行分发时会将事件添加到oq中
wq:inputDIspatch分发完成后,会将事件从oq中移除,添加到wq中, 当接收到应用处理完成的回调后会将对应的entry从wq中移除。
此时也会将事件添加到anrTrack中。顺序为oq->wq->anrTrack
当有新的事件进入到inputDispatcher中时,如果有检查到anr,会将anrTrack时间最小的那个超时token移除掉
3.mAnrTraker中的token是什么?待更新
inputReader准备唤醒inputDispatcher的looper时 往iq中添加EventEntry
void InputDispatcher::enqueueFocusEventLocked(const sp<IBinder>& windowToken, bool hasFocus,
const std::string& reason) {
if (mPendingEvent != nullptr) {
// Move the pending event to the front of the queue. This will give the chance
// for the pending event to get dispatched to the newly focused window
mInboundQueue.push_front(mPendingEvent);
mPendingEvent = nullptr;
}
std::unique_ptr<FocusEntry> focusEntry =
std::make_unique<FocusEntry>(mIdGenerator.nextId(), now(), windowToken, hasFocus,
reason);
// This event should go to the front of the queue, but behind all other focus events
// Find the last focus event, and insert right after it
std::deque<std::shared_ptr<EventEntry>>::reverse_iterator it =
std::find_if(mInboundQueue.rbegin(), mInboundQueue.rend(),
[](const std::shared_ptr<EventEntry>& event) {
return event->type == EventEntry::Type::FOCUS;
});
// Maintain the order of focus events. Insert the entry after all other focus events.
mInboundQueue.insert(it.base(), std::move(focusEntry));
}
inputDispatcher looper被唤醒后,从iq中取出一个EventEntry
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
// Reset the key repeat timer whenever normal dispatch is suspended while the
// device is in a non-interactive state. This is to ensure that we abort a key
// repeat if the device is just coming out of sleep.
if (!mDispatchEnabled) {
resetKeyRepeatLocked();
}
// If dispatching is frozen, do not process timeouts or try to deliver any new events.
if (mDispatchFrozen) {
if (DEBUG_FOCUS) {
ALOGD("Dispatch frozen. Waiting some more.");
}
return;
}
// Optimize latency of app switches.
// Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
// been pressed. When it expires, we preempt dispatch and drop all other pending events.
bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
if (mAppSwitchDueTime < *nextWakeupTime) {
*nextWakeupTime = mAppSwitchDueTime;
}
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (!mPendingEvent) {
if (mInboundQueue.empty()) {
if (isAppSwitchDue) {
// The inbound queue is empty so the app switch key we were waiting
// for will never arrive. Stop waiting for it.
resetPendingAppSwitchLocked(false);
isAppSwitchDue = false;
}
// Synthesize a key repeat if appropriate.
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
} else {
if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
*nextWakeupTime = mKeyRepeatState.nextRepeatTime;
}
}
}
// 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);
}
}
....
}
准备开始派发 将eventEntry转变为DispatchEntry 将DispatchEntry添加到oq中
void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connection>& connection,
std::shared_ptr<EventEntry> eventEntry,
const InputTarget& inputTarget,
ftl::Flags<InputTarget::Flags> dispatchMode) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf("enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)",
connection->getInputChannelName().c_str(),
dispatchMode.string().c_str());
ATRACE_NAME(message.c_str());
}
ftl::Flags<InputTarget::Flags> inputTargetFlags = inputTarget.flags;
if (!inputTargetFlags.any(dispatchMode)) {
return;
}
inputTargetFlags.clear(InputTarget::DISPATCH_MASK);
inputTargetFlags |= dispatchMode;
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
std::unique_ptr<DispatchEntry> dispatchEntry =
createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);
// Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
// different EventEntry than what was passed in.
EventEntry& newEntry = *(dispatchEntry->eventEntry);
// Apply target flags and update the connection's input state.
switch (newEntry.type) {
case EventEntry::Type::KEY: {
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(newEntry);
dispatchEntry->resolvedEventId = keyEntry.id;
dispatchEntry->resolvedAction = keyEntry.action;
dispatchEntry->resolvedFlags = keyEntry.flags;
if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags)) {
LOG(WARNING) << "channel " << connection->getInputChannelName()
<< "~ dropping inconsistent event: " << *dispatchEntry;
return; // skip the inconsistent event
}
break;
}
case EventEntry::Type::MOTION: {
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(newEntry);
// Assign a default value to dispatchEntry that will never be generated by InputReader,
// and assign a InputDispatcher value if it doesn't change in the if-else chain below.
constexpr int32_t DEFAULT_RESOLVED_EVENT_ID =
static_cast<int32_t>(IdGenerator::Source::OTHER);
dispatchEntry->resolvedEventId = DEFAULT_RESOLVED_EVENT_ID;
if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_OUTSIDE)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
} else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_HOVER_EXIT)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
} else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_HOVER_ENTER)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
} else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
} else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
} else {
dispatchEntry->resolvedAction = motionEntry.action;
dispatchEntry->resolvedEventId = motionEntry.id;
}
if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
!connection->inputState.isHovering(motionEntry.deviceId, motionEntry.source,
motionEntry.displayId)) {
if (DEBUG_DISPATCH_CYCLE) {
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover "
"enter event",
connection->getInputChannelName().c_str());
}
// We keep the 'resolvedEventId' here equal to the original 'motionEntry.id' because
// this is a one-to-one event conversion.
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
}
dispatchEntry->resolvedFlags = motionEntry.flags;
if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_CANCEL) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_CANCELED;
}
if (dispatchEntry->targetFlags.test(InputTarget::Flags::WINDOW_IS_OBSCURED)) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
}
if (dispatchEntry->targetFlags.test(InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED)) {
dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
}
if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags)) {
LOG(WARNING) << "channel " << connection->getInputChannelName()
<< "~ dropping inconsistent event: " << *dispatchEntry;
return; // skip the inconsistent event
}
dispatchEntry->resolvedEventId =
dispatchEntry->resolvedEventId == DEFAULT_RESOLVED_EVENT_ID
? mIdGenerator.nextId()
: motionEntry.id;
if (ATRACE_ENABLED() && dispatchEntry->resolvedEventId != motionEntry.id) {
std::string message = StringPrintf("Transmute MotionEvent(id=0x%" PRIx32
") to MotionEvent(id=0x%" PRIx32 ").",
motionEntry.id, dispatchEntry->resolvedEventId);
ATRACE_NAME(message.c_str());
}
if ((motionEntry.flags & AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) &&
(motionEntry.policyFlags & POLICY_FLAG_TRUSTED)) {
// Skip reporting pointer down outside focus to the policy.
break;
}
dispatchPointerDownOutsideFocus(motionEntry.source, dispatchEntry->resolvedAction,
inputTarget.inputChannel->getConnectionToken());
break;
}
case EventEntry::Type::FOCUS:
case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::POINTER_CAPTURE_CHANGED:
case EventEntry::Type::DRAG: {
break;
}
case EventEntry::Type::SENSOR: {
LOG_ALWAYS_FATAL("SENSOR events should not go to apps via input channel");
break;
}
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("%s events should not go to apps",
ftl::enum_string(newEntry.type).c_str());
break;
}
}
// Remember that we are waiting for this dispatch to complete.
if (dispatchEntry->hasForegroundTarget()) {
incrementPendingForegroundDispatches(newEntry);
}
// Enqueue the dispatch entry.
connection->outboundQueue.push_back(dispatchEntry.release());
traceOutboundQueueLength(*connection);
}
开始派发给应用的时候
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const std::shared_ptr<Connection>& connection) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf("startDispatchCycleLocked(inputChannel=%s)",
connection->getInputChannelName().c_str());
ATRACE_NAME(message.c_str());
}
if (DEBUG_DISPATCH_CYCLE) {
ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str());
}
while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
dispatchEntry->deliveryTime = currentTime;
const std::chrono::nanoseconds timeout = getDispatchingTimeoutLocked(connection);
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);
if (DEBUG_OUTBOUND_EVENT_DETAILS) {
LOG(DEBUG) << "Publishing " << *dispatchEntry << " to "
<< connection->getInputChannelName();
}
// 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;
}
case EventEntry::Type::MOTION: {
if (DEBUG_OUTBOUND_EVENT_DETAILS) {
LOG(DEBUG) << "Publishing " << *dispatchEntry << " to "
<< connection->getInputChannelName();
}
status = publishMotionEvent(*connection, *dispatchEntry);
break;
}
....
}
// Check the result.
if (status) {
.....
return;
}
// 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);
if (connection->responsive) {
mAnrTracker.insert(dispatchEntry->timeoutTime,
connection->inputChannel->getConnectionToken());
}
traceWaitQueueLength(*connection);
}
}
接收到应用处理完成的回调 移除wq中的DispatchEntry
void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime,
const std::shared_ptr<Connection>& connection,
uint32_t seq, bool handled,
nsecs_t consumeTime) {
// Handle post-event policy actions.
std::deque<DispatchEntry*>::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq);
if (dispatchEntryIt == connection->waitQueue.end()) {
return;
}
DispatchEntry* dispatchEntry = *dispatchEntryIt;
const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
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());
}
if (shouldReportFinishedEvent(*dispatchEntry, *connection)) {
mLatencyTracker.trackFinishedEvent(dispatchEntry->eventEntry->id,
connection->inputChannel->getConnectionToken(),
dispatchEntry->deliveryTime, consumeTime, finishTime);
}
bool restartEvent;
if (dispatchEntry->eventEntry->type == EventEntry::Type::KEY) {
KeyEntry& keyEntry = static_cast<KeyEntry&>(*(dispatchEntry->eventEntry));
restartEvent =
afterKeyEventLockedInterruptable(connection, dispatchEntry, keyEntry, handled);
} else if (dispatchEntry->eventEntry->type == EventEntry::Type::MOTION) {
MotionEntry& motionEntry = static_cast<MotionEntry&>(*(dispatchEntry->eventEntry));
restartEvent = afterMotionEventLockedInterruptable(connection, dispatchEntry, motionEntry,
handled);
} else {
restartEvent = false;
}
// 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;
connection->waitQueue.erase(dispatchEntryIt);
const sp<IBinder>& connectionToken = connection->inputChannel->getConnectionToken();
mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken);
if (!connection->responsive) {
connection->responsive = isConnectionResponsive(*connection);
if (connection->responsive) {
// The connection was unresponsive, and now it's responsive.
processConnectionResponsiveLocked(*connection);
}
}
traceWaitQueueLength(*connection);
if (restartEvent && connection->status == Connection::Status::NORMAL) {
connection->outboundQueue.push_front(dispatchEntry);
traceOutboundQueueLength(*connection);
} else {
releaseDispatchEntry(dispatchEntry);
}
}
// Start the next dispatch cycle for this connection.
startDispatchCycleLocked(now(), connection);
}