ANR怎么产生的,怎么分析ANR?(三)

简介: ANR怎么产生的,怎么分析ANR?(三)

ContentProvider Timeout

ContentProvider Timeout 发生在应用启动过程中。如果应用启动时,Provider 发布超过限定时间就会触发 ANR。应用进程创建后,会调用 attachApplicationLocked() 进行初始化。

    frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
        // 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;
        ......
        private final boolean attachApplicationLocked(IApplicationThread thread,
                int pid, int callingUid, long startSeq) {
            ......
            // 如果应用存在 Provider,设置延迟消息处理 Provider 超时
            if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
                Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
                msg.obj = app;
                mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
            }
            ......
        }

    当在限定时间内没有完成 Provider 发布时,会发送消息 CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG,Handler 会进行相应处理。

      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
          final class MainHandler extends Handler {
              public MainHandler(Looper looper) {
                  super(looper, null, true);
              }
              @Override
              public void handleMessage(Message msg) {
                  switch (msg.what) {
                  ......
                  case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: {
                      // 处理 Provider 超时消息
                      ProcessRecord app = (ProcessRecord)msg.obj;
                      synchronized (ActivityManagerService.this) {
                          processContentProviderPublishTimedOutLocked(app);
                      }
                  } break
                  ......
              }
          }
          ......
          boolean removeProcessLocked(ProcessRecord app,
                  boolean callerWillRestart, boolean allowRestart, String reason) {
              final String name = app.processName;
              final int uid = app.uid;
              ......
              // 移除mProcessNames中的相应对象
              removeProcessNameLocked(name, uid);
              ......
              boolean needRestart = false;
              if ((app.pid > 0 && app.pid != MY_PID) || (app.pid == 0 && app.pendingStart)) {
                  int pid = app.pid;
                  if (pid > 0) {
                      // 杀进程前处理一些相关状态
                      ......
                  }
                  // 判断是否需要重启进程
                  boolean willRestart = false;
                  if (app.persistent && !app.isolated) {
                      if (!callerWillRestart) {
                          willRestart = true;
                      } else {
                          needRestart = true;
                      }
                  }
                  app.kill(reason, true); // 杀死进程
                  handleAppDiedLocked(app, willRestart, allowRestart); // 回收资源
                  if (willRestart) {
                      removeLruProcessLocked(app);
                      addAppLocked(app.info, null, false, null /* ABI override */);
                  }
              } else {
                  mRemovedProcesses.add(app);
              }
              return needRestart;
          }
          ......
          private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
              // 清理 Provider
              cleanupAppInLaunchingProvidersLocked(app, true);
              // 清理应用进程
              removeProcessLocked(app, false, true, "timeout publishing content providers");
          }
          ......
          boolean cleanupAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
              boolean restart = false;
              for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
                  ContentProviderRecord cpr = mLaunchingProviders.get(i);
                  if (cpr.launchingApp == app) {
                      if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) {
                          restart = true;
                      } else {
                          // 移除死亡的 Provider
                          removeDyingProviderLocked(app, cpr, true);
                      }
                  }
              }
              return restart;
          }

      可以看到 ContentProvider Timeout 发生时并没有调用 AMS.appNotResponding() 方法,仅仅杀死问题进程及清理相关信息。Provider 的超时消息会在发布成功时被清除,相关代码如下。

        frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
            public final void publishContentProviders(IApplicationThread caller,
                    List<ContentProviderHolder> providers) {
                ......
                synchronized (this) {
                    final ProcessRecord r = getRecordForAppLocked(caller);
                    ......
                    final int N = providers.size();
                    for (int i = 0; i < N; i++) {
                        ContentProviderHolder src = providers.get(i);
                        ......
                        ContentProviderRecord dst = r.pubProviders.get(src.info.name);
                        if (dst != null) {
                            ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
                            mProviderMap.putProviderByClass(comp, dst);
                            ......
                            if (wasInLaunchingProviders) {
                                // 移除超时消息
                                mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
                            }
                            ......
                        }
                    }
                    Binder.restoreCallingIdentity(origId);
                }
            }
        相关文章
        |
        Android开发
        ANR怎么产生的,怎么分析ANR?(二)
        ANR怎么产生的,怎么分析ANR?(二)
        95 0
        |
        大数据 数据库 Android开发
        ANR怎么产生的,怎么分析ANR?(一)
        ANR怎么产生的,怎么分析ANR?
        137 0
        |
        Java 调度 C++
        ANR分析总结
        ANR分析总结
        1250 0
        ANR分析总结
        |
        存储 监控 Android开发
        Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)
        Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)
        |
        Android开发
        为什么会触发ANR,从源码中扒一扒
        为什么会触发ANR,从源码中扒一扒
        98 0
        |
        6月前
        |
        JavaScript IDE Java
        bugly崩溃排查3:观察是谁调用了崩溃函数
        bugly崩溃排查3:观察是谁调用了崩溃函数
        66 0
        |
        6月前
        |
        缓存 Java 数据库
        Android 性能优化: 请解释ANR(Application Not Responding)是什么,如何避免它?
        Android 性能优化: 请解释ANR(Application Not Responding)是什么,如何避免它?
        110 0
        |
        Web App开发 缓存 监控
        一文教你轻松搞定ANR异常捕获与分析方法
        选择一款有超强捕获能力的专业产品,对于开发者定位和修复稳定性问题至关重要。友盟+U-APM SDK集成了UC 内核团队强大的技术及友盟+超强的错误捕获能力,通过数万次捕获实践中积累了丰富经验,在产品、性能和研发能力上都极大保障了开发者定位和修复稳定性问题的超强效率。
        一文教你轻松搞定ANR异常捕获与分析方法
        |
        Android开发 算法
        ANR简介以及解决方案
        同步发布在:http://snowdream.github.io/blog/2016/02/25/anr-introduce-and-solutions/ ANR ANR,英文全称为 Application Not Responding,即应用无响应。 具体表现,弹出一个应用无响应的窗口,
        3624 0