当前位置:   article > 正文

Android ANR机制的原理以及问题分析(一)_timeout publishing content providers

timeout publishing content providers

一、前言

Android开发人员对ANR应该毫不陌生——Application Not Responding,即应用程序未响应。ANR的核心原理是消息机制的调度和超时处理,它要求主线程在限定时间内做完任务处理,比如:启动Activity/Service、发送广播、ContentProvider查询、Input事件分发等,否则就可能发生ANR引起性能问题。处理超时时,系统会认为当前主线程已经失去响应其他操作的能力。这些耗时操作包括:密集的CPU运算、大量的IO操作、复杂的media编解码、大量需要绘制的嵌套布局等等,这些都可能会降低主线程的响应能力。

PS:会有相当一部分的ANR问题是很难分析的,有时候由于系统底层的一些影响,导致消息调度失败,出现问题的场景难以复现。这类ANR问题往往需要花费大量的时间取了解系统的一些行为,除了了解ANR机制本身外,还需要对系统子功能模块的具体实现进行分析。

二、 ANR的类型

ANR大致可以分为以下四种类型:

  • Service Timeout(Timeout executing service:)

前台服务20s内未执行完成
后台服务200s内未执行完成

  • Broadcase Timeout(Timeout of broadcase:)

前台广播在10s内未执行完成
后台广播在60s内为执行完成

  • ContentProvider Timeout(Timeout publishing content providers:)

ContentProvider超时,这里分为两种情况:
【1】 publish时超过CONTENT_PROVIDER_PUBLISH_TIMEOUT 10s的时间,触发timeout publishing content providers,会直接kill,这一类的启动超时,有service,process,同样会触发.
【2】 对给定的provider进行操作时,如果通过setDetectNotResponding方法给定了超时时间,例如query时超过设定的时间会触发ANR

三、臭名昭著的ANR

在这里插入图片描述
我们遇到的ANR大部分都会出现类似上面的对话框,伴随着ANR的日志同步出现、分析一些初级的ANR问题,只需要简单看看输出的日志即可,但对于一些由系统原因(比如CPU负载过高、进程死锁)引发的ANR,就需要熟悉整个ANR机制,才有可能定位出问题的原因。

首先,通过查看log日志中的ANR in关键字找到AppErrors.java中appNotResponding()负责弹出上面这个ANR对话框。这个类核心功能就是负责显示ANR的对话框还有出现crash时出现的ForceClose对话框

appNotResponding具体代码逻辑如下:

  1. 如果有设置IActivityController的话,通知client端appEarlyNotResponding
  2. 检测是香是下面几种情况的ANR.如果是直接忽路
  3. 记录ANR出现时的1og.方便后面调试问题

如果没有生成对应的trace文件直接发送SIGNALQUIT命令,也就是kill-3

  1. 添加日志到Dropbox
  2. 通过Handler发送Message给AMS,通知运行在UiThread的UiHandler,显示ANR对话框
//frameworks/base/services/core/java/com/android/server/am/AppErrors.java

final void appNotResponding(ProcessRecord app, ActivityRecord activity,
        ActivityRecord parent, boolean aboveSystem, final String annotation) {
   
    ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
    SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);

    //【1】如果有设置IActivityController的话,通知client端appEarlyNotResponding
    if (mService.mController != null) {
   
        try {
   
            // 0 == continue, -1 = kill process immediately
            int res = mService.mController.appEarlyNotResponding(
                    app.processName, app.pid, annotation);
            if (res < 0 && app.pid != MY_PID) {
   
                app.kill("anr", true);
            }
        } catch (RemoteException e) {
   
            mService.mController = null;
            Watchdog.getInstance().setActivityController(null);
        }
    }
    //...省略
    synchronized (mService) {
   
        //【2】检测是否是下面几种情况的ANR,如果是直接返回
        // A:正在关机 B:已经出现了ANR的应用 C:已经崩溃的应用 D:AM杀死的应用 E:已经死亡的应用
        // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
        if (mService.mShuttingDown) {
   
            Slog.i(TAG, "During shutdown skipping ANR: " + app + " " 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/989623
推荐阅读
相关标签
  

闽ICP备14008679号