Android ANR

Android ANR

文章目录

  • Android ANR
  • 1.ANR简单介绍
      • 1.1 产生ANR的场景
      • 1.2 ANR具体时间定义
  • 2.ANR触发分析
      • 2.1 Input相关
      • 2.2 Service相关
      • 2.3Broadcast相关
      • 2.4 ContentProvider相关
    • 参考资料

1.ANR简单介绍

  • ANR:应用程序无响应(Application Not Responding)

1.1 产生ANR的场景

  • InputDispatching Timeout5秒内无法响应屏幕触摸事件或键盘输入事件。
  • Service Timeout:前台服务20秒内内没有执行完毕。
  • BroadcastQueue Timeout:在执行前台广播10秒没有处理完成。
  • ContentProvider Timeout :ContentProvider的publish在10秒内没进行完。

1.2 ANR具体时间定义

  • Service Timeout相关:(ActiveServices.java)

    // How long we wait for a service to finish executing.
    static final int SERVICE_TIMEOUT = 20*1000;
    // How long we wait for a service to finish executing.
    static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
    // How long the startForegroundService() grace period is to get around to
    // calling startForeground() before we ANR + stop it.
    static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000;
    
    • 前台服务20s。
    • 后台服务200s。
  • BroadcastQueue Timeout相关:(ActivityManagerService.java)

    // How long we allow a receiver to run before giving up on it.
    static final int BROADCAST_FG_TIMEOUT = 10*1000;
    static final int BROADCAST_BG_TIMEOUT = 60*1000;
    
    • 前台广播10s。
    • 后台广播60s。
  • ContentProvider Timeout相关

    // How long we wait for an attached process to publish its content providers
    // before we decide it must be hung.
    static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
    

2.ANR触发分析

2.1 Input相关

  • ANR检测区间主要指:当前事件dispatch过程中执行**findFocusedWindowTargetsLocked()方法到下一次执行resetANRTimeoutsLocked()**的时间区间。
  • Input ANR 的实现是通过将InputManagerService加入到Watchdog的monitor队列,定时监测是否发生死锁。

2.2 Service相关

超时设置:

  • Service进程attach到system_server进程的过程中会调用**realStartServiceLocked()**方法。

  • realStartServiceLocked()方法中会调用**bumpServiceExecutingLocked()**方法。

  • bumpServiceExecutingLocked()方法又会调用**scheduleServiceTimeoutLocked()**方法。

    // scheduleServiceTimeoutLocked方法节选
    mAm.mHandler.sendMessageDelayed(msg,
            proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
    
    • scheduleServiceTimeoutLocke()方法通过delay消息(SERVICE_TIMEOUT_MSG)设置了服务超时。
    • 如果不能在规定时间内移除该消息(SERVICE_TIMEOUT_MSG),则会触发ANR。

超时移除:

  • (ActivityThread.java)目标进程主线程会调用**handleCreateService()**方法。

    // handleCreateService方法节选
    ...
    try {
        // 创建ContextImpl对象
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        context.setOuterContext(service);
        // 创建Application对象
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
        // 调用服务的onService()方法
        service.onCreate();
        mServices.put(data.token, service);
        try {
            // 移除超时消息
            ActivityManager.getService().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } ...
    
  • **serviceDoneExecuting()**方法中会从消息队列中将消息(SERVICE_TIMEOUT_MSG)异常。

    // 位于ActivieService.java
    private void serviceDoneExecutingLocked(){
        ...
        mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
        ...
    }
    
  • 移除后则不会触发ANR。

ANR触发:

  • 当AMS(ActivityManagerService)收到SERVICE_TIMEOUT_MSG消息,调用serviceTimeout()方法。

    ...
    case SERVICE_TIMEOUT_MSG: {
        mServices.serviceTimeout((ProcessRecord)msg.obj);
    } break;
    ...
    
  • serviceTimeout()方法会调用**appNotResponding()**方法。

    ...
    if (anrMessage != null) {
        proc.appNotResponding(null, null, null, null, false, anrMessage);
    }
    ...
    
  • 至此触发了ANR异常。

2.3Broadcast相关

超时设置:

  • 调用**processNextBroadcast()**方法来处理广播。
    • 通过调用**setBroadcastTimeoutLocked()**方法设置超时消息(BROADCAST_TIMEOUT_MSG)。
    • 当广播接收者等待时间过长,会调用**broadcastTimeoutLocked(false)**方法。
    • 当广播执行完,会调用**cancelBroadcastTimeoutLocked()**方法,取消超时消息。
      超时移除:
  • 与Service大致相同,但是通过静态注册的广播超时会受SharedPreference的影响,动态注册的广播不会受到影响。
  • 当SharedPreference有未同步到磁盘的工作,则需等待其完成,才告知系统已完成该广播。

ANR触发:

  • (BroadcastQueue.java)BroadcastHandler处理超时消息(BROADCAST_TIMEOUT_MSG)会调用**broadcastTimeoutLocked(true)**方法。
  • 在 broadcastTimeoutLocked()方法中:
    • mOrderedBroadcasts已处理完成,则不会ANR。
    • 在执行dexopt,则不会ANR。
    • 系统还没有进入ready状态(mProcessesReady=false),则不会ANR。
    • 如果当前正在执行的receiver没有超时,则重新设置广播超时,不会ANR。
  • 否则触发ANR异常。

2.4 ContentProvider相关

超时设置:

  • Provider启动,在进程创建后会调用**attachApplicationLocked()**进入system_server进程。
  • attachApplicationLocked()方法中会设置超时消息(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG)。

超时移除:

  • provider成功publish之后,会移除超时消息。

ANR触发:

  • (ActivityManagerService.java)MainHandler处理超时消息(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG),调用**processContentProviderPublishTimedOutLocked()**方法。
  • processContentProviderPublishTimedOutLocked()方法会调用**cleanupAppInLaunchingProvidersLocked()方法和removeProcessLocked()**方法。
  • cleanupAppInLaunchingProvidersLocked()方法会调用**removeDyingProviderLocked()**方法。
  • removeDyingProviderLocked()方法会:
    • 对于stable类型的provider(即conn.stableCount > 0),会杀掉所有跟该provider建立stable连接的非persistent进程。
    • 对于unstable类的provider(即conn.unstableCount > 0),不会导致client进程被级联所杀。
  • removeProcessLocked()方法终止进程,不会弹出ANR的对话框。

参考资料

  • 理解Android ANR的触发原理
  • Android ANR:原理分析及解决办法
  • Input系统—ANR原理分析

你可能感兴趣的:(Android学习笔记,#,Android基础知识,android)