Android卡顿优化 | 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原因:锁冲突;

    更改代码:
    运行程序,等到程序ANR或崩溃,

    在Terminal使用刚刚提到的命令,导出ANR的信息文件:
    生成文件:
    打开文件,可以找到原因:
    上次的BlockCanary同样捕捉到原因:

线下套路其实就是在APP发生ANR时,
导出信息文件,
查看文件,结合代码进行分析;

线上ANR监控方案

  • 通过FileOberver监控上述的ANR信息文件的变化,
    如果这个文件发生了变化,那就说明发生了ANR,
    那便可以把它上报到服务器,进行详细的分析;
    【高版本需注意权限问题】

  • ANR-WatchDog

    • 依赖compile 'com.github.anrwatchdog:anrwatchdog:1.4.0'
    • 官网 https://github.com/SalomonBrys/ANR-WatchDog
    • 原理(源码分析):ANRWatchDog本身就是Thread的子类:
      ANRWatchDog中,用一个绑定了主线程Looper的Handler,
      去处理_ticker【一个Runnable任务单元】;
      任务单元对一些值进行了处理,如_tick_reported
      _tick在初始为ANRWatchDog的全局变量时,被赋值为0;^^^^^^^^^^^^^^^^^
      ANRWatchDogrun()中,
      首先被利用去判定_ticker被post没有(因为一开始就_tick为0的话说明_tick还没被post),
      没有便将_tick=加上卡顿周期,之后post了_ticker
      此时_tick不为0!!^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      _ticker中的run(),再一次将_tick置零;^^^^^^^^^^^^^^^^^^^^^^^^^^
      所以只要_ticker不被处理,其run()便不会执行,
      _tick就不会被置零,
      由此根据_tick的值可以判断_ticker是否被处理了;
      _tick重新归零则主线程处理了_ticker
      _tick不为零则判定主线程卡顿,它没处理_tick!!!!!!!!


      ANRWatchDogrun()中,
      用刚说的主线程Handler,post了_ticker这个任务,
      然后自己sleep一段时间【即一个卡顿周期,稍后细说】,
      如果sleep结束之后,如果_tick != 0 && !_reported
      则说明主线程还没有处理_tickerrun()
      没有处理_ticker这个任务单元,
      那便认为主线程发生了卡顿【如源码注释所示】:!!!!!!
      确定发生了卡顿,就开始封装一个ANRError,进行后续处理了:
      另外补充一下,
      ANRWatchDog提供了两个重载的构造器,
      提供给开发者对卡顿判定周期进行设置,开发者不设置则使用默认配置
      【跟BlockCanary同一个德行】
      接着仔细看ANRError的构造流程
      这里是有两种构造方式New()NewMainOnly(),其最终处理都差不多,
      就是通过mainLooper拿到主线程,
      再通过主线程拿到现场的堆栈信息
      最后返回构造好的ANRError实例:
      拿到ANRError实例之后,
      通过_anrListener.onAppNotResponding(error);回调机制处理ANRError实例;

      回调机制就妙啊!^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      刚刚的_anrListener.onAppNotResponding(error);只是一个应用层上的调用;
      onAppNotResponding()的实现方式暴露给开发者了,
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      在外部可以通过setANRListener()自己定制包含不同处理方式的ANRListener
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      开发者不定制,则使用框架自带的默认处理方式呗:
      处理方式简单粗暴哈,直接把ANRError丢出去,
      这样APP就直接崩溃了:
      ANRError乃是Error的子类:

ANR-WatchDog实战

  • 引入依赖
  • 初始化ANR-WatchDog:
  • 还是上面那个项目,手动阻塞60s,
    运行程序,
    程序会5s后崩溃【5s是默认周期时间,崩溃操作见上面源码分析】
    logcat定位关键字fatal,可以看到ANRError打印的信息,
    信息中包括了崩溃现场所有线程堆栈信息
    以及显示bug代码的位置

优化:
当然默认的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监控;
    两者可以相辅相成,结合使用!





参考:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容