安卓InputDispatching Timeout ANR 流程

server/2024/11/25 14:26:15/
  • 1 ANR的检测逻辑有两个参与者: 观测者A和被观测者B,当然,这两者是不在同一个线程中的。
  • 2 A在调用B中的逻辑时,同时在A中保存一个标记F,然后做个延时操作C,延时时间设为T,这一步称为: 埋雷
  • 3 B中的逻辑如果被执行到,就会通知A去清除标记F,并且通知A解除C,这一步称为: 拆雷
  • 4 如果C没被拆除,那么在时间T后就会被触发,就会去检测标记F是否还在,如果在,就说明B没有在指定的时间T内完成,那么就提示B发生了ANR,这一步称为: 爆雷
  • 5 由于A和B是在不同线程中的,所以B即使死循环,也不会影响C的检测过程。
    所以,我们可以将ANR更精炼的总结为: 埋雷、拆雷和爆雷三个步骤

InputDispatching Timeout: 输入事件(包括按键和触屏事件)在5秒内无响应,就会弹出 ANR 提示框,供用户选择继续等待程序响应或者关闭这个应用程序(也就是杀掉这个应用程序的进程)。输入超时类的 ANR 可以细分为以下两类:

1)处理消息超时: 这一类是指因为消息处理超时而发生的 ANR,在 log,会看到 “Input dispatching timed out (Waiting because the focused window has not finished processing
the input events that were previously delivered to it.)”

2)无法获取焦点: 这一类通常因为新窗口创建慢或旧窗口退出慢而造成窗口无法获得焦点从而发生 ANR,典型 Log “Reason: Waiting because no window has focus but there is a focused application
that may eventually add a window when it finishes starting up.”

这里不分析没有焦点的情形,只分析处理消息超时流程

input子系统中,正常逻辑是:InputDispatcher 负责将输入事件分发给 UI 主线程。UI主线程接收到输入事件后,使用 InputConsumer 来处理事件。经过一系列的 InputStage 完成事件分发后,执行finishInputEvent() 方法来告知 InputDispatcher 事件已经处理完成。InputDispatcher 中使用handleReceiveCallback() 方法来处理 UI 主线程返回的消息,最终将 dispatchEntry事件从等待队列中移除。

http://aospxref.com/android-13.0.0_r3/xref/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

3975  void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
// 打开下列的开关,会打印对应的log
3976      if (DEBUG_INBOUND_EVENT_DETAILS) {
3977          ALOGD("notifyMotion - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
3978                "displayId=%" PRId32 ", policyFlags=0x%x, "
3979                "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
3980                "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
3981                "yCursorPosition=%f, downTime=%" PRId64,
3982                args->id, args->eventTime, args->deviceId, args->source, args->displayId,
3983                args->policyFlags, args->action, args->actionButton, args->flags, args->metaState,
3984                args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision,
3985                args->xCursorPosition, args->yCursorPosition, args->downTime);
3986          for (uint32_t i = 0; i < args->pointerCount; i++) {
。。。。
4047          // Just enqueue a new motion event.// 创建 MotionEntry 对象
4048          std::unique_ptr<MotionEntry> newEntry =
4049                  std::make_unique<MotionEntry>(args->id, args->eventTime, args->deviceId,
4050                                                args->source, args->displayId, policyFlags,
4051                                                args->action, args->actionButton, args->flags,
4052                                                args->metaState, args->buttonState,
4053                                                args->classification, args->edgeFlags,
4054                                                args->xPrecision, args->yPrecision,
4055                                                args->xCursorPosition, args->yCursorPosition,
4056                                                args->downTime, args->pointerCount,
4057                                                args->pointerProperties, args->pointerCoords);
4058  
4059          if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
4060              IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER &&
4061              !mInputFilterEnabled) {
4062              const bool isDown = args->action == AMOTION_EVENT_ACTION_DOWN;
4063              mLatencyTracker.trackListener(args->id, isDown, args->eventTime, args->readTime);
4064          }
4065  
// 将 MotionEntry 事件保存到 mInboundQueue 队列中;如果保存之前 mInboundQueue是为空的,则 needWake 为true。
4066          needWake = enqueueInboundEventLocked(std::move(newEntry));
4067          mLock.unlock();
4068      } // release lock
4069  // 这里分析直接去唤醒inputdispatcher 线程
4070      if (needWake) {
4071          mLooper->wake();
4072      }
4073  }

InputDispatcher 是个线程,会循环执行 dispatchOnce 方法

602  void InputDispatcher::dispatchOnce() {
603      nsecs_t nextWakeupTime = LONG_LONG_MAX;// 局部空间,获取同步锁
604      { // acquire lock
605          std::scoped_lock _l(mLock);
606          mDispatcherIsAlive.notify_all();
607  
608          // Run a dispatch loop if there are no pending commands.
609          // The dispatch loop might enqueue commands to run afterwards.// 如果没有 mCommandQueue ,没有 command 命令的话,
// 则执行 dispatchOnceInnerLocked,获取到下一次唤醒的时间:nextWakeupTime
// 1)如果有motion 事件,调用 dispatchOnceInnerLocked 方法
610          if (!haveCommandsLocked()) {
611              dispatchOnceInnerLocked(&nextWakeupTime);
612          }
613  // 执行command 命令,如果有的话,直接返回 true,然后马上唤醒线程
616          if (runCommandsLockedInterruptable()) {
617              nextWakeupTime = LONG_LONG_MIN;
618          }
619  // 处理anr 或者获取到下一次anr 的时间
// 2)获取超时anr 的时间:processAnrsLocked
622          const nsecs_t nextAnrCheck = processAnrsLocked();
623          nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);
624  
625          // We are about to enter an infinitely long sleep, because we have no commands or
626          // pending or queued events// 如果唤醒时间为最大,则表明没有input 事件,是idle 空闲状态
627          if (nextWakeupTime == LONG_LONG_MAX) {
628              mDispatcherEnteredIdle.notify_all();
629          }
630      } // release lock
631  
632      // Wait for callback or timeout or wake.  (make sure we round up, not down)
633      nsecs_t currentTime = now();
// 获取到唤醒线程的时间
// 调用  mLooper->wake 函数也可以唤醒线程
634      int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
635      mLooper->pollOnce(timeoutMillis);
636  }

1)如果有motion 事件,调用 dispatchOnceInnerLocked 方法

718  void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
719      nsecs_t currentTime = now();
。。。
// 初始 mPendingEvent 为null
746      if (!mPendingEvent) {
// 前面notifymotion 增加了 mInboundQueue
747          if (mInboundQueue.empty()) {
。。。
770          } else {
771              // Inbound queue has at least one entry.
// 这里去获取到motion 事件
772              mPendingEvent = mInboundQueue.front();
773              mInboundQueue.pop_front();
774              traceInboundQueueLengthLocked();
775          }
776  
777          // Poke user activity for this event.
778          if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
779              pokeUserActivityLocked(*mPendingEvent);
780          }
781      }
。。。
798      switch (mPendingEvent->type) {
868          case EventEntry::Type::MOTION: {
869              std::shared_ptr<MotionEntry> motionEntry =
870                      std::static_pointer_cast<MotionEntry>(mPendingEvent);
871              if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
872                  dropReason = DropReason::APP_SWITCH;
873              }
874              if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) {
875                  dropReason = DropReason::STALE;
876              }
877              if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
878                  dropReason = DropReason::BLOCKED;
879              }
// dispatchMotionLocked 方法去分发motion 事件
880              done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);
881              break;
882          }
。。。
// 一般是返回true,表示分发motion 事件到应用了
902      if (done) {
903          if (dropReason != DropReason::NOT_DROPPED) {
904              dropInboundEventLocked(*mPendingEvent, dropReason);
905          }
906          mLastDropReason = dropReason;
907  
// 返回true,则重新设置 mPendingEvent 为null
908          releasePendingEventLocked();
// 设置 nextWakeupTime  为最小,马上唤醒
909          *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
910      }
911  }

// dispatchMotionLocked 方法去分发motion 事件

1634  bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<MotionEntry> entry,
1635                                             DropReason* dropReason, nsecs_t* nextWakeupTime) {
// 会打印对应的trace
1636      ATRACE_CALL();
。。。
1652      const bool isPointerEvent = isFromSource(entry->source, AINPUT_SOURCE_CLASS_POINTER);
1653  
1654      // Identify targets.
1655      std::vector<InputTarget> inputTargets;
1656  
1657      bool conflictingPointerActions = false;
1658      InputEventInjectionResult injectionResult;
1659      if (isPointerEvent) {
1660          // Pointer event.  (eg. touchscreen)// 去根据xy 的坐标点,去找到触摸的 window
1661          injectionResult =
1662                  findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,
1663                                                 &conflictingPointerActions);
。。。
// 增加到全局触摸事件
1687      addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));
1688  
1689      // Dispatch the motion.
1690      if (conflictingPointerActions) {
1691          CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
1692                                     "conflicting pointer actions");
1693          synthesizeCancelationEventsForAllConnectionsLocked(options);
1694      }
// 分发event
1695      dispatchEventLocked(currentTime, entry, inputTargets);
1696      return true;
1697  }

// 分发event

1753  void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
1754                                            std::shared_ptr<EventEntry> eventEntry,
1755                                            const std::vector<InputTarget>& inputTargets) {
1756      ATRACE_CALL();
1757      if (DEBUG_DISPATCH_CYCLE) {
1758          ALOGD("dispatchEventToCurrentInputTargets");
1759      }
1760  
1761      updateInteractionTokensLocked(*eventEntry, inputTargets);
1762  
1763      ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
1764  
1765      pokeUserActivityLocked(*eventEntry);
1766  
1767      for (const InputTarget& inputTarget : inputTargets) {// 找到对应的窗口的 connection
1768          sp<Connection> connection =
1769                  getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
1770          if (connection != nullptr) {
1771              prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
1772          } else {
1773              if (DEBUG_FOCUS) {
1774                  ALOGD("Dropping event delivery to target with channel '%s' because it "
1775                        "is no longer registered with the input dispatcher.",
1776                        inputTarget.inputChannel->getName().c_str());
1777              }
1778          }
1779      }
1780  }

准备分发事件给应用 prepareDispatchCycleLocked

2887  void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
2888                                                   const sp<Connection>& connection,
2889                                                   std::shared_ptr<EventEntry> eventEntry,
2890                                                   const InputTarget& inputTarget) {
2891      if (ATRACE_ENABLED()) {
2892          std::string message =
2893                  StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, id=0x%" PRIx32 ")",
2894                               connection->getInputChannelName().c_str(), eventEntry->id);
2895          ATRACE_NAME(message.c_str());
2896      }
。。。。。
2944  
2945      // Not splitting.  Enqueue dispatch entries for the event as is.
2946      enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
2947  }
2949  void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
2950                                                     const sp<Connection>& connection,
2951                                                     std::shared_ptr<EventEntry> eventEntry,
2952                                                     const InputTarget& inputTarget) {
2953      if (ATRACE_ENABLED()) {
2954          std::string message =
2955                  StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, id=0x%" PRIx32 ")",
2956                               connection->getInputChannelName().c_str(), eventEntry->id);
2957          ATRACE_NAME(message.c_str());
2958      }
2959  
2960      bool wasEmpty = connection->outboundQueue.empty();
2961  
// 将触摸事件保存到 outboundQueue 中
2962      // Enqueue dispatch entries for the requested modes.
2963      enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
2964                                 InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
2965      enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
2966                                 InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
2967      enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
2968                                 InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
2969      enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
2970                                 InputTarget::FLAG_DISPATCH_AS_IS);
2971      enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
2972                                 InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
2973      enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
2974                                 InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
2975  
2976      // If the outbound queue was previously empty, start the dispatch cycle going.
2977      if (wasEmpty && !connection->outboundQueue.empty()) {
// 开始socket 通信去分发给应用 startDispatchCycleLocked
2978          startDispatchCycleLocked(currentTime, connection);
2979      }
2980  }

// 开始socket 通信去分发给应用 startDispatchCycleLocked

3214  void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
3215                                                 const sp<Connection>& connection) {
3216      if (ATRACE_ENABLED()) {
3217          std::string message = StringPrintf("startDispatchCycleLocked(inputChannel=%s)",
3218                                             connection->getInputChannelName().c_str());
3219          ATRACE_NAME(message.c_str());
3220      }
3221      if (DEBUG_DISPATCH_CYCLE) {
3222          ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str());
3223      }
3224  
3225      while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) {
3226          DispatchEntry* dispatchEntry = connection->outboundQueue.front();
3227          dispatchEntry->deliveryTime = currentTime;
// 获取到应用设置的超时事件,一般为 5 秒
3228          const std::chrono::nanoseconds timeout = getDispatchingTimeoutLocked(connection);
// 设置timeout 的时间
3229          dispatchEntry->timeoutTime = currentTime + timeout.count();
。。。
3252              case EventEntry::Type::MOTION: {
3253                  const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
。。。
// socket 通信发送给 应用,给到应用去处理了
3285                  // Publish the motion event.
3286                  status = connection->inputPublisher
3287                                   .publishMotionEvent(dispatchEntry->seq,
3288                                                       dispatchEntry->resolvedEventId,
3289                                                       motionEntry.deviceId, motionEntry.source,
3290                                                       motionEntry.displayId, std::move(hmac),
3291                                                       dispatchEntry->resolvedAction,
3292                                                       motionEntry.actionButton,
3293                                                       dispatchEntry->resolvedFlags,
3294                                                       motionEntry.edgeFlags, motionEntry.metaState,
3295                                                       motionEntry.buttonState,
3296                                                       motionEntry.classification,
3297                                                       dispatchEntry->transform,
3298                                                       motionEntry.xPrecision, motionEntry.yPrecision,
3299                                                       motionEntry.xCursorPosition,
3300                                                       motionEntry.yCursorPosition,
3301                                                       dispatchEntry->rawTransform,
3302                                                       motionEntry.downTime, motionEntry.eventTime,
3303                                                       motionEntry.pointerCount,
3304                                                       motionEntry.pointerProperties, usingCoords);
3305                  break;
3306              }
。。。。。
3383          // Re-enqueue the event on the wait queue.
// 将触摸事件从 outboundQueue 移除掉
3384          connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
3385                                                      connection->outboundQueue.end(),
3386                                                      dispatchEntry));
3387          traceOutboundQueueLength(*connection);
// 将其增加到 waitQueue 等待队列中
3388          connection->waitQueue.push_back(dispatchEntry);
// 如果应用没有die,则 将anr 超时时间保存到 mAnrTracker 中,还有对应的应用token
3389          if (connection->responsive) {
3390              mAnrTracker.insert(dispatchEntry->timeoutTime,
3391                                 connection->inputChannel->getConnectionToken());
3392          }
3393          traceWaitQueueLength(*connection);
3394      }
3395  }

2)获取超时anr 的时间:processAnrsLocked

622 const nsecs_t nextAnrCheck = processAnrsLocked();
// nextWakeupTime 由前面的分析,返回的是为 LONG_LONG_MIN,所以这里的唤醒时间为马上唤醒
623 nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);

670  nsecs_t InputDispatcher::processAnrsLocked() {
671      const nsecs_t currentTime = now();
672      nsecs_t nextAnrCheck = LONG_LONG_MAX;// 下列是处理no focus 没有焦点的情况,这里不满足
674      if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) {
675          if (currentTime >= *mNoFocusedWindowTimeoutTime) {
676              processNoFocusedWindowAnrLocked();
677              mAwaitedFocusedApplication.reset();
678              mNoFocusedWindowTimeoutTime = std::nullopt;
679              return LONG_LONG_MIN;
680          } else {
681              // Keep waiting. We will drop the event when mNoFocusedWindowTimeoutTime comes.
682              nextAnrCheck = *mNoFocusedWindowTimeoutTime;
683          }
684      }
685  
// 获取到前面保存到anr 的时间,即前面当前的时间 + timeout 5 秒
687      nextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout());
// 当前的时间是小于 nextAnrCheck,所以返回 nextAnrCheck的时间
688      if (currentTime < nextAnrCheck) { // most likely scenario
689          return nextAnrCheck;          // everything is normal. Let's check again at nextAnrCheck
690      }
691  
692      // If we reached here, we have an unresponsive connection.
693      sp<Connection> connection = getConnectionLocked(mAnrTracker.firstToken());
694      if (connection == nullptr) {
695          ALOGE("Could not find connection for entry %" PRId64, mAnrTracker.firstTimeout());
696          return nextAnrCheck;
697      }
698      connection->responsive = false;
699      // Stop waking up for this unresponsive connection
700      mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());
701      onAnrLocked(connection);
702      return LONG_LONG_MIN;
703  }

但是接下有个处理 :这里返回时 MIN 的,即马上唤醒。所以再走一次线程dispatchOnce 方法
nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);

602  void InputDispatcher::dispatchOnce() {
603      nsecs_t nextWakeupTime = LONG_LONG_MAX;
604      { // acquire lock
605          std::scoped_lock _l(mLock);
606          mDispatcherIsAlive.notify_all();
607  // 这时候没有inboundqueue 了
610          if (!haveCommandsLocked()) {
611              dispatchOnceInnerLocked(&nextWakeupTime);
612          }
613  
// 也没有cammand
616          if (runCommandsLockedInterruptable()) {
617              nextWakeupTime = LONG_LONG_MIN;
618          }
619  
// 这里就可以获取到 anr 的时间了
622          const nsecs_t nextAnrCheck = processAnrsLocked();
623          nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);
624  
625          // We are about to enter an infinitely long sleep, because we have no commands or
626          // pending or queued events
627          if (nextWakeupTime == LONG_LONG_MAX) {
628              mDispatcherEnteredIdle.notify_all();
629          }
630      } // release lock
631  
633      nsecs_t currentTime = now();
634      int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
// 这里去等待anr 超时的时间
635      mLooper->pollOnce(timeoutMillis);
636  }

3)排雷过程

// 在inputdispatcher 与应用创建连接的时候,会设置socket 通信的callback,执行 handleReceiveCallback 方法

5450  Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
5451      if (DEBUG_CHANNEL_CREATION) {
5452          ALOGD("channel '%s' ~ createInputChannel", name.c_str());
5453      }
。。。5475          std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
5476                                                              this, std::placeholders::_1, token);
5477  
5478          mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);
5479      } // release lock
5480  
5481      // Wake the looper because some connections have changed.
5482      mLooper->wake();
5483      return clientChannel;
5484  }

如果应用有发送socket 消息,则执行 handleReceiveCallback 方法

int InputDispatcher::handleReceiveCallback(int events, sp<IBinder> connectionToken) {std::scoped_lock _l(mLock);
// 通过token 获取到对应的connectionsp<Connection> connection = getConnectionLocked(connectionToken);bool notify;
// event 不能为 ALOOPER_EVENT_ERROR 或者 ALOOPER_EVENT_HANGUPif (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {if (!(events & ALOOPER_EVENT_INPUT)) {ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  ""events=0x%x",connection->getInputChannelName().c_str(), events);return 1;}nsecs_t currentTime = now();bool gotOne = false;status_t status = OK;
// 循环操作for (;;) {
// 通过socket 获取到消息Result<InputPublisher::ConsumerResponse> result =connection->inputPublisher.receiveConsumerResponse();if (!result.ok()) {status = result.error().code();break;}
// 如果result 是 Finished,则执行 finishDispatchCycleLockedif (std::holds_alternative<InputPublisher::Finished>(*result)) {const InputPublisher::Finished& finish =std::get<InputPublisher::Finished>(*result);finishDispatchCycleLocked(currentTime, connection, finish.seq, finish.handled,finish.consumeTime);
。。。
// 设置 gotOne = true
gotOne = true;}if (gotOne) {
// finishDispatchCycleLocked 增加了command,这里去执行 commandrunCommandsLockedInterruptable();if (status == WOULD_BLOCK) {return 1;}}

// 如果result 是 Finished,则执行 finishDispatchCycleLocked

void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection, uint32_t seq,bool handled, nsecs_t consumeTime) {if (DEBUG_DISPATCH_CYCLE) {ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",connection->getInputChannelName().c_str(), seq, toString(handled));}if (connection->status == Connection::Status::BROKEN ||connection->status == Connection::Status::ZOMBIE) {return;}// Notify other system components and prepare to start the next dispatch cycle.auto command = [this, currentTime, connection, seq, handled, consumeTime]() REQUIRES(mLock) {doDispatchCycleFinishedCommand(currentTime, connection, seq, handled, consumeTime);};postCommandLocked(std::move(command));
}

前面 runCommandsLockedInterruptable 方法会去执行 doDispatchCycleFinishedCommand 方法

void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime,const sp<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;
// 如果应用处理超过 2 秒,则会打印下列的日志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());}
。。。
// 从等待队列中找到 dispatchEntryIt 
dispatchEntryIt = connection->findWaitQueueEntry(seq);if (dispatchEntryIt != connection->waitQueue.end()) {dispatchEntry = *dispatchEntryIt;connection->waitQueue.erase(dispatchEntryIt);const sp<IBinder>& connectionToken = connection->inputChannel->getConnectionToken();
// 从anrtracker 中移除这个超时时间,和connectionmAnrTracker.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 继续去处理startDispatchCycleLocked(now(), connection);
}

则下次执行线程的时候,由于mAnrTracker移除了对应的conenction,则 processAnrsLocked不会触发anr 流程

4)爆雷过程

在anr 时间点触发线程执行:dispatchOnce,然后执行 processAnrsLocked 方法

nsecs_t InputDispatcher::processAnrsLocked() {const nsecs_t currentTime = now();nsecs_t nextAnrCheck = LONG_LONG_MAX;
// 不满足下列的条件if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) {if (currentTime >= *mNoFocusedWindowTimeoutTime) {processNoFocusedWindowAnrLocked();mAwaitedFocusedApplication.reset();mNoFocusedWindowTimeoutTime = std::nullopt;return LONG_LONG_MIN;} else {// Keep waiting. We will drop the event when mNoFocusedWindowTimeoutTime comes.nextAnrCheck = *mNoFocusedWindowTimeoutTime;}}// Check if any connection ANRs are duenextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout());
// 这里当前的时间点是大于 anr 的时间,即前面没有移除if (currentTime < nextAnrCheck) { // most likely scenarioreturn nextAnrCheck;          // everything is normal. Let's check again at nextAnrCheck}// 执行下列anr 的流程// If we reached here, we have an unresponsive connection.sp<Connection> connection = getConnectionLocked(mAnrTracker.firstToken());if (connection == nullptr) {ALOGE("Could not find connection for entry %" PRId64, mAnrTracker.firstTimeout());return nextAnrCheck;}
// 设置应用回复为 falseconnection->responsive = false;// Stop waking up for this unresponsive connection
// 从anrtracker 中移除,防止进入到线程又再次触发anrmAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());
// 走anr 流程:onAnrLockedonAnrLocked(connection);return LONG_LONG_MIN;
}

// 走anr 流程:onAnrLocked

void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {if (connection == nullptr) {LOG_ALWAYS_FATAL("Caller must check for nullness");}// Since we are allowing the policy to extend the timeout, maybe the waitQueue// is already healthy again. Don't raise ANR in this situationif (connection->waitQueue.empty()) {ALOGI("Not raising ANR because the connection %s has recovered",connection->inputChannel->getName().c_str());return;}
// 从等待队列中获取DispatchEntry* oldestEntry = *connection->waitQueue.begin();
// 获取到等待的时间const nsecs_t currentWait = now() - oldestEntry->deliveryTime;
// 设置input dispatcher 时间分发超时的原因 reasonstd::string reason =android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",connection->inputChannel->getName().c_str(),ns2ms(currentWait),oldestEntry->eventEntry->getDescription().c_str());sp<IBinder> connectionToken = connection->inputChannel->getConnectionToken();
// 保存到dump 中updateLastAnrStateLocked(getWindowHandleLocked(connectionToken), reason);processConnectionUnresponsiveLocked(*connection, std::move(reason));// Stop waking up for events on this connection, it is already unresponsivecancelEventsForAnrLocked(connection);
}

processConnectionUnresponsiveLocked 处理anr

void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& connection,std::string reason) {const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken();std::optional<int32_t> pid;
// 不满足下列条件if (connection.monitor) {ALOGW("Monitor %s is unresponsive: %s", connection.inputChannel->getName().c_str(),reason.c_str());pid = findMonitorPidByTokenLocked(connectionToken);} else {// The connection is a windowALOGW("Window %s is unresponsive: %s", connection.inputChannel->getName().c_str(),reason.c_str());const sp<WindowInfoHandle> handle = getWindowHandleLocked(connectionToken);if (handle != nullptr) {pid = handle->getInfo()->ownerPid;}}sendWindowUnresponsiveCommandLocked(connectionToken, pid, std::move(reason));
}
void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp<IBinder>& token,std::optional<int32_t> pid,std::string reason) {
// 将command 保存到queue 中,因为前面会直接返回 MIN,所以线程会马山处理auto command = [this, token, pid, reason = std::move(reason)]() REQUIRES(mLock) {scoped_unlock unlock(mLock);mPolicy->notifyWindowUnresponsive(token, pid, reason);};postCommandLocked(std::move(command));
}

// 通知到界面没有反应 notifyWindowUnresponsive

/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
// 前面将 NativeInputManager 保存到 了InputManager中

831  void NativeInputManager::notifyWindowUnresponsive(const sp<IBinder>& token,
832                                                    std::optional<int32_t> pid,
833                                                    const std::string& reason) {
834  #if DEBUG_INPUT_DISPATCHER_POLICY
835      ALOGD("notifyWindowUnresponsive");
836  #endif
// 会打印对应的trace:notifyWindowUnresponsive
837      ATRACE_CALL();
838  
839      JNIEnv* env = jniEnv();
840      ScopedLocalFrame localFrame(env);
841  
842      jobject tokenObj = javaObjectForIBinder(env, token);
843      ScopedLocalRef<jstring> reasonObj(env, env->NewStringUTF(reason.c_str()));
844  
// 调用java 层的方法
845      env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowUnresponsive, tokenObj,
846                          pid.value_or(0), pid.has_value(), reasonObj.get());
847      checkAndClearExceptionFromCallback(env, "notifyWindowUnresponsive");
848  }

/frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

2927      // Native callback
2928      @SuppressWarnings("unused")
2929      private void notifyWindowUnresponsive(IBinder token, int pid, boolean isPidValid,
2930              String reason) {
2931          mWindowManagerCallbacks.notifyWindowUnresponsive(token,
2932                  isPidValid ? OptionalInt.of(pid) : OptionalInt.empty(), reason);
2933      }

/frameworks/base/services/core/java/com/android/server/wm/InputManagerCallback.java

102      @Override
103      public void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
104              @NonNull String reason) {
105          mService.mAnrController.notifyWindowUnresponsive(token, pid, reason);
106      }

/frameworks/base/services/core/java/com/android/server/wm/AnrController.java

88      void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
89              @NonNull String reason) {
90          if (notifyWindowUnresponsive(token, reason)) {
91              return;
92          }
93          if (!pid.isPresent()) {
94              Slog.w(TAG_WM, "Failed to notify that window token=" + token + " was unresponsive.");
95              return;
96          }
97          notifyWindowUnresponsive(pid.getAsInt(), reason);
98      }
99  
100      /**
101       * Notify a window identified by its input token was unresponsive.
102       *
103       * @return true if the window was identified by the given input token and the request was
104       *         handled, false otherwise.
105       */
106      private boolean notifyWindowUnresponsive(@NonNull IBinder inputToken, String reason) {
107          preDumpIfLockTooSlow();
108          final int pid;
109          final boolean aboveSystem;
110          final ActivityRecord activity;
111          synchronized (mService.mGlobalLock) {
112              InputTarget target = mService.getInputTargetFromToken(inputToken);
113              if (target == null) {
114                  return false;
115              }
116              WindowState windowState = target.getWindowState();
117              pid = target.getPid();
118              // Blame the activity if the input token belongs to the window. If the target is
119              // embedded, then we will blame the pid instead.
120              activity = (windowState.mInputChannelToken == inputToken)
121                      ? windowState.mActivityRecord : null;// 会打印下列的log
122              Slog.i(TAG_WM, "ANR in " + target + ". Reason:" + reason);
123              aboveSystem = isWindowAboveSystem(windowState);
124              dumpAnrStateLocked(activity, windowState, reason);
125          }
// ActivityRecord  不为空
126          if (activity != null) {
127              activity.inputDispatchingTimedOut(reason, pid);
128          } else {
129              mService.mAmInternal.inputDispatchingTimedOut(pid, aboveSystem, reason);
130          }
131          return true;
132      }

/frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java

6649      public boolean inputDispatchingTimedOut(String reason, int windowPid) {
6650          ActivityRecord anrActivity;
6651          WindowProcessController anrApp;
6652          boolean blameActivityProcess;
6653          synchronized (mAtmService.mGlobalLock) {
6654              anrActivity = getWaitingHistoryRecordLocked();
6655              anrApp = app;
6656              blameActivityProcess =  hasProcess()
6657                      && (app.getPid() == windowPid || windowPid == INVALID_PID);
6658          }
6659  
6660          if (blameActivityProcess) {
6661              return mAtmService.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner,
6662                      anrActivity.shortComponentName, anrActivity.info.applicationInfo,
6663                      shortComponentName, app, false, reason);

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

17647      boolean inputDispatchingTimedOut(ProcessRecord proc, String activityShortComponentName,
17648              ApplicationInfo aInfo, String parentShortComponentName,
17649              WindowProcessController parentProcess, boolean aboveSystem, String reason) {
17650          if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
17651              throw new SecurityException("Requires permission " + FILTER_EVENTS);
17652          }
17653  
17654          final String annotation;
17655          if (reason == null) {
17656              annotation = "Input dispatching timed out";
// 这里增加 Input dispatching timed out
17657          } else {
17658              annotation = "Input dispatching timed out (" + reason + ")";
17659          }
17660  
17661          if (proc != null) {
17662              synchronized (this) {
17663                  if (proc.isDebugging()) {
17664                      return false;
17665                  }
17666  
17667                  if (proc.getActiveInstrumentation() != null) {
17668                      Bundle info = new Bundle();
17669                      info.putString("shortMsg", "keyDispatchingTimedOut");
17670                      info.putString("longMsg", annotation);
17671                      finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
17672                      return true;
17673                  }
17674              }// 这里去弹框
17675              mAnrHelper.appNotResponding(proc, activityShortComponentName, aInfo,
17676                      parentShortComponentName, parentProcess, aboveSystem, annotation);
17677          }
17678  
17679          return true;
17680      }

http://www.ppmy.cn/server/144814.html

相关文章

设计自己的网络通信协议

文章目录 一、为什么需要设计网络通信协议1. **标准化通信规则**2. **确保数据传输的可靠性**3. **支持网络的多样性和可扩展性**4. **分层设计&#xff0c;简化复杂性**5. **实现设备的互操作性**6. **支持多任务和多应用并发**7. **提供安全性**8. **支持不同的通信模式**总结…

大数据实验4-HBase

一、实验目的 阐述HBase在Hadoop体系结构中的角色&#xff1b;能够掌握HBase的安装和配置方法熟练使用HBase操作常用的Shell命令&#xff1b; 二、实验要求 学习HBase的安装步骤&#xff0c;并掌握HBase的基本操作命令的使用&#xff1b; 三、实验平台 操作系统&#xff1…

【Docker集群应用】Docker基础与部署安装

文章目录 Docker概述Docker 与 虚拟机的区别Linux 六大命名空间Docker 的核心技术Docker 核心概念 Docker部署安装关闭防火墙和 SELinux安装依赖包设置阿里云镜像源安装 Docker-CE 并设置为开机自动启动查看 Docker 版本信息查看 Docker 信息Docker 系统信息 Docker 概述 Doc…

ctfshow-Misc入门(1-16)

misc1 查看图片得到flag misc2 1、打开文本&#xff0c;发现以“塒NG”开头 3、修改文件格式为png格式 4、查看图片&#xff0c;得到flag *遇到的问题&#xff1a;无法直接修改后缀名 *解决方法&#xff1a;需要点击文件夹&#xff0c;然后点击查看&#xff0c;将文件拓…

核心差异:知识VS文档管理(+工具软件安利)

在讨论知识管理和文档管理时&#xff0c;我们经常会听到这两种说法被混淆使用。然而&#xff0c;它们各自服务于不同的目的&#xff0c;这一点至关重要。 想象一下&#xff0c;你是一名项目经理&#xff0c;面临以下两项任务&#xff1a; 存储最新的项目计划捕捉团队讨论中获…

spring循环依赖以及MyBatis-Plus的继承特性导致循环依赖自动解决失效

在 Spring 中&#xff0c;循环依赖是指两个或多个 bean 之间相互依赖&#xff0c;形成一个循环引用的情况。Spring 对于循环依赖有一定的处理机制&#xff0c;但也存在一些限制。 一、Spring 处理循环依赖的方式 三级缓存解决构造函数注入的循环依赖&#xff1a; Spring 首先创…

C++结构型设计模式之使用抽象工厂来创建和配置桥接模式的例子

下面是一个使用抽象工厂模式来创建和配置桥接模式的示例&#xff0c;场景是创建不同操作系统的窗口&#xff08;Window&#xff09;及其对应的实现&#xff08;WindowImpl&#xff09;。我们将通过抽象工厂来创建不同操作系统下的窗口和实现。 代码示例 #include <iostrea…

机器学习周志华学习笔记-第5章<神经网络>

机器学习周志华学习笔记-第5章<神经网络> 卷王&#xff0c;请看目录 5模型的评估与选择5.1 神经元模型5.2 感知机与多层网络5.3 BP(误逆差)神经网络算法 5.4常见的神经网络5.4.1 RBF网络&#xff08;Radial Basis Function Network&#xff0c;径向基函数网络&#xff0…