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?
        137 0
        |
        Android开发
        ANR怎么产生的,怎么分析ANR?(二)
        ANR怎么产生的,怎么分析ANR?(二)
        95 0
        |
        Java 调度 C++
        ANR分析总结
        ANR分析总结
        1249 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:观察是谁调用了崩溃函数
        65 0
        |
        6月前
        |
        缓存 Java 数据库
        Android 性能优化: 请解释ANR(Application Not Responding)是什么,如何避免它?
        Android 性能优化: 请解释ANR(Application Not Responding)是什么,如何避免它?
        109 0
        |
        存储 iOS开发
        iOS主线程耗时检测方案
        找出那个拖后腿的凶手
        230 1
        iOS主线程耗时检测方案
        |
        存储 运维 监控
        mPass iOS崩溃与Crash⽇志符号化详解
        在日常mPaas客户端运维中,经常遇到一些iOS闪退,无法直接从闪退堆栈看到原因。主要是因为iOS客户端上传的崩溃日志里的调用栈信息都是通过内存地址记录的,无法直接看到闪退的调用栈信息。如果需要定位到调用栈,需要使用符号表对闪退日志进行符号化。本文从日志收集、日志符号化原理、符号化工具等方向介绍下iOS下crash日志符号化方案。
        1977 1
        mPass iOS崩溃与Crash⽇志符号化详解