Android的ANR原理分析

大概

Android的ANR主要有兩種方式:
1. 通過(guò)handler的延遲機(jī)制觸發(fā)ANR
2. Input事件觸發(fā)ANR
Service踢俄、BroadcastReceiver聂宾、ContentProvider都是通過(guò)Hander機(jī)制觸發(fā)ANR。

ANR的發(fā)生的場(chǎng)景有:

  • service timeout:前臺(tái)服務(wù)在20s未執(zhí)行完虚倒,后臺(tái)服務(wù)200s未執(zhí)行完美侦。
  • BroadcastQueue timeout:前臺(tái)廣播在10s未執(zhí)行完,后臺(tái)廣播在60s未執(zhí)行完魂奥。
  • ContentProvider timeout: ContentProvider在發(fā)布時(shí)超過(guò)10s未執(zhí)行完菠剩。
  • InputDispatching Timeout:輸入分發(fā)事件超過(guò)5s未執(zhí)行完。

ANR的過(guò)程總體就是:裝炸彈耻煤、拆炸彈具壮、引爆炸彈

1. Service Timeout

在文章startService啟動(dòng)流程可以知道Service的生命周期和啟動(dòng)流程。

Service的生命周期

啟動(dòng)流程

裝彈

ActiveServices.realStartServiceLocked()方法中開(kāi)始真正執(zhí)行Service的生命周期方法哈蝇,并開(kāi)始裝炸彈的開(kāi)始嘴办。

 private final void realStartServiceLocked(ServiceRecord r,
                                            ProcessRecord app, boolean execInFg) throws RemoteException {
   
      // handle發(fā)送延遲消息,如果在規(guī)定時(shí)間還沒(méi)有被取消买鸽,則證明方法執(zhí)行時(shí)間長(zhǎng),則拋ANR異常贯被。
      bumpServiceExecutingLocked(r, execInFg, "create");
      //...
      try {
          //調(diào)用Service對(duì)應(yīng)onCreate()方法
          app.thread.scheduleCreateService(r, r.serviceInfo,
                  mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                  app.getReportedProcState());
   
      } catch (DeadObjectException e) {
          mAm.appDiedLocked(app, "Died when creating service");
          throw e;
      } finally {
         //...
      }

  }

// 通過(guò)Handler發(fā)送延遲時(shí)間眼五,到時(shí)間內(nèi)沒(méi)被取消則拋ANR異常
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
    ....
    // 發(fā)送Handler
    scheduleServiceTimeoutLocked(r.app);
  }

 //  發(fā)送延遲消息
  void scheduleServiceTimeoutLocked(ProcessRecord proc) {
      if (proc.executingServices.size() == 0 || proc.thread == null) {
          return;
      }
      Message msg = mAm.mHandler.obtainMessage(
              ActivityManagerService.SERVICE_TIMEOUT_MSG);
      msg.obj = proc;
      //當(dāng)超時(shí)后仍沒(méi)有remove該SERVICE_TIMEOUT_MSG消息妆艘,則執(zhí)行service Timeout流程
      mAm.mHandler.sendMessageDelayed(msg,
              proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
  }
  static final int SERVICE_TIMEOUT = 20 * 1000;
  static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;

在執(zhí)行生命周期的方法前會(huì)通過(guò)bumpServiceExecutingLocked()方法進(jìn)行裝炸彈,通過(guò)Handler機(jī)制發(fā)送一個(gè)標(biāo)志為SERVICE_TIMEOUT_MSG的延遲消息看幼,如果是前臺(tái)則20s,是后臺(tái)則200s執(zhí)行批旺。

拆彈

在執(zhí)行完Service的生命周期方法后就會(huì)執(zhí)行拆彈,比如onCreate()方法在Application.handleCreateService()執(zhí)行完畢:

 private class ApplicationThread extends IApplicationThread.Stub {

  // 創(chuàng)建對(duì)應(yīng)的Service并執(zhí)行onCreate()方法
  private void handleCreateService(CreateServiceData data) {
   
      try {
          ....
          // 調(diào)用service.attach綁定資源文件
          service.attach(context, this, data.info.name, data.token, app,
                  ActivityManager.getService());
          // 調(diào)用 service.onCreate()方法
          service.onCreate();
        
          try {
              // onCreate()執(zhí)行完成诵姜,拆彈過(guò)程汽煮,最終調(diào)用到ActiveServices.serviceDoneExecutingLocked方法
              ActivityManager.getService().serviceDoneExecuting(
                      data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      } catch (Exception e) {
        //...
      }
  }


   // AMS
    public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
        synchronized (this) {
            if (!(token instanceof ServiceRecord)) {
                Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
                throw new IllegalArgumentException("Invalid service token");
            }
            mServices.serviceDoneExecutingLocked((ServiceRecord) token, type, startId, res);
        }
    }


    // ActiveServices
    private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
                                            boolean finishing) {
        //...
        // 取消SERVICE_TIMEOUT_MSG消息,拆出炸彈
        mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
        //...       
    }

如果在生命周期方法內(nèi)執(zhí)行完棚唆,會(huì)回調(diào)AMS的方法暇赤,解除SERVICE_TIMEOUT_MSG延遲發(fā)送的消息。

引爆彈

如果Service方法在規(guī)定時(shí)間內(nèi)沒(méi)有執(zhí)行完成宵凌,則會(huì)執(zhí)行AMS.MainHandlerSERVICE_TIMEOUT_MSG類型的消息:

    // AMS
    final class MainHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SERVICE_TIMEOUT_MSG: {
                    mServices.serviceTimeout((ProcessRecord) msg.obj);
                }
                break;
            }
        }
    }

    // ActiveServices
    void serviceTimeout(ProcessRecord proc) {
        // 如果超時(shí)鞋囊,調(diào)用appNotResponding()方法
        if (anrMessage != null) {
            mAm.mAnrHelper.appNotResponding(proc, anrMessage);
        }
    }

如果超時(shí)則會(huì)觸發(fā)ANR,調(diào)用mAm.mAnrHelper.appNotResponding()方法。

2. BroadcastReceiver Timeout

image.png

裝彈

在文章廣播的注冊(cè)瞎惫、發(fā)送原理流程可以了解溜腐,發(fā)送廣播后調(diào)用之行對(duì)應(yīng)的廣播接收器的方法,對(duì)應(yīng)的方法在BroadcastQueue.processNextBroadcast()

  public final class BroadcastQueue {

        final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
            BroadcastRecord r;

            // 處理當(dāng)前有序廣播
            do {
                // 獲取BroadcastRecord
                final long now = SystemClock.uptimeMillis();
                r = mDispatcher.getNextBroadcastLocked(now);

                //當(dāng)廣播處理時(shí)間超時(shí)瓜喇,則強(qiáng)制結(jié)束這條廣播
                if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {
                    if ((numReceivers > 0) &&
                            (now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
                        broadcastTimeoutLocked(false); // forcibly finish this broadcast
                        forceReceive = true;
                        r.state = BroadcastRecord.IDLE;
                    }
                }
                //...
                if (r.receivers == null || r.nextReceiver >= numReceivers
                        || r.resultAbort || forceReceive) {
                    if (r.resultTo != null) {
                        //...
                        //處理廣播消息消息,調(diào)用到onReceive()
                        performReceiveLocked(r.callerApp, r.resultTo,
                                new Intent(r.intent), r.resultCode,
                                r.resultData, r.resultExtras, false, false, r.userId);
                        //...
                    }

                    //拆炸彈
                    cancelBroadcastTimeoutLocked();
                    r = null;
                    looped = true;
                    continue;
                }
                //..
            } while (r == null);


            //獲取下一個(gè)receiver的index
            int recIdx = r.nextReceiver++;
            if (!mPendingBroadcastTimeoutMessage) {
                long timeoutTime = r.receiverTime + mTimeoutPeriod;
                //裝炸彈乘寒,設(shè)置廣播超時(shí)時(shí)間望众,發(fā)送BROADCAST_TIMEOUT_MSG
                setBroadcastTimeoutLocked(timeoutTime);
            }

            //...
        }

        // 裝彈
        final void setBroadcastTimeoutLocked(long timeoutTime) {
            if (!mPendingBroadcastTimeoutMessage) {
                Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
                mHandler.sendMessageAtTime(msg, timeoutTime);
                mPendingBroadcastTimeoutMessage = true;
            }
        }

    }

通過(guò)setBroadcastTimeoutLocked()方法進(jìn)行裝彈。

拆彈

通過(guò)上面的processNextBroadcastLocked()方法可知肃续,調(diào)用cancelBroadcastTimeoutLocked()進(jìn)行拆彈黍檩。

    // 拆彈
    final void cancelBroadcastTimeoutLocked() {
        if (mPendingBroadcastTimeoutMessage) {
            mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
            mPendingBroadcastTimeoutMessage = false;
        }
    }

引爆彈

通過(guò)BroadcastHandlerBROADCAST_TIMEOUT_MSG類型的消息的執(zhí)行,進(jìn)行引爆炸彈始锚。

    public void handleMessage(Message msg) {
        switch (msg.what) {
            case BROADCAST_TIMEOUT_MSG: {
                synchronized (mService) {
                    // 調(diào)用broadcastTimeoutLocked()方法
                    broadcastTimeoutLocked(true);
                }
            }
            break;
        }
    }


    final void broadcastTimeoutLocked(boolean fromMsg) {
        ...
        // 如果超時(shí)刽酱,調(diào)用AMS.mAnrHelper.appNotResponding
        if (!debugging && anrMessage != null) {
            mService.mAnrHelper.appNotResponding(app, anrMessage);
        }
    }

最后也是調(diào)用AMS.mAnrHelper.appNotResponding()方法

3. ContentProvider Timeout

裝彈

ContentProvider的注冊(cè)在啟動(dòng)進(jìn)程的時(shí)候就開(kāi)始執(zhí)行,在注冊(cè)的過(guò)程中會(huì)向AMS綁定Application瞧捌,如果有ContentProvider就裝彈棵里,方法在AMS.attachApplicationLocked()方法中:

    // AMS
    private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
                                            int pid, int callingUid, long startSeq) {

        //...
        boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
        List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;

        if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
            // 裝彈
            Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
            msg.obj = app;
            mHandler.sendMessageDelayed(msg,
                    ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS);
        }
    }

    public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS = 10 * 1000;

在綁定Application時(shí),會(huì)判斷是否有ContentProvider時(shí)會(huì)裝炸彈進(jìn)行一個(gè)CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息的延遲發(fā)送姐呐。

拆彈

AT.installContentProviders()安裝完后會(huì)調(diào)用AMS.publishContentProviders()方法進(jìn)行拆彈殿怜。

    public final void publishContentProviders(IApplicationThread caller,
                                              List<ContentProviderHolder> providers) {
        ...
        // 拆彈,移除CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息
        mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r)

    }

引爆彈

如果消息沒(méi)被移除則引爆炸彈,CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG的handler在AMS.MainHandler中曙砂,

    public void handleMessage(Message msg) {
        switch (msg.what) {
            case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: {
                ProcessRecord app = (ProcessRecord) msg.obj;
                synchronized (ActivityManagerService.this) {
                    processContentProviderPublishTimedOutLocked(app);
                }
            }
            break;
        }
    }

    private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
        //移除死亡的provider
        cleanupAppInLaunchingProvidersLocked(app, true);
        //移除mProcessNames中的相應(yīng)對(duì)象
        mProcessList.removeProcessLocked(app, false, true,
                ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
                ApplicationExitInfo.SUBREASON_UNKNOWN,
                "timeout publishing content providers");
    }

4. InputDispatching Timeout

InputReader 不斷的從EventHub中監(jiān)聽(tīng)是否有Input事件头谜,InputReader把事件分發(fā)給InputDispatcher
InputDispatcher調(diào)用dispatchOnce()方法開(kāi)始把事件分發(fā)給對(duì)應(yīng)的View,就從InputDispatcher的分發(fā)開(kāi)始監(jiān)控ANR鸠澈,InputDispatcher的ANR區(qū)間是查找窗口findFocusedWindowTargetsLocked()方法到resetANRTimeoutsLocked()重置方法柱告。

    void InputDispatcher::dispatchOnce() {
        ...
        // 調(diào)用dispatchOnceInnerLocked進(jìn)行分析
        dispatchOnceInnerLocked(&nextWakeupTime);
    }

    void InputDispatcher::dispatchOnceInnerLocked(nsecs_t*nextWakeupTime) {
        nsecs_t currentTime = now();
        // ...
        // 重置標(biāo)記
        resetANRTimeoutsLocked();

        switch (mPendingEvent -> type) {

            case EventEntry::TYPE_KEY: {
                ...
                // key類型
                done = dispatchKeyLocked(currentTime, typedEntry, & dropReason, nextWakeupTime);
                break;
            }

            case EventEntry::TYPE_MOTION: {
                ...
                done = dispatchMotionLocked(currentTime, typedEntry,
                        & dropReason, nextWakeupTime);
                break;
            }

            default:
                ALOG_ASSERT(false);
                break;
        }
    }


    void InputDispatcher::resetANRTimeoutsLocked() {
        // 將mInputTargetWaitCause設(shè)置為INPUT_TARGET_WAIT_CAUSE_NONE
        mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
        mInputTargetWaitApplicationToken.clear();
    }

在分發(fā)之前會(huì)調(diào)用resetANRTimeoutsLocked()方法截驮,重置mInputTargetWaitCause標(biāo)記為:INPUT_TARGET_WAIT_CAUSE_NONE。接著根據(jù)下發(fā)的類型际度,尋找對(duì)應(yīng)的窗口葵袭,比如KEY類型,則調(diào)用dispatchKeyLocked()方法乖菱。

    bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry*entry,
                      DropReason*dropReason, nsecs_t*nextWakeupTime) {

        // 尋找目標(biāo)窗口
        int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime);

        // 給目標(biāo)窗口分發(fā)事件
        dispatchEventLocked(currentTime, entry, inputTargets);
        return true;
    }

    int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
        const EventEntry*entry, std::vector<InputTarget>&inputTargets, nsecs_t*nextWakeupTime) {
        ...
        // 檢查窗口不能input的原因
        reason = checkWindowReadyForMoreInputLocked(currentTime,
                focusedWindowHandle, entry, "focused");
        if (!reason.empty()) {
            // 調(diào)用handleTargetsNotReadyLocked()方法
            injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                    focusedApplicationHandle, focusedWindowHandle, nextWakeupTime, reason.c_str());
         goto Unresponsive;
        }

        ...
        return injectionResult;
    }

    int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,const EventEntry*entry,const sp<InputApplicationHandle>&applicationHandle,const sp<InputWindowHandle>&windowHandle,
                                nsecs_t*nextWakeupTime, const char*reason) {
        // 在resetANRTimeoutsLocked方法中坡锡,mInputTargetWaitCause為INPUT_TARGET_WAIT_CAUSE_NONE
        if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
            // DEFAULT_INPUT_DISPATCHING_TIMEOUT為5s
            nsecs_t timeout;
            if (windowHandle != nullptr) {
                timeout = windowHandle -> getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
            } else if (applicationHandle != nullptr) {
                timeout = applicationHandle -> getDispatchingTimeout(
                        DEFAULT_INPUT_DISPATCHING_TIMEOUT);
            } else {
                timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT;
            }
            // 要等到下次調(diào)用resetANRTimeoutsLocked時(shí)才能進(jìn)
            mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
            // 當(dāng)前時(shí)間加上5s
            mInputTargetWaitTimeoutTime = currentTime + timeout;
            mInputTargetWaitTimeoutExpired = false;
            mInputTargetWaitApplicationToken.clear();

        }

        if (mInputTargetWaitTimeoutExpired) {
            return INPUT_EVENT_INJECTION_TIMED_OUT;
        }

        if (currentTime >= mInputTargetWaitTimeoutTime) {
            // 當(dāng)前時(shí)間超過(guò)設(shè)定的5s,后執(zhí)行onANRLocked()的ANR方法
            onANRLocked(currentTime, applicationHandle, windowHandle,
                    entry -> eventTime, mInputTargetWaitStartTime, reason);
            return INPUT_EVENT_INJECTION_PENDING;
        } else {
            // Force poll loop to wake up when timeout is due.
            if (mInputTargetWaitTimeoutTime < *nextWakeupTime){
                     *nextWakeupTime = mInputTargetWaitTimeoutTime;
            }
            return INPUT_EVENT_INJECTION_PENDING;
        }
    }

在分發(fā)一次事件時(shí)窒所,會(huì)調(diào)用resetANRTimeoutsLocked將標(biāo)記為INPUT_TARGET_WAIT_CAUSE_NONE,所以第一次事件會(huì)設(shè)置一個(gè)5s后的超時(shí)時(shí)間鹉勒,并把標(biāo)記設(shè)置為INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY,如果下次事件來(lái)臨時(shí)當(dāng)前的時(shí)間超過(guò)上次設(shè)置的5s時(shí)間就會(huì)調(diào)用onANRLocked()方法產(chǎn)生ANR墩新。

    void InputDispatcher::onANRLocked(
            nsecs_t currentTime, const sp<InputApplicationHandle>&applicationHandle,
            const sp<InputWindowHandle>&windowHandle,
            nsecs_t eventTime, nsecs_t waitStartTime, const char*reason) {
        float dispatchLatency = (currentTime - eventTime) * 0.000001f;
        float waitDuration = (currentTime - waitStartTime) * 0.000001f;

        // 收集ANR現(xiàn)場(chǎng)信息
        time_t t = time(nullptr);
        struct tm tm;
        localtime_r( & t, &tm);
        char timestr[ 64];
        strftime(timestr, sizeof(timestr), "%F %T", & tm);
        mLastANRState.clear();
        mLastANRState += INDENT "ANR:\n";
        mLastANRState += StringPrintf(INDENT2"Time: %s\n", timestr);
        mLastANRState += StringPrintf(INDENT2"Window: %s\n",
                getApplicationWindowLabel(applicationHandle, windowHandle).c_str());
        mLastANRState += StringPrintf(INDENT2"DispatchLatency: %0.1fms\n", dispatchLatency);
        mLastANRState += StringPrintf(INDENT2"WaitDuration: %0.1fms\n", waitDuration);
        mLastANRState += StringPrintf(INDENT2"Reason: %s\n", reason);
        //dump信息
        dumpDispatchStateLocked(mLastANRState);
        //將ANR命令加入commandQueue
        CommandEntry * commandEntry = postCommandLocked(
                & InputDispatcher::doNotifyANRLockedInterruptible);
        commandEntry -> inputApplicationHandle = applicationHandle;
        commandEntry -> inputChannel = windowHandle != nullptr ?
                getInputChannelLocked(windowHandle -> getToken()) : nullptr;
        commandEntry -> reason = reason;
    }

在下次執(zhí)行InputDispatcher.dispatchOnce時(shí)會(huì)先執(zhí)行commandQueue的隊(duì)列命令贸弥,這里把InputDispatcher::doNotifyANRLockedInterruptible放入到了隊(duì)列。

    void InputDispatcher::doNotifyANRLockedInterruptible(CommandEntry*commandEntry) {
        mLock.unlock();
        //mPolicy是指NativeInputManager
        nsecs_t newTimeout = mPolicy -> notifyANR(
                commandEntry -> inputApplicationHandle,
                commandEntry -> inputChannel ? commandEntry -> inputChannel -> getToken() : nullptr,
                commandEntry -> reason);

        mLock.lock();

        resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
                commandEntry -> inputChannel);
    }

mPolicy -> notifyANR通過(guò)JNI最終調(diào)用到InputManagerService.notifyANR()方法:

   // InputManagerService
    private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
                           String reason) {
        return mWindowManagerCallbacks.notifyANR(inputApplicationHandle,
                token, reason);
    }

這里的mWindowManagerCallbacks是InputManagerCallback對(duì)象

//InputManagerCallback
    public long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
                          String reason) {
        final long startTime = SystemClock.uptimeMillis();
        try {
            return notifyANRInner(inputApplicationHandle, token, reason);
        } finally {
        }
    }

    private long notifyANRInner(InputApplicationHandle inputApplicationHandle, IBinder token,
                                String reason) {
        ...
        // 調(diào)用AMS的inputDispatchingTimedOut()方法
        long timeout = mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem,
                reason);

        return 0; // abort dispatching
    }

最終調(diào)用到AMS.inputDispatchingTimedOut()方法

    // AMS
    long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
        if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Requires permission " + FILTER_EVENTS);
        }
        ProcessRecord proc;
        long timeout;
        synchronized (this) {
            synchronized (mPidsSelfLocked) {
                proc = mPidsSelfLocked.get(pid);
            }
            timeout = proc != null ? proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
        }
        // 調(diào)用inputDispatchingTimedOut
        if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason)) {
            return -1;
        }

        return timeout;
    }


    boolean inputDispatchingTimedOut(ProcessRecord proc, String activityShortComponentName,
                                     ApplicationInfo aInfo, String parentShortComponentName,
                                     WindowProcessController parentProcess, boolean aboveSystem, String reason) {
            // 調(diào)用appNotResponding方法
            mAnrHelper.appNotResponding(proc, activityShortComponentName, aInfo,
                    parentShortComponentName, parentProcess, aboveSystem, annotation);

        return true;
    }

還是執(zhí)行appNotResponding()方法海渊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绵疲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子臣疑,更是在濱河造成了極大的恐慌盔憨,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讯沈,死亡現(xiàn)場(chǎng)離奇詭異郁岩,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)缺狠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門问慎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人挤茄,你說(shuō)我怎么就攤上這事如叼。” “怎么了穷劈?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵笼恰,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我歇终,道長(zhǎng)社证,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任评凝,我火速辦了婚禮追葡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己辽俗,他們只是感情好疾渣,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著崖飘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪杈女。 梳的紋絲不亂的頭發(fā)上朱浴,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音达椰,去河邊找鬼翰蠢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛啰劲,可吹牛的內(nèi)容都是我干的梁沧。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蝇裤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼廷支!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起栓辜,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤恋拍,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后藕甩,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體施敢,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年狭莱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了僵娃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡腋妙,死狀恐怖默怨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情辉阶,我是刑警寧澤先壕,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站谆甜,受9級(jí)特大地震影響垃僚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜规辱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一谆棺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦改淑、人聲如沸碍岔。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蔼啦。三九已至,卻和暖如春仰猖,著一層夾襖步出監(jiān)牢的瞬間捏肢,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工饥侵, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鸵赫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓躏升,卻偏偏與公主長(zhǎng)得像辩棒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子膨疏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容