zoukankan      html  css  js  c++  java
  • @Android ANR 监测方案解析

    ANR的触发条件

    ANR的本质是一个性能问题,即主线程中的耗时操作造成主线程堵塞,导致应用失去响应能力。常见的超时时限:

     

    Service与Bradcast只会打印trace信息,不会提示用户ANR弹窗,大部分可感知的ANR都是由于InputEvent。

    Android对ANR的监控机制

    Android应用程序是通过消息来驱动的,Android某种意义上也可以说成是一个以消息驱动的系统,UI、事件、生命周期都和消息处理机制息息相关。Android的ANR监测方案也是一样,大部分就是利用了Android的消息机制。

     

    InputEvent的ANR与上图有些许不同,是在Native监控,但同样会堵塞主线程的消息队列,后面会讲到一部分监测场景。

    应用ANR检测方案

    目前流行的ANR检测方案有开源的BlockCanary 、ANR-WatchDog、SafeLooper, 还有根据谷歌原生系统接口监测的方案:FileObserver。下面就针对这四种方案根据场景解析对比。

    BlockCanary

    BlockCanary是国内开发者markzhai开发的一款非侵入式的轻量性能监控组件,在Github上有接近4000 star。原理巧妙的利用了Android原生Looper.loop中的一个log打印逻辑。

     

    这个log打印逻辑正是在Message消息分发前后,大部分的性能卡顿问题都是在这里发生的,监控这两个逻辑之间的时间差就可以得到当前主线程的卡顿状态,如果超时则获取trace信息并上报。具体实现:

     
     
    • 优点
      灵活配置可监控常见APP应用性能也可作为一部分场景的ANR监测,并且可以准确定位ANR和耗时调用栈。

    • 缺点
      但BlockCanary应用在ANR监控上有几个比较严重的问题
      1、 谷歌已经明确标注This must be in a local variable, in case a UI event sets the logger这个looger对象是可以被更改的,已经有开发者遇到在使用WebView时logger被set为Null导致BlockCanary失效,只能让BlockCanary在WebView初始化之后调用start。
      2、 如果dispatchMessage执行的非常久是无法触发BlockCanary的逻辑。
      3、 谷歌在Looper中还有一个标注

       

      这里的queue.next是可能block的,场景就是文章开始提到的InputEvent。此处block同样会触发ANR,但BlockCanary同样无法适用的。一个例子可以验证下:

       

      在Activity中重写dispatchTouchEvent和dispatchKeyEvent,模拟耗时操作,弹出ANR告警,但BlockCanary没有任何反应,查看调用栈。

       

      会看到InputEvent在queue.next中block,不会继续执行dispatchMessage,而是从native回调给InputEventReceiver.dispatchInputEvent处理分发,所以BlockCanary也就无法监控到这类ANR。
      4、 无法监控CPU资源紧张造成系统卡顿,无法响应的ANR。

    ANR-WatchDog

    ANR-WatchDog是参考Android WatchDog机制(com.android.server.WatchDog.java)起个单独线程向主线程发送一个变量+1操作,自我休眠自定义ANR的阈值,休眠过后判断变量是否+1完成,如果未完成则告警。

     

     
    • 优点
      1、 兼容性好,各个机型版本通用
      2、 无需修改APP逻辑代码,非侵入式
      3、 逻辑简单,性能影响不大

    • 缺点
      无法保证能捕捉所有ANR,对阈值的设置直接影响捕获概率。如图:

       

      如果对线程的堵塞大于10s则设置监控阈值5s能捕获所有ANR,堵塞时间在5s~10s,则可能出现无法捕获场景。

    SafeLooper

    SafeLooper是个比较新奇的思路,本身就是一个堵塞的消息,在自己内部进行消息的处理,通过反射接管主线程Looper的功能。

     

    此方案使用反射进行message管理会有很大的性能损耗,但可以自由定制,这种AOP的思想是可以借鉴的。

    FileObserver

    有ANR的流程就可以知道/data/anr文件夹的变化代表着ANR的发生,AMS在dumpStackTrace方法中给了我们一些提示。

     

    按照这个思路,当ANR发生的时候,我们是可以通过监听该文件的写入情况来判断是否发生了ANR,看起来这是一个不错的时机。需要注意的是,所有应用发生ANR的时候都会进行回调,因此需要做一些过滤与判断,如包名、进程号等。ANR生成的trace如图:

     
    • 优点
      1、基于原生接口调用,时机和内容准确。
      2、无性能问题实现简单

    • 缺点
      最大的困难是兼容性问题,这个方案受限于Android系统的SELinux机制,5.0以后基本已经使低权限应用无法监听到trace文件了,但是可以在开发内测阶段通过root手机修改app对应的te文件提权进行监控。Android 7.1.1版本的测试截图

       

      可以看到很多应用都尝试监听ANR文件,但是都被权限拒绝,属于不受信任应用。
      SELinux(或SEAndroid)将app划分为主要三种类型(根据user不同,也有其他的domain类型):
      1、untrusted_app:第三方app,没有android平台签名,没有system权限
      2、platform_app:有android平台签名,没有system权限
      3、system_app:有android平台签名和system权限
      从上面划分,权限等级,理论上:untrusted_app < platform_app < system_app

    总结

    本文汇总了目前主流的ANR监测方案的原理和实现,目前能了解到的方案并不太多,在Goolge Play上有2.68%实用率的ACRA库也只是推荐了WatchDog方式。建议 FileObserver和watchDog组合使用,能覆盖绝大部分的机型和ANR异常。如果其他同学有更好的建议和方案欢迎交流,共同进步。



    作者:奶盖ww
    链接:https://www.jianshu.com/p/473abd102604
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    leetcode Remove Linked List Elements
    leetcode Word Pattern
    leetcode Isomorphic Strings
    leetcode Valid Parentheses
    leetcode Remove Nth Node From End of List
    leetcode Contains Duplicate II
    leetcode Rectangle Area
    leetcode Length of Last Word
    leetcode Valid Sudoku
    leetcode Reverse Bits
  • 原文地址:https://www.cnblogs.com/chenxibobo/p/14230278.html
Copyright © 2011-2022 走看看