我们常说Input超时,都是指的是Input事件分发超时,因此整个超时计算以及触发都在InputDispatcher这个类中。其代码路径如下:/frameworks/native/services/inputflinger/InputDispatcher.cpp,Input分发事件的时候就是不断执行InputDispatcher的threadLoop来读取Input事件,并调用dispatchOnce进行分发事件的。当然如果没有Input事件的时候,他会执行mLooper->pollOnce,进入等待状态。这个就和Android应用UI主线程的Looper一样,MessageQueue里面没有消息的时候,等待于nativePollOnce方法,其实最终还是调用Looper->pollOnce进入等待状态。

InputDispatcherThread dispatchOnce

// --- InputDispatcherThread ---InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}InputDispatcherThread::~InputDispatcherThread() {
}bool InputDispatcherThread::threadLoop() {mDispatcher->dispatchOnce();return true;
}} // namespace android

这个一个input 事件分发的线程。当收到一个消息的时候,会调用下面的DispatchOnce方法。

void InputDispatcher::dispatchOnce() {nsecs_t nextWakeupTime = LONG_LONG_MAX;{ // acquire lockAutoMutex _l(mLock);mDispatcherIsAliveCondition.broadcast();// 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;}} // 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);
}

当一个input事件开始处理的时候, 会在startDispatchCycleLocked 方法里面,给input 事件设置一个开始的时间。后面用来做超时判断使用。

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection) {
#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ startDispatchCycle",connection->getInputChannelName().c_str());
#endifwhile (connection->status == Connection::STATUS_NORMAL&& !connection->outboundQueue.isEmpty()) {DispatchEntry* dispatchEntry = connection->outboundQueue.head;dispatchEntry->deliveryTime = currentTime;

当一个事件,分发到InputDispatch.cpp, 最终会调用到findFocusedWindowTargetsLocked 方法。
在里面,会先去调用checkWindowReadyForMoreInputLocked,检查一下当前的窗口是不是已经准备好可以处理新来的这个事件了。

int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {int32_t injectionResult;std::string reason;// Check whether the window is ready for more input.reason = checkWindowReadyForMoreInputLocked(currentTime,mFocusedWindowHandle, entry, "focused");if (!reason.empty()) {injectionResult = handleTargetsNotReadyLocked(currentTime, entry,mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.c_str());goto Unresponsive;}// Success!  Output targets.injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;addWindowTargetLocked(mFocusedWindowHandle,InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),inputTargets);// Done.
Failed:
Unresponsive:nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);updateDispatchStatisticsLocked(currentTime, entry,injectionResult, timeSpentWaitingForApplication);
#if DEBUG_FOCUSALOGD("findFocusedWindow finished: injectionResult=%d, ""timeSpentWaitingForApplication=%0.1fms",injectionResult, timeSpentWaitingForApplication / 1000000.0);
#endifreturn injectionResult;
}

checkWindowReadyForMoreInputLocked 检查是不是发生了anr:

std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,const char* targetType) {// If the window is paused then keep waiting.if (windowHandle->getInfo()->paused) {return StringPrintf("Waiting because the %s window is paused.", targetType);}// Touch events can always be sent to a window immediately because the user intended// to touch whatever was visible at the time.  Even if focus changes or a new// window appears moments later, the touch event was meant to be delivered to// whatever window happened to be on screen at the time.//// Generic motion events, such as trackball or joystick events are a little trickier.// Like key events, generic motion events are delivered to the focused window.// Unlike key events, generic motion events don't tend to transfer focus to other// windows and it is not important for them to be serialized.  So we prefer to deliver// generic motion events as soon as possible to improve efficiency and reduce lag// through batching.//// The one case where we pause input event delivery is when the wait queue is piling// up with lots of events because the application is not responding.// This condition ensures that ANRs are detected reliably.if (!connection->waitQueue.isEmpty()&& currentTime >= connection->waitQueue.head->deliveryTime+ STREAM_AHEAD_EVENT_TIMEOUT) {return StringPrintf("Waiting to send non-key event because the %s window has not ""finished processing certain input events that were delivered to it over ""%0.1fms ago.  Wait queue length: %d.  Wait queue head age: %0.1fms.",targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f,connection->waitQueue.count(),(currentTime - connection->waitQueue.head->deliveryTime) * 0.000001f);}}return "";
}

这个方法是最关键的,他会去判断一下等待处理的事件队列是不是空的,如果不是空的,那么查看下队首的的消息处理事件是不是超时了,如果超时了,就会出发ANR.

总结:

Input 类型的ANR,如果你点击了屏幕,做了一个很耗时的操作,5s之后是不是弹出ANR弹窗的。只有当你再次点击屏幕的时候,才会触发。因为input 类型的ANR,他没有使用Handler.sendMessageDeley 这种方式去做处理。当点击了一个按钮,如果这个onClick 里面把线程睡眠了20s,只要你不再次点击屏幕,都不会触发ANR。 只有在这个过程中,你再次点击屏幕,又走到了InputDispath.cpp 的DispatchOnce 里面,他会去检测,当前窗口的input 事件是不是处理完了,如果没有处理完,那么判断一下当前的时间和input消息队列里队首的input 事件,是否大于5s,如果大于5s,触发ANR 逻辑。

参考:
https://www.jianshu.com/p/1c827675f457
https://blog.csdn.net/abm1993/article/details/80461752
https://www.jianshu.com/p/914df9091a80
https://blog.csdn.net/abm1993/article/details/80461752

android Anr Input类型系统源码解析相关推荐

  1. android handler2--消息队列源码解析

    android handler2–消息队列源码解析 1.Looper 对于Looper主要是prepare()和loop()两个方法. 首先看prepare()方法 public static fin ...

  2. Android Hawk数据库的源码解析,Github开源项目,基于SharedPreferences的的存储框架

    今天看了朋友一个项目用到了Hawk,然后写了这边文章 一.了解一下概念 Android Hawk数据库github开源项目 Hawk是一个非常便捷的数据库.操作数据库只需一行代码,能存任何数据类型. ...

  3. android网络框架retrofit源码解析二

    注:源码解析文章参考了该博客:http://www.2cto.com/kf/201405/305248.html 前一篇文章讲解了retrofit的annotation,既然定义了,那么就应该有解析的 ...

  4. Android手游 “2048” 源码解析

    转载请写明出处:http://blog.csdn.net/big_heart_c 下面所解析的源码是来自极客学院"Android 2048 "中的源码,读者可以从 https:// ...

  5. Android存储之SharedPreferences源码解析

    个人博客:haichenyi.com.感谢关注 1. 目录 1–目录 2–简介 3–getSharedPreferences会不会阻塞线程,为什么? 4–get操作,为什么有时候会卡顿? 5–comm ...

  6. Android EdgeEffect 使用 和 源码解析

    创建EdgeEffect private EdgeEffect leftEdgeEffect;private void init(Context context) {leftEdgeEffect = ...

  7. Android SharedPreferences 详解 源码解析

    1.实现类 SharedPreferences 只是一个接口,其实现类是SharedPreferencesImpl. 工作流程分析: 创建sp 的时候,会去查看是否有bak文件,如果有的话,把bak文 ...

  8. Android之EventBus框架源码解析下(源码解析)

    转载请标明出处:[顾林海的博客] 个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持! 前言 EventBus是典型的发布订阅模式,多个订阅者可以订阅某个事件,发布者通过 ...

  9. Android 常用开源框架源码解析 系列 (四)Glide

    一.定义  Glide 一个被google所推荐的图片加载库,作者是bumptech.对Android SDk 最低要求是 API 10  与之功能类似的是Square公司的picasso  二.基本 ...

最新文章

  1. .net网格怎么把值插入指定列表_Python列表有什么内置函数可以使用,怎么使用这些函数...
  2. AS安装APK失败的两种情况
  3. .Net Core 认证系统之基于Identity Server4 Token的JwtToken认证源码解析
  4. 转载:PyBus(排忧巴士)的C#源代码(windows mobile手机软件 查询公交的)
  5. vep文件如何转换mp4_如何将m4v视频格式快速转换成mp4视频呢
  6. 非线性回归的数学理论与方法(非线性最小二乘法)
  7. Hbuilder如何创建并运行Vue项目
  8. 多线程中redistemplate不执行_在 Flink 算子中使用多线程如何保证不丢数据?
  9. webpack5+vue3搭建h5项目模板-(二)-eslint代码规范化
  10. 深度解读智慧农业传感器及应用
  11. windows下一键修改IP地址
  12. 环信php修改头像,集成环信3.0 处理UI上展示昵称 头像的方法
  13. 雪夜拾到一部破旧的手机
  14. 汇编获取CPU的id
  15. pythonbmi代码_python用代码实现体质指数BMI测试功能
  16. Ubuntu21.10配置阿里云DNS方法
  17. 我的世界java版的马难以驯服_我的世界:这几种生物很难驯服,最难搞定的就是它了!...
  18. 用爬虫程序批量采集拉勾网职位招聘信息
  19. 计算机考试中英文打字题,计算机信息技术(五笔及中英文打字测试试题)
  20. 2016年蓝桥杯预赛第十题最大比例

热门文章

  1. textureview 旋转90度后平铺_轮滑知识 | 单排轮滑的旋转技巧
  2. linux查看服务依赖关系,服务管理(1)
  3. python数据结构与算法(11)
  4. Django - - 进阶 - - 同源策略和跨域解决方案
  5. CentOS Linux最常用命令及快捷键整理
  6. python中.whl文件下载,pandas
  7. AngularJs 1.5 $location获取url参数
  8. 【Android】 01. APP 进程启动和 ActivityThread 的关系
  9. 移动端手势操作--两点同时点击的实现方案
  10. LocalResizeIMG前端HTML5本地压缩图片上传,兼容移动设备IOS,android