天天看点

Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

本文要点
  • ANR概述
  • 发生ANR后Android系统的执行流程
  • ANR-WatchDog原理与实战
  • ANR的传统解决套路
  • ANR模拟实战
  • 线上ANR监控方案【ANR-WatchDog原理分析】
  • ANR-WatchDog实战
  • ANR-WatchDog总结
  • ANR-WatchDog与AndroidPerformanceMonitor的区别
项目GitHub

ANR概述

  • KeyDispatchTimeout,5s

    即按键或者触摸事件,在特定的时间(一般5s)之内没有响应;

  • BroadcastTimeout,前台10s,后台60s

    BroadReceiver 在特定的时间(一般前台10s,后台60s)之内没有响应完成;

  • ServiceTimeout,前台20s,后台200s

    Service 在特定的时间(一般前台20s,后台200s)之内没有处理完成;

发生ANR后Android系统的执行流程

  • APP发生ANR
  • 进程接收异常终止信号,开始写入进程ANR信息(当时场景,包含当前线程所有堆栈信息、CPU/IO的使用情况等);
  • 弹出ANR提示框,提示用户关闭APP或者继续等待;(不同ROM表现不同,有的手机厂商会去掉这个提示框)

ANR的传统解决套路

  • 【线下】在AS的Terminal中,使用

    adb pull data/anr/traces.txt 要存储在本地的路径

    导出上面提到的

    ANR现场信息文件

    导出来后,便可对文件内容进行详细分析:从

    CPU、IO、锁冲突

    等原因思考;

ANR模拟实战

  • 模拟ANR原因:锁冲突;

    更改代码:

Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

运行程序,等到程序ANR或崩溃,

在Terminal使用刚刚提到的命令,导出ANR的信息文件:

Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

生成文件:

Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

打开文件,可以找到原因:

Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

上次的BlockCanary同样捕捉到原因:

Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

线下套路其实就是在APP发生ANR时,

导出信息文件,

查看文件,结合代码进行分析;

线上ANR监控方案

  • 通过

    FileOberver

    监控上述的ANR信息文件的变化,

    如果这个文件发生了变化,那就说明发生了ANR,

    那便可以把它上报到服务器,进行详细的分析;

    【高版本需注意权限问题】

  • ANR-WatchDog
    • 依赖

      compile 'com.github.anrwatchdog:anrwatchdog:1.4.0'

    • 官网 https://github.com/SalomonBrys/ANR-WatchDog
    • 原理(源码分析):

      ANRWatchDog

      本身就是

      Thread

      的子类:
    Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

    ANRWatchDog

    中,用一个绑定了主线程Looper的Handler,

    去处理

    _ticker

    【一个Runnable任务单元】;

    任务单元对一些值进行了处理,如

    _tick

    _reported

    Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

    _tick

    在初始为

    ANRWatchDog

    的全局变量时,被赋值为0;^^^^^^^^^^^^^^^^^

    ANRWatchDog

    run()

    中,

    首先被利用去判定

    _ticker

    被post没有(因为一开始就

    _tick

    为0的话说明

    _tick

    还没被post),

    没有便将

    _tick

    =加上

    卡顿周期

    ,之后post了

    _ticker

    此时

    _tick

    不为0!!^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    _ticker

    中的

    run()

    ,再一次将

    _tick

    置零;^^^^^^^^^^^^^^^^^^^^^^^^^^

    所以只要

    _ticker

    不被处理,其

    run()

    便不会执行,

    _tick

    就不会被置零,
    Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别
    由此根据

    _tick

    的值可以判断

    _ticker

    是否被处理了;

    _tick

    重新归零则主线程处理了

    _ticker

    _tick

    不为零则判定

    主线程卡顿

    ,它没处理

    _tick

    !!!!!!!!
    Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

    ANRWatchDog

    run()

    中,

    用刚说的主线程Handler,post了

    _ticker

    这个任务,

    然后自己sleep一段时间【即一个卡顿周期,稍后细说】,

    如果sleep结束之后,如果

    _tick != 0 && !_reported

    则说明主线程还没有处理

    _ticker

    run()

    没有处理

    _ticker

    这个任务单元,

    那便认为

    主线程

    发生了

    卡顿

    【如源码注释所示】:!!!!!!

    确定发生了卡顿,就开始封装一个

    ANRError

    ,进行后续处理了:
    Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别
    另外补充一下,

    ANRWatchDog

    提供了两个重载的构造器,

    提供给开发者对

    卡顿判定周期

    进行设置,开发者不设置则使用

    默认配置

    【跟

    BlockCanary

    同一个德行】
    Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别
    接着仔细看

    ANRError

    的构造流程
    Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别
    这里是有两种构造方式

    New()

    NewMainOnly()

    ,其最终处理都差不多,

    就是通过

    mainLooper

    拿到主线程,

    再通过主线程拿到

    现场的堆栈信息

    最后返回构造好的

    ANRError

    实例:
    Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别
    拿到

    ANRError

    实例之后,

    通过

    _anrListener.onAppNotResponding(error);

    回调机制处理

    ANRError

    实例;
    Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

    回调机制就妙啊!^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    刚刚的

    _anrListener.onAppNotResponding(error);

    只是一个应用层上的调用;

    onAppNotResponding()

    的实现方式暴露给开发者了,

    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    在外部可以通过

    setANRListener()

    自己定制包含不同处理方式的

    ANRListener

    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

    开发者不定制,则使用框架自带的默认处理方式呗:

    处理方式简单粗暴哈,直接把

    ANRError

    丢出去,

    这样APP就直接

    崩溃

    了:
    Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

    ANRError

    乃是

    Error

    的子类:
    Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

ANR-WatchDog实战

  • 引入依赖
  • 初始化ANR-WatchDog:
Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别
  • 还是上面那个项目,手动阻塞60s,

    运行程序,

    程序会5s后崩溃【5s是默认周期时间,崩溃操作见上面源码分析】

    logcat

    定位关键字

    fatal

    ,可以看到

    ANRError

    打印的信息,

    信息中包括了

    崩溃现场所有线程

    堆栈信息

    以及显示

    bug代码的位置

Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)ANR概述发生ANR后Android系统的执行流程ANR的传统解决套路ANR模拟实战线上ANR监控方案ANR-WatchDog实战总结与AndroidPerformanceMonitor的区别

优化:

当然默认的APP崩溃处理法并不妥当,

影响用户体验,

实际开发中,

我们可以自己定义

ANRListener

,自定义处理方式【上面说过了】,

把堆栈信息上报给服务器就是了!!!!

总结

  • 非浸入式
  • 弥补高版本无权限问题

与AndroidPerformanceMonitor的区别

  • AndroidPerformanceMonitor:

    原理是基于Handler-Message机制,

    监控主线程每一个Message的执行,

    在每一个Message的分发执行前后,进行信息处理;

    (不足:

    一般没有阻塞的情况下,

    每一个Message的执行时间是非常短暂的,

    达不到ANR的级别;

    而且InputEvent在queue.next中block,不会继续执行dispatchMessage,

    而是从native回调给InputEventReceiver.dispatchInputEvent处理分发,

    所以BlockCanary也就无法监控到这类ANR)

  • ANR-WatchDog:

    不管主线程是怎么执行的,

    只管最后的结果,

    我sleep一个周期之后,就要看我

    _tick

    值有没有被修改,

    没被修改就是ANR!

  • AndroidPerformanceMonitor

    适合全程监控卡顿,

    ANR-WatchDog

    适合补充ANR监控;

    两者可以相辅相成,结合使用!