ANR(0)---理解Android ANR的觸發(fā)原理

移步ANR系列

一、概述

  • ANR(Application Not responding),是指應(yīng)用程序未響應(yīng),Android系統(tǒng)對于一些事件需要在一定的時(shí)間范圍內(nèi)完成,如果超過預(yù)定時(shí)間能未能得到有效響應(yīng)或者響應(yīng)時(shí)間過長,都會造成ANR。
  • 一般地,這時(shí)往往會彈出一個(gè)提示框,告知用戶當(dāng)前xxx未響應(yīng),用戶可選擇繼續(xù)等待或者Force Close。

那么哪些場景會造成ANR呢?

  • Service Timeout:比如前臺服務(wù)在20s內(nèi)未執(zhí)行完成;
  • BroadcastQueue Timeout:比如前臺廣播在10s內(nèi)未執(zhí)行完成
  • ContentProvider Timeout:內(nèi)容提供者,在publish過超時(shí)10s;
  • InputDispatching Timeout: 輸入事件分發(fā)超時(shí)5s,包括按鍵和觸摸事件。

觸發(fā)ANR的過程可分為三個(gè)步驟: 埋炸彈, 拆炸彈, 引爆炸彈

二 Service

Service Timeout是位于”ActivityManager”線程中的AMS.MainHandler收到SERVICE_TIMEOUT_MSG消息時(shí)觸發(fā)。

對于Service有兩類:

  • 對于前臺服務(wù),則超時(shí)為SERVICE_TIMEOUT = 20s;
  • 對于后臺服務(wù),則超時(shí)為SERVICE_BACKGROUND_TIMEOUT = 200s

由變量ProcessRecord.execServicesFg來決定是否前臺啟動

2.1 埋炸彈

Android組件1--startService啟動過程分析詳細(xì)介紹Service啟動流程. 其中在Service進(jìn)程attach到system_server進(jìn)程的過程中會調(diào)用realStartServiceLocked()方法來埋下炸彈.

2.1.1 AS.realStartServiceLocked

[-> ActiveServices.java]

private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException {
    ...
    //發(fā)送delay消息(SERVICE_TIMEOUT_MSG),【見小節(jié)2.1.2】
    bumpServiceExecutingLocked(r, execInFg, "create");
    try {
        ...
        //最終執(zhí)行服務(wù)的onCreate()方法
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);
    } catch (DeadObjectException e) {
        mAm.appDiedLocked(app);
        throw e;
    } finally {
        ...
    }
}

2.1.2 AS.bumpServiceExecutingLocked

private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
    ... 
    scheduleServiceTimeoutLocked(r.app);
}

void scheduleServiceTimeoutLocked(ProcessRecord proc) {
    if (proc.executingServices.size() == 0 || proc.thread == null) {
        return;
    }
    long now = SystemClock.uptimeMillis();
    Message msg = mAm.mHandler.obtainMessage(
            ActivityManagerService.SERVICE_TIMEOUT_MSG);
    msg.obj = proc;
    
    //當(dāng)超時(shí)后仍沒有remove該SERVICE_TIMEOUT_MSG消息,則執(zhí)行service Timeout流程【見2.3.1】
    mAm.mHandler.sendMessageAtTime(msg,
        proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
}

該方法的主要工作發(fā)送delay消息(SERVICE_TIMEOUT_MSG). 炸彈已埋下, 我們并不希望炸彈被引爆, 那么就需要在炸彈爆炸之前拆除炸彈.

2.2 拆炸彈

  • 在system_server進(jìn)程AS.realStartServiceLocked()調(diào)用的過程會埋下一顆炸彈, 超時(shí)沒有啟動完成則會爆炸.
  • 那么什么時(shí)候會拆除這顆炸彈的引線呢? 經(jīng)過Binder等層層調(diào)用進(jìn)入目標(biāo)進(jìn)程的主線程handleCreateService()的過程.

2.2.1 AT.handleCreateService

[-> ActivityThread.java]

    private void handleCreateService(CreateServiceData data) {
        ...
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        Service service = (Service) cl.loadClass(data.info.name).newInstance();
        ...

        try {
            //創(chuàng)建ContextImpl對象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            //創(chuàng)建Application對象
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            //調(diào)用服務(wù)onCreate()方法 
            service.onCreate();
            
            //拆除炸彈引線[見小節(jié)2.2.2]
            ActivityManagerNative.getDefault().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (Exception e) {
            ...
        }
    }

在這個(gè)過程會創(chuàng)建目標(biāo)服務(wù)對象,以及回調(diào)onCreate()方法, 緊接再次經(jīng)過多次調(diào)用回到system_server來執(zhí)行serviceDoneExecuting.

2.2.2 AS.serviceDoneExecutingLocked

private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) {
    ...
    if (r.executeNesting <= 0) {
        if (r.app != null) {
            r.app.execServicesFg = false;
            r.app.executingServices.remove(r);
            if (r.app.executingServices.size() == 0) {
                //當(dāng)前服務(wù)所在進(jìn)程中沒有正在執(zhí)行的service
                mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
        ...
    }
    ...
}

該方法的主要工作是當(dāng)service啟動完成,則移除服務(wù)超時(shí)消息SERVICE_TIMEOUT_MSG。

2.3 引爆炸彈

  • 前面介紹了埋炸彈和拆炸彈的過程, 如果在炸彈倒計(jì)時(shí)結(jié)束之前成功拆卸炸彈,那么就沒有爆炸的機(jī)會,
  • 但是世事難料. 總有些極端情況下無法即時(shí)拆除炸彈,導(dǎo)致炸彈爆炸, 其結(jié)果就是App發(fā)生ANR. 接下來,帶大家來看看炸彈爆炸的現(xiàn)場:
  • 在system_server進(jìn)程中有一個(gè)Handler線程, 名叫”ActivityManager”.當(dāng)?shù)褂?jì)時(shí)結(jié)束便會向該Handler線程發(fā)送 一條信息SERVICE_TIMEOUT_MSG,

2.3.1 MainHandler.handleMessage

[-> ActivityManagerService.java ::MainHandler]

final class MainHandler extends Handler {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case SERVICE_TIMEOUT_MSG: {
                ...
                //【見小節(jié)2.3.2】
                mServices.serviceTimeout((ProcessRecord)msg.obj);
            } break;
            ...
        }
        ...
    }
}

2.3.2 AS.serviceTimeout

void serviceTimeout(ProcessRecord proc) {
    String anrMessage = null;

    synchronized(mAm) {
        if (proc.executingServices.size() == 0 || proc.thread == null) {
            return;
        }
        final long now = SystemClock.uptimeMillis();
        final long maxTime =  now -
                (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
        ServiceRecord timeout = null;
        long nextTime = 0;
        for (int i=proc.executingServices.size()-1; i>=0; i--) {
            ServiceRecord sr = proc.executingServices.valueAt(i);
            if (sr.executingStart < maxTime) {
                timeout = sr;
                break;
            }
            if (sr.executingStart > nextTime) {
                nextTime = sr.executingStart;
            }
        }
        if (timeout != null && mAm.mLruProcesses.contains(proc)) {
            Slog.w(TAG, "Timeout executing service: " + timeout);
            StringWriter sw = new StringWriter();
            PrintWriter pw = new FastPrintWriter(sw, false, 1024);
            pw.println(timeout);
            timeout.dump(pw, " ");
            pw.close();
            mLastAnrDump = sw.toString();
            mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
            mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS);
            anrMessage = "executing service " + timeout.shortName;
        }
    }

    if (anrMessage != null) {
        //當(dāng)存在timeout的service,則執(zhí)行appNotResponding
        mAm.appNotResponding(proc, null, null, false, anrMessage);
    }
}

其中anrMessage的內(nèi)容為”executing service [發(fā)送超時(shí)serviceRecord信息]”;

三 BroadcastReceiver

BroadcastReceiver Timeout是位于”ActivityManager”線程中的BroadcastQueue.BroadcastHandler收到BROADCAST_TIMEOUT_MSG消息時(shí)觸發(fā)。

  • 對于廣播隊(duì)列有兩個(gè): foreground隊(duì)列和background隊(duì)列:
    • 對于前臺廣播,則超時(shí)為BROADCAST_FG_TIMEOUT = 10s;
    • 對于后臺廣播,則超時(shí)為BROADCAST_BG_TIMEOUT = 60s

3.1 埋炸彈

Android組件3--Broadcast廣播機(jī)制分析詳細(xì)介紹廣播啟動流程,通過調(diào)用 processNextBroadcast來處理廣播.其流程為先處理并行廣播,再處理當(dāng)前有序廣播,最后獲取并處理下條有序廣播.

3.1.1 processNextBroadcast

[-> BroadcastQueue.java]

final void processNextBroadcast(boolean fromMsg) {
    synchronized(mService) {
        ...
        //part 2: 處理當(dāng)前有序廣播
        do {
            r = mOrderedBroadcasts.get(0);
            //獲取所有該廣播所有的接收者
            int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
            if (mService.mProcessesReady && r.dispatchTime > 0) {
                long now = SystemClock.uptimeMillis();
                if ((numReceivers > 0) &&
                        (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
                    //當(dāng)廣播處理時(shí)間超時(shí),則強(qiáng)制結(jié)束這條廣播【見小節(jié)3.3.2】
                    broadcastTimeoutLocked(false);
                    ...
                }
            }
            if (r.receivers == null || r.nextReceiver >= numReceivers
                    || r.resultAbort || forceReceive) {
                if (r.resultTo != null) {
                    //處理廣播消息消息
                    performReceiveLocked(r.callerApp, r.resultTo,
                        new Intent(r.intent), r.resultCode,
                        r.resultData, r.resultExtras, false, false, r.userId);
                    r.resultTo = null;
                }
                //拆炸彈【見小節(jié)3.2.1】
                cancelBroadcastTimeoutLocked();
            }
        } while (r == null);
        ...

        //part 3: 獲取下條有序廣播
        r.receiverTime = SystemClock.uptimeMillis();
        if (!mPendingBroadcastTimeoutMessage) {
            long timeoutTime = r.receiverTime + mTimeoutPeriod;
            //埋炸彈【見小節(jié)3.1.3】
            setBroadcastTimeoutLocked(timeoutTime);
        }
        ...
    }
}

對于廣播超時(shí)處理時(shí)機(jī):

  1. 首先在part3的過程中setBroadcastTimeoutLocked(timeoutTime) 設(shè)置超時(shí)廣播消息;
  2. 然后在part2根據(jù)廣播處理情況來處理:
    • 當(dāng)廣播接收者等待時(shí)間過長,則調(diào)用broadcastTimeoutLocked(false);
    • 當(dāng)執(zhí)行完廣播,則調(diào)用cancelBroadcastTimeoutLocked;

3.1.2 setBroadcastTimeoutLocked

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

設(shè)置定時(shí)廣播BROADCAST_TIMEOUT_MSG,即當(dāng)前往后推mTimeoutPeriod時(shí)間廣播還沒處理完畢,則進(jìn)入廣播超時(shí)流程。

3.2 拆炸彈

在processNextBroadcast()過程, 執(zhí)行完performReceiveLocked,便會拆除炸彈.

3.2.1 cancelBroadcastTimeoutLocked

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

移除廣播超時(shí)消息BROADCAST_TIMEOUT_MSG

3.3 引爆炸彈

3.3.1 BroadcastHandler.handleMessage

[-> BroadcastQueue.java ::BroadcastHandler]

private final class BroadcastHandler extends Handler {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case BROADCAST_TIMEOUT_MSG: {
                synchronized (mService) {
                    //【見小節(jié)3.3.2】
                    broadcastTimeoutLocked(true);
                }
            } break;
            ...
        }
        ...
    }
}

3.3.2 broadcastTimeoutLocked

[-> BroadcastRecord.java]

//fromMsg = true
final void broadcastTimeoutLocked(boolean fromMsg) {
    if (fromMsg) {
        mPendingBroadcastTimeoutMessage = false;
    }

    if (mOrderedBroadcasts.size() == 0) {
        return;
    }

    long now = SystemClock.uptimeMillis();
    BroadcastRecord r = mOrderedBroadcasts.get(0);
    if (fromMsg) {
        if (mService.mDidDexOpt) {
            mService.mDidDexOpt = false;
            long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
            setBroadcastTimeoutLocked(timeoutTime);
            return;
        }
        
        if (!mService.mProcessesReady) {
            return; //當(dāng)系統(tǒng)還沒有準(zhǔn)備就緒時(shí),廣播處理流程中不存在廣播超時(shí)
        }

        long timeoutTime = r.receiverTime + mTimeoutPeriod;
        if (timeoutTime > now) {
            //如果當(dāng)前正在執(zhí)行的receiver沒有超時(shí),則重新設(shè)置廣播超時(shí)
            setBroadcastTimeoutLocked(timeoutTime);
            return;
        }
    }

    BroadcastRecord br = mOrderedBroadcasts.get(0);
    if (br.state == BroadcastRecord.WAITING_SERVICES) {
        //廣播已經(jīng)處理完成,但需要等待已啟動service執(zhí)行完成。當(dāng)?shù)却銐驎r(shí)間,則處理下一條廣播。
        br.curComponent = null;
        br.state = BroadcastRecord.IDLE;
        processNextBroadcast(false);
        return;
    }

    r.receiverTime = now;
    //當(dāng)前BroadcastRecord的anr次數(shù)執(zhí)行加1操作
    r.anrCount++;

    if (r.nextReceiver <= 0) {
        return;
    }
    ...
    
    Object curReceiver = r.receivers.get(r.nextReceiver-1);
    //查詢App進(jìn)程
    if (curReceiver instanceof BroadcastFilter) {
        BroadcastFilter bf = (BroadcastFilter)curReceiver;
        if (bf.receiverList.pid != 0
                && bf.receiverList.pid != ActivityManagerService.MY_PID) {
            synchronized (mService.mPidsSelfLocked) {
                app = mService.mPidsSelfLocked.get(
                        bf.receiverList.pid);
            }
        }
    } else {
        app = r.curApp;
    }

    if (app != null) {
        anrMessage = "Broadcast of " + r.intent.toString();
    }

    if (mPendingBroadcast == r) {
        mPendingBroadcast = null;
    }

    //繼續(xù)移動到下一個(gè)廣播接收者
    finishReceiverLocked(r, r.resultCode, r.resultData,
            r.resultExtras, r.resultAbort, false);
    scheduleBroadcastsLocked();

    if (anrMessage != null) {
        // [見小節(jié)3.3.3]
        mHandler.post(new AppNotResponding(app, anrMessage));
    }
}
  1. mOrderedBroadcasts已處理完成,則不會anr;
  2. 正在執(zhí)行dexopt,則不會anr;
  3. 系統(tǒng)還沒有進(jìn)入ready狀態(tài)(mProcessesReady=false),則不會anr;
  4. 如果當(dāng)前正在執(zhí)行的receiver沒有超時(shí),則重新設(shè)置廣播超時(shí),不會anr;

3.3.3 AppNotResponding

[-> BroadcastQueue.java]

private final class AppNotResponding implements Runnable {
    ...
    public void run() {
        // 進(jìn)入ANR處理流程
        mService.appNotResponding(mApp, null, null, false, mAnnotation);
    }
}

四 ContentProvider

  • ContentProvider Timeout是位于”ActivityManager”線程中的AMS.MainHandler收到CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息時(shí)觸發(fā)。
  • ContentProvider 超時(shí)為CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10s. 這個(gè)跟前面的Service和BroadcastQueue完全不同, 由Provider進(jìn)程啟動過程相關(guān).

4.1 埋炸彈

Android組件4--理解ContentProvider原理詳細(xì)介紹了Provider啟動流程. 埋炸彈的過程 其實(shí)是在進(jìn)程創(chuàng)建的過程,進(jìn)程創(chuàng)建后會調(diào)用attachApplicationLocked()進(jìn)入system_server進(jìn)程.

4.1.1 AMS.attachApplicationLocked

private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
    ProcessRecord app;
    if (pid != MY_PID && pid >= 0) {
        synchronized (mPidsSelfLocked) {
            app = mPidsSelfLocked.get(pid); // 根據(jù)pid獲取ProcessRecord
        }
    } 
    ...
    
    //系統(tǒng)處于ready狀態(tài)或者該app為FLAG_PERSISTENT進(jìn)程則為true
    boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
    List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;

    //app進(jìn)程存在正在啟動中的provider,則超時(shí)10s后發(fā)送CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息
    if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
        Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
        msg.obj = app;
        mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
    }
    
    thread.bindApplication(...);
    ...
}

10s之后引爆該炸彈

4.2 拆炸彈

當(dāng)provider成功publish之后,便會拆除該炸彈.

4.2.1 AMS.publishContentProviders

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); //將該provider添加到mProviderMap
               String names[] = dst.info.authority.split(";");
               for (int j = 0; j < names.length; j++) {
                   mProviderMap.putProviderByName(names[j], dst);
               }

               int launchingCount = mLaunchingProviders.size();
               int j;
               boolean wasInLaunchingProviders = false;
               for (j = 0; j < launchingCount; j++) {
                   if (mLaunchingProviders.get(j) == dst) {
                       //將該provider移除mLaunchingProviders隊(duì)列
                       mLaunchingProviders.remove(j);
                       wasInLaunchingProviders = true;
                       j--;
                       launchingCount--;
                   }
               }
               //成功pubish則移除該消息
               if (wasInLaunchingProviders) {
                   mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
               }
               synchronized (dst) {
                   dst.provider = src.provider;
                   dst.proc = r;
                   //喚醒客戶端的wait等待方法
                   dst.notifyAll();
               }
               ...
           }
       }
   }    
}

4.3 引爆炸彈

在system_server進(jìn)程中有一個(gè)Handler線程, 名叫”ActivityManager”.當(dāng)?shù)褂?jì)時(shí)結(jié)束便會向該Handler線程發(fā)送 一條信息CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG,

4.3.1 MainHandler.handleMessage

[-> ActivityManagerService.java ::MainHandler]

final class MainHandler extends Handler {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: {
                ...
                ProcessRecord app = (ProcessRecord)msg.obj;
                synchronized (ActivityManagerService.this) {
                    //【見小節(jié)4.3.2】
                    processContentProviderPublishTimedOutLocked(app);
                }
            } break;
            ...
        }
        ...
    }
}

4.3.2 AMS.processContentProviderPublishTimedOutLocked

private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
    cleanupAppInLaunchingProvidersLocked(app, true); //[見4.3.3]
    //[見小節(jié)4.3.4]
    removeProcessLocked(app, false, true, "timeout publishing content providers");
}

4.3.3 AMS.cleanupAppInLaunchingProvidersLocked

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;
}

removeDyingProviderLocked()的功能跟進(jìn)程的存活息息相關(guān):詳見ContentProvider引用計(jì)數(shù) []小節(jié)4.5]

  • 對于stable類型的provider(即conn.stableCount > 0),則會殺掉所有跟該provider建立stable連接的非persistent進(jìn)程.
  • 對于unstable類的provider(即conn.unstableCount > 0),并不會導(dǎo)致client進(jìn)程被級聯(lián)所殺.

4.3.4 AMS.removeProcessLocked

private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart, boolean allowRestart, String reason) {
    final String name = app.processName;
    final int uid = app.uid;

    //移除mProcessNames中的相應(yīng)對象
    removeProcessNameLocked(name, uid);
    if (mHeavyWeightProcess == app) {
        mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
                mHeavyWeightProcess.userId, 0));
        mHeavyWeightProcess = null;
    }
    boolean needRestart = false;
    if (app.pid > 0 && app.pid != MY_PID) {
        int pid = app.pid;
        synchronized (mPidsSelfLocked) {
            mPidsSelfLocked.remove(pid);
            mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
        }
        
        ...
        boolean willRestart = false;
        if (app.persistent && !app.isolated) {
            if (!callerWillRestart) {
                willRestart = true;
            } else {
                needRestart = true;
            }
        }
        app.kill(reason, true); //殺進(jìn)程
        handleAppDiedLocked(app, willRestart, allowRestart);
        if (willRestart) {
            removeLruProcessLocked(app);
            addAppLocked(app.info, false, null /* ABI override */);
        }
    } else {
        mRemovedProcesses.add(app);
    }
    return needRestart;
}

五、總結(jié)

當(dāng)出現(xiàn)ANR時(shí),都是調(diào)用到AMS.appNotResponding()方法,詳細(xì)過程見文章ANR(1)---理解Android ANR的信息收集過程. 當(dāng)然這里介紹的provider例外.

5.1 Timeout時(shí)長

  • 對于前臺服務(wù),則超時(shí)為SERVICE_TIMEOUT = 20s;
  • 對于后臺服務(wù),則超時(shí)為SERVICE_BACKGROUND_TIMEOUT = 200s
  • 對于前臺廣播,則超時(shí)為BROADCAST_FG_TIMEOUT = 10s;
  • 對于后臺廣播,則超時(shí)為BROADCAST_BG_TIMEOUT = 60s;
    ContentProvider超時(shí)為
  • CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10s;

5.2 超時(shí)檢測

Service超時(shí)檢測機(jī)制:

  • 超過一定時(shí)間沒有執(zhí)行完相應(yīng)操作來觸發(fā)移除延時(shí)消息,則會觸發(fā)anr;

BroadcastReceiver超時(shí)檢測機(jī)制:

  • 有序廣播的總執(zhí)行時(shí)間超過 2* receiver個(gè)數(shù) * timeout時(shí)長,則會觸發(fā)anr;
  • 有序廣播的某一個(gè)receiver執(zhí)行過程超過 timeout時(shí)長,則會觸發(fā)anr;

另外:

  • 對于Service, Broadcast, Input發(fā)生ANR之后,最終都會調(diào)用AMS.appNotResponding;
  • 對于provider,在其進(jìn)程啟動時(shí)publish過程可能會出現(xiàn)ANR, 則會直接殺進(jìn)程以及清理相應(yīng)信息,而不會彈出ANR的對話框. appNotRespondingViaProvider()過程會走appNotResponding(), 這個(gè)就不介紹了,很少使用,由用戶自定義超時(shí)時(shí)間.

參考

理解Android ANR的觸發(fā)原理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 點(diǎn)贊點(diǎn)贊點(diǎn)贊點(diǎn)贊點(diǎn)贊…… 你不來點(diǎn)贊 再多的點(diǎn)贊也沒有意義
    先80閱讀 246評論 1 1
  • 2014年8月20日,我高中畢業(yè)在深圳呆了20多天后,深深地感受到了這座城市的魅力,決定將來不能局限于自己曾經(jīng)的小...
    找不到我404閱讀 404評論 4 4
  • 人的生命 只在一個(gè)呼吸間 如此短促 彌足珍貴 此生只有一次 善待自己的生命 讓生命的旅行 像清晨的一縷陽光 柔和而...
    山野觀瀾閱讀 308評論 2 7

友情鏈接更多精彩內(nèi)容