Android学习笔记|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 Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件。
  • 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之后,会移除超时消息。
【Android学习笔记|Android ANR】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原理分析

    推荐阅读