Android ANR 实现机制详解

一 ANR 概述

ANR(Application Not Responding),即应用程序无响应,Android 系统指定某些事件需要在规定时间内完成,如果超过预定时间还能未能得到有效响应,就会造成 ANR。具体表现为,应用位于前台时,系统会向用户显示一个对话框,如下图所示。用户可以选择“wait”让程序继续运行,也可以选择“Close app”强制关闭。

二 ANR 触发场景

系统发生 ANR 时会在 system_server 进程调用 AppNotRespondingDialog.show() 方法,弹出对话框提示用户,对话框的调用链如下:

ProcessRecord.appNotResponding()
└── mService.mUiHandler.sendMessage(SHOW_NOT_RESPONDING_UI_MSG)
    └── AMS.UiHandler.handleMessage()
        └── AppErrors.handleShowAnrUi()
             └── AppNotRespondingDialog.show()

其中 AppErrors.appNotResponding() 方法是弹出 ANR 对话框的唯一入口,查看其调用关系如如下图:

总结有以下 4 种场景的超时会引起 ANR:

  1. Service Timeout: 组件 Service 执行超时

  2. BroadcastReceiverTimeout:组件 BroadcastReceiver 执行超时

  3. ContentProvider Timeout:组件 ContentProvider 执行超时

  4. InputDispatching Timeout: 按键或触摸事件在特定时间内无响应

以下是 Android 原生系统对不同类型的超时阈值设置,各手机厂商或芯片厂商也会对此值进行自行定制。

类型TimeOut (sec)
Service前台:20,后台:200
Broadcast前台:10,后台:60
ContentProvider10
InputDispatching5

三 ANR 实现机制

3.1 ANR 触发流程

触发 ANR 的过程大致可分为三个步骤: 埋下炸弹 ->执行任务 ->引爆炸弹(或拆除炸弹)

其主体实现在系统层:

  1. 前文所述 4 种场景相关的事件都会经过系统进程(system_server) 调度,设置定时监控(即埋下炸弹)
  2. 然后,system_server 进程将任务派发到应用进程完成对消息的实际处理(执行任务)
  3. 最后,执行任务时间过长,在定时器超时前 system_server 还未收到任务完成的通知,触发 ANR(炸弹爆炸)

在第 3 步中,如果任务在规定时间内执行完成,通知 system_server 进程移除监控,则炸弹被拆除,不会发生 ANR 异常。

3.2 Service超时机制源码解读

以 Service 超时为例,从源码来分析其超时机制引发 ANR 的流程。

Service Timeout 是位于 system_server 进程 -> ActivityManager 线程中 AMS.MainHandler 收到 SERVICE_TIMEOUT_MSG消息时触发。

对于 Service 有两类:

  • 对于前台服务,则超时为 SERVICE_TIMEOUT = 20s;
  • 对于后台服务,则超时为 SERVICE_BACKGROUND_TIMEOUT = 200s 由变量 ProcessRecord.execServicesFg来决定是否前台启动

Service ANR检测

Android 是通过设置定时消息实现的检测 Service 超时的。定时消息是由 AMS 的消息队列处理的(system_server 的 ActivityManager 线程)。AMS 有 Service 运行的上下文信息。

Service ANR 主体实现在 ActiveServices 中。 当 Service 的生命周期开始时,bumpServiceExecutingLocked() 会被调用,紧接着会调用 scheduleServiceTimeoutLocked()

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

void scheduleServiceTimeoutLocked(ProcessRecord proc) {
    if (proc.executingServices.size() == 0 || proc.thread == null) {
        return;
    }
    Message msg = mAm.mHandler.obtainMessage(
            ActivityManagerService.SERVICE_TIMEOUT_MSG);
    msg.obj = proc;
    mAm.mHandler.sendMessageDelayed(msg,
            proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}

当 Service 的生命周期结束时,会调用 serviceDoneExecutingLocked() 方法,之前抛出的 SERVICE_TIMEOUT_MSG 消息在这个方法中会被清除。 如果在超时时间内,SERVICE_TIMEOUT_MSG 没有被清除,那么,AMS.MainHandler 就会响应这个消息

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

case SERVICE_TIMEOUT_MSG: {
    mServices.serviceTimeout((ProcessRecord)msg.obj);
} break;

serviceTimeout 在 ActiveServices 启动打印信息

frameworks/base/services/core/java/com/android/server/am/ActiveServicesjava

if (timeout != null && mAm.mProcessList.mLruProcesses.contains(proc)) {
    Slog.w(TAG, "Timeout executing service: " + timeout);
    StringWriter sw = new StringWriter();
    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
    pw.println(timeout);
    timeout.dump(pw, "    ");
    pw.close();
    mLastAnrDump = sw.toString();
    mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
    mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS);
    anrMessage = "executing service " + timeout.shortInstanceName;
}

// 打印 ANR 信息
if (anrMessage != null) {
    mAm.mAnrHelper.appNotResponding(proc, anrMessage);
}

通过 ANRHelper 打印 ANR 信息

frameworks/base/services/core/java/com/androidserver/am/AnrHelper.java

void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
        ApplicationInfo aInfo, String parentShortComponentName,
        WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
    synchronized (mAnrRecords) {
        mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
                parentShortComponentName, parentProcess, aboveSystem, annotation));
    }
    startAnrConsumerIfNeeded();
}

Service 的 ANR机制总结 通过定时消息跟踪 Service 的运行,当定时消息被响应时,说明 Service 还没有运行完成,这就意味着 Service ANR。

四 ANR 问题分析流程

ANR 问题主要有两种原因:应用自身的问题系统异常导致的问题。在分析 ANR 问题的时候,最主要的就是要确定是哪个原因导致的

ANR 问题一般的分析步骤如下:

  1. 分析 trace.txt:查看是否有明显的异常,比如死锁、SystemServer 异常持锁等
    1. 死锁堆栈: 观察 Trace 堆栈,确认是否有明显问题,如主线程是否与其他线程发生死锁,如果是进程内部发生了死锁,只需找到与当前线程死锁的线程,问题即可解决
    2. 业务堆栈: 观察 Trace 堆栈,发现当前主线程堆栈正在执行业务逻辑,这时候需要分析对应的代码,查看是否真的有问题
      1. 重要:如果业务方觉得这里没有问题,需要进一步分析,因为 Trace 堆栈可能并不是真正耗时的地方,需要结合其他信息一起分析
    3. IPC Block 堆栈: 观察通过 Trace 堆栈,发现主线程堆栈是在跨进程(Binder)通信,这时候可以根据其他 Log、Binder Info 等信息,来分析 IPC 信息
      1. 大部分 IPC 都是在跟 SystemServer,如果没有 BinderInfo,可以搜索对应的接口关键字,在 SystemServer 进程查找是否有相关的堆栈
      2. 重要:如果业务方觉得这里没有问题,需要进一步分析,因为 Trace 堆栈可能并不是真正耗时的地方,需要结合其他信息一起分析
    4. 系统堆栈: 通过观察 Trace,发现当前堆栈只是简单的系统堆栈,比如 NativePollOnce,想要搞清楚是否发生严重耗时,以及进一步的分析定位
      1. 重要:大部分比较难分析的 ANR 基本上应用主线程堆栈都是 NativePollOnce 这个状态,之所以出现这种状态,可能有下面几个原因
        1. 确实没有消息在处理,可能进程被冻结,或者 No Focused Window 这种 ANR
        2. 刚好处理完某一个耗时消息,系统抓堆栈的时候,已经晚了,耗时的状态没有抓到
        3. 线程调度的原因,主线程没有机会执行
  2. 分析 Event Log:看具体的 ANR 时间(搜索 am_anr),看看是否跟 ANR log 能够对上,以确定 ANR Log 是否有效,如果 ANR Log 有效,分析 ANR Log,提取有用信息:pid、tid、死锁等,遇到 ANR 问题,摆在我们面前的 trace 是不是第一案发现场,如果 ANR 发生的输出的信息很多,当时的 CPU 和 I/O 资源比较紧张,那么这段日志输出的时间点可能会延迟 10 秒到 20 秒都有可能,所以我们有时候需要提高警惕。不过正常情况下,EventLog 中的 am_anr 的输出时间是最早的,也是最接近 ANR 时间的 (提取有效信息到单独文件中)
  3. 分析 Android Log:看 MainLog(Android Log) 或者 SystemLog 查看 ANR 详细信息(搜索 ANR in),提取有效的信息 (提取有效信息到单独文件中)
    1. 发生 ANR 的时间
    2. 打印 ANR 日志的进程
    3. 发生 ANR 的进程
    4. 发生 ANR 的原因
    5. CPU 负载
    6. Memory 负载
    7. CPU 使用统计时间段
    8. 各进程的 CPU 使用率
      1. 总的 CPU 使用率
      2. 缺页次数 fault
        1. xxx minor 表示高速缓存中的缺页次数,可以理解为进程在做内存访问
        2. xxx major 表示内存的缺页次数,可以理解为进程在做 IO 操作
    9. CPU 使用汇总
  4. 配合 Main Log(Android Log) 和 EventLog 把 CPU 开始和结束的时间点内的所有有用信息提取出来到一个 文件中,搜索的主要关键字:pid,进程名,WindowManager、ActivityManager(关键字参考下一节的关键 Log 那里)
    1. 收集关键操作场景,比如解锁、安装应用、亮灭屏、应用启动等
    2. 收集异常和系统关键 Log
      1. 系统变慢 :比如 Slow operation、Slow dispatch、Slow delivery、dvm_lock_sample、binder_sample
      2. 进程变化 :am_kill、am_proc_died、lowmemorykiller、ANR、应用启动关系等
      3. 系统信息 :cpu info、meminfo、binder info(是否满了) 、iowait (是否过高)
      4. 消息监控:ANR 前的 ANR Message 打印,Block Message 信息,应用自己代码执行逻辑推断出的 Message 耗时等
    3. 收集 ANR 进程的所有关键线程的运行情况、线程优先级等
    4. 根据第四步提取出来的关键信息文件,进一步理出系统当时的情况、状态(推荐 vscode 或者 notepad ++ ,有 线索就全局搜索)),比如
      1. 是处于低内存频繁杀进程?
      2. 重启第一次解锁系统繁忙
      3. 还是短时间内多个应用启动系统繁忙
      4. 还是应用自己的逻辑等待?
    5. 针对不同的 ANR 类型,提取不同的信息
  5. 不行就加 Log 复现

作者:话唠扇贝
链接:https://juejin.cn/post/7128397546099048478

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

一、架构师筑基必备技能

1、深入理解Java泛型
2、注解深入浅出
3、并发编程
4、数据传输与序列化
5、Java虚拟机原理
6、高效IO
……

在这里插入图片描述

二、Android百大框架源码解析

1.Retrofit 2.0源码解析
2.Okhttp3源码解析
3.ButterKnife源码解析
4.MPAndroidChart 源码解析
5.Glide源码解析
6.Leakcanary 源码解析
7.Universal-lmage-Loader源码解析
8.EventBus 3.0源码解析
9.zxing源码分析
10.Picasso源码解析
11.LottieAndroid使用详解及源码解析
12.Fresco 源码分析——图片加载流程

在这里插入图片描述

三、Android性能优化实战解析

  • 腾讯Bugly:对字符串匹配算法的一点理解
  • 爱奇艺:安卓APP崩溃捕获方案——xCrash
  • 字节跳动:深入理解Gradle框架之一:Plugin, Extension, buildSrc
  • 百度APP技术:Android H5首屏优化实践
  • 支付宝客户端架构解析:Android 客户端启动速度优化之「垃圾回收」
  • 携程:从智行 Android 项目看组件化架构实践
  • 网易新闻构建优化:如何让你的构建速度“势如闪电”?

在这里插入图片描述

四、高级kotlin强化实战

1、Kotlin入门教程
2、Kotlin 实战避坑指南
3、项目实战《Kotlin Jetpack 实战》

  • 从一个膜拜大神的 Demo 开始

  • Kotlin 写 Gradle 脚本是一种什么体验?

  • Kotlin 编程的三重境界

  • Kotlin 高阶函数

  • Kotlin 泛型

  • Kotlin 扩展

  • Kotlin 委托

  • 协程“不为人知”的调试技巧

  • 图解协程:suspend

在这里插入图片描述

五、Android高级UI开源框架进阶解密

1.SmartRefreshLayout的使用
2.Android之PullToRefresh控件源码解析
3.Android-PullToRefresh下拉刷新库基本用法
4.LoadSir-高效易用的加载反馈页管理框架
5.Android通用LoadingView加载框架详解
6.MPAndroidChart实现LineChart(折线图)
7.hellocharts-android使用指南
8.SmartTable使用指南
9.开源项目android-uitableview介绍
10.ExcelPanel 使用指南
11.Android开源项目SlidingMenu深切解析
12.MaterialDrawer使用指南
在这里插入图片描述

六、NDK模块开发

1、NDK 模块开发
2、JNI 模块
3、Native 开发工具
4、Linux 编程
5、底层图片处理
6、音视频开发
7、机器学习

在这里插入图片描述

七、Flutter技术进阶

1、Flutter跨平台开发概述
2、Windows中Flutter开发环境搭建
3、编写你的第一个Flutter APP
4、Flutter开发环境搭建和调试
5、Dart语法篇之基础语法(一)
6、Dart语法篇之集合的使用与源码解析(二)
7、Dart语法篇之集合操作符函数与源码分析(三)

在这里插入图片描述

八、微信小程序开发

1、小程序概述及入门
2、小程序UI开发
3、API操作
4、购物商场项目实战……

在这里插入图片描述

全套视频资料:

一、面试合集
在这里插入图片描述
二、源码解析合集

在这里插入图片描述
三、开源框架合集

在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

请添加图片描述

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值