Android ANR分析

ANR基礎知識

ANR全稱Application not response,即程序無響應。

ANR的分類

  • KeyDispatchTimeout 輸入超時,一般超時為5S
  • BroadcastTimeout 廣播超時, 一般為10S
  • ServiceTimeout Service處理超時,這個比較少見, 一般為20S
    這幾個值在ActivityManagerService.java中有定義。
KeyDispatch:
const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec
Broadcast:
    static final int BROADCAST_FG_TIMEOUT = 10*1000;    ->前臺10S
    static final int BROADCAST_BG_TIMEOUT = 60*1000;    ->后臺60S
Service:
    static final int SERVICE_TIMEOUT = 20*1000;  ->前臺20S
    // How long we wait for a service to finish executing.
    static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; ->后臺200S

ANR產生的原因

  • 一般是主線程處理耗時動作,Android線程一般是串行作用,如果主線程處理耗時,則其他線程就沒法繼續(xù)處理;
主線程進行網絡訪問
主線程進行大數據庫的訪問
主線程進行硬件操作
主線程調用Thread.join或者Thread.sleep
Service忙碌超時
其他線程占有l(wèi)ock,主線程等待Lock,這個設計到鎖的問題
主線程等待其他線程返回結果
總結就是主線程因為各種原因,無法處理系統(tǒng)的任務
  • 系統(tǒng)性能問題,同一時間系統(tǒng)運行多個程序,造成CPU占用太高,俗稱CPU饑餓。
  • 特殊情況, 系統(tǒng)向程序發(fā)送輸入事件,但是由于特殊原因(管道壞掉等),造成程序無法處理。

ANR設置原理

ANR其實就是在SystemServer進程,在下面三個響應的處理Service里面設置timer,當timer時間到達,沒有得到響應,編彈出ANR提示,可以讓用戶kill掉目標進程,來確保系統(tǒng)運行正常, 它一般流程為"埋炸彈",“拆炸彈”, “引爆炸彈”;

  • KeyDispatchTimeout
    key的流程是在systemServer調用inputReader和InPutDispatcher兩個線程,InputReader負責從EventHub中讀取key事件,通過notify的方式,喚醒inputDispatcher線程,并通過inputDispatcher進行分發(fā)到應用進程;
    keyDispatch的ANR區(qū)間是inputDispatcher中findFocusedWindowTargetsLocked到下一次執(zhí)行resetANRTimeoutsLocked的時候;
拆炸彈
void InputDispatcher::resetANRTimeoutsLocked() {
    // Reset input target wait timeout.
    mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
    mInputTargetWaitApplicationHandle.clear();
}
引爆炸彈
在findFocusedWindowTargetsLocked里面, 如果mFocusedWindowHandle == NULL ,則調用handleTargetsNotReadyLocked來進行處理,如果時間超過5S,則進入anr,ANR通過jni的方式最終調用到AMS的inputDispatchingTimedOut來執(zhí)行ANR;
  • BroadcastTimeout
埋炸彈和拆炸彈
BroadcastQueue.java
final void processNextBroadcast(boolean fromMsg) {
//broadcast的埋炸彈和拆炸彈都在這個函數里面
  if (r.receivers == null || r.nextReceiver >= numReceivers
                        || r.resultAbort || forceReceive) {
    cancelBroadcastTimeoutLocked();//拆炸彈
  }
  if (! mPendingBroadcastTimeoutMessage) {
    setBroadcastTimeoutLocked(timeoutTime); //埋炸彈
  }
}

引爆炸彈
BroadcastQueue.java
final void broadcastTimeoutLocked(boolean fromMsg) {
    if (anrMessage != null) {
            // Post the ANR to the handler since we do not want to process ANRs while
            // potentially holding our lock. 
            mHandler.post(new AppNotResponding(app, anrMessage));//進入anr處理
    }
}
  • ServiceTimeout
埋炸彈
private final void realStartServiceLocked(ServiceRecord r,ProcessRecord app, boolean execInFg) throws RemoteException {
    bumpServiceExecutingLocked(r, execInFg, "create");
}
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
  scheduleServiceTimeoutLocked(r.app);
}
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
  //就是這邊, 定時發(fā)送一個message,如果一定時間內,不clear掉,將會執(zhí)行對應的函數引爆
  mAm.mHandler.sendMessageAtTime(msg proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
}

拆炸彈
應用進程創(chuàng)建Service的時候, 通過 Binder調用serviceDoneExecuting;
private void handleCreateService(CreateServiceData data) {
   ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ActivityManagerService.java
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
    mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
ActiveServices.java
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
    serviceDoneExecutingLocked(r, inDestroying, inDestroying);
}

private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
            boolean finishing) {
    //這邊remove掉message,所有, 如果在20S 內,中途有任何block的,造成這邊沒有remove ,便會引起anr
    mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
}

引爆炸彈
如果message沒有被remove,這執(zhí)行對應的handler;
ActivityManagerService.java
case SERVICE_TIMEOUT_MSG: {
      mServices.serviceTimeout((ProcessRecord)msg.obj);
} break;

void serviceTimeout(ProcessRecord proc) {
        //彈出提示,用戶可以kill掉進程
        if (anrMessage != null) {
            mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage);
        }
}

ANR問題分析步驟

  • 查看main_log,查找關鍵字"ANR in",查看event log,查找關鍵字"am_anr",可以找到對應anr的信息;
  • 在main log中查看當時的CPU使用情況,是否占用過高,造成CPU饑餓;
  • 查看 IOwait,是否是因為IO操作造成anr
  • 查看發(fā)生時的data/anr/traces.txt,找到對應的anr進程,查看main線程的堆棧;
  • 初步定為線程是因為阻塞,死鎖等問題,查看棧頂是否有wait,sleep等進程操作,是否有Binder操作, 因為binder是同步的,所以如果binder另一端出現(xiàn)問題,得不到返回,這邊就一直等待了,是否有網絡數據庫等操作(這些占時操作盡量放到子線程);
  • 根據堆棧的函數,結合log推測當時的情況;

ANR實例分析

(1)主線程執(zhí)行耗時操作
  • 問題描述
    在Setting數據流量的菜單,選擇"限制后臺流量",出現(xiàn)ANR;
  • 問題分析
    main log
01-21 18:37:20.918 E/ActivityManager(  830): ANR in com.android.settings (com.android.settings/.SubSettings)
01-21 18:37:20.918 E/ActivityManager(  830): PID: 1111
01-21 18:37:20.918 E/ActivityManager(  830): Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago.  Wait queue length: 11.  Wait queue head age: 5599.9ms.)
01-21 18:37:20.918 E/ActivityManager(  830): Load: 7.01 / 3.19 / 1.21
01-21 18:37:20.918 E/ActivityManager(  830): CPU usage from 22ms to -5294ms ago:
01-21 18:37:20.918 E/ActivityManager(  830):   69% 830/system_server: 32% user + 36% kernel / faults: 15796 minor 50 major

traces log

DALVIK THREADS (22):
"main" prio=5 tid=1 Native
  | group="main" sCount=1 dsCount=0 obj=0x7548dfb8 self=0x55773a16a0
  | sysTid=3374 nice=0 cgrp=apps sched=0/0 handle=0x7f87c54150
  | state=S schedstat=( 11692707735 13876692717 17098 ) utm=936 stm=233 core=0 HZ=100
  | stack=0x7fc8ba3000-0x7fc8ba5000 stackSize=8MB
  | held mutexes=
  kernel: (couldn't read /proc/self/task/3374/stack)
  native: #00 pc 0005f234  /system/lib64/libc.so (__ioctl+4)
  native: #01 pc 00068758  /system/lib64/libc.so (ioctl+100)
  native: #02 pc 00027544  /system/lib64/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+164)
  native: #03 pc 00027fa4  /system/lib64/libbinder.so (android::IPCThreadState::waitForResponse(android::Parcel*, int*)+112)
  native: #04 pc 00028218  /system/lib64/libbinder.so (android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+176)
  native: #05 pc 0001ff18  /system/lib64/libbinder.so (android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+64)
  native: #06 pc 000d9a48  /system/lib64/libandroid_runtime.so (???)
  native: #07 pc 00fd580c  /data/dalvik-cache/arm64/system@framework@boot.oat (Java_android_os_BinderProxy_transactNative__ILandroid_os_Parcel_2Landroid_os_Parcel_2I+212)
  at android.os.BinderProxy.transactNative(Native method)
  at android.os.BinderProxy.transact(Binder.java:496)
  at android.net.INetworkPolicyManager$Stub$Proxy.setRestrictBackground(INetworkPolicyManager.java:454)
  at android.net.NetworkPolicyManager.setRestrictBackground(NetworkPolicyManager.java:169)

根據之前的分析流程,得出下面的結論:
(1) anr發(fā)生在com.android.settings
(2) CPU和IO都正常
(3) 查看trace,main線程沒有發(fā)生死鎖,wait, sleep這些;
(4) 從trace看,settings進程執(zhí)行android.net.INetworkPolicyManager$Stub$Proxy.setRestrictBackground,懷疑是不是這個函數耗時太多;
(5) 查看代碼

//函數setRestrictBackground,在做個什么鬼,經過檢測,發(fā)現(xiàn)果然是這個函數耗費時間長,把他放到子線程;
public void setRestrictBackground(boolean restrictBackground) {
        mPolicyManager.setRestrictBackground(restrictBackground);
        updateMenuTitles();
}

//option執(zhí)行,點擊菜單就只調用了setRestrictBackground
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.data_usage_menu_restrict_background: {
             setRestrictBackground(false);
        }
    }
}
  • 解決方案
    將mPolicyManager.setRestrictBackground(restrictBackground);放到子線程處理
    public class RestrictBackgroundTask extends AsyncTask<DataUsageSummary, Void, Void>{
        private boolean restrictBackground;
        public  RestrictBackgroundTask(boolean restrictBackground){
            this.restrictBackground = restrictBackground;
        }
 
        @Override
        protected Void doInBackground(DataUsageSummary... params) {
            mPolicyManager.setRestrictBackground(restrictBackground);
            return null;
        }
            
    }
   
   public void setRestrictBackground(boolean restrictBackground) {
        mRestrictBackgroundTask = new RestrictBackgroundTask(restrictBackground);
        mRestrictBackgroundTask.execute(this);//開起線程處理
        updateMenuTitles();
    }

(2)主線程死鎖
  • 問題描述
    音樂中刪除記錄時出現(xiàn)anr;

  • 問題分析
    這個問題只抓到了trace.txt,不過驚喜的是, trace居然能直接看出問題;

DALVIK THREADS (22):
"main" prio=5 tid=1 TimedWaiting
  | group="main" sCount=1 dsCount=0 obj=0x752ccfb8 self=0x559e6b26a0
  | sysTid=3078 nice=0 cgrp=apps/bg_non_interactive sched=0/0 handle=0x7f81cd4150
  | state=S schedstat=( 521831915 7324195292 1199 ) utm=46 stm=6 core=3 HZ=100
  | stack=0x7fec70d000-0x7fec70f000 stackSize=8MB
  | held mutexes=
  at java.lang.Object.wait!(Native method)
  - waiting on <0x2f38fd73> (a java.lang.Object)
  at java.lang.Thread.parkFor(Thread.java:1220)
  - locked <0x2f38fd73> (a java.lang.Object)
  at sun.misc.Unsafe.park(Unsafe.java:299)
  at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:197)
  at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:670)
  at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
  at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
  at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:586)
  at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
  at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
  at android.database.sqlite.SQLiteDatabase.updateWithOnConflict(SQLiteDatabase.java:1574)
  at android.database.sqlite.SQLiteDatabase.update(SQLiteDatabase.java:1522)
  at com.android.providers.media.MediaProvider$2.onReceive(MediaProvider.java:351)
  at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:861)
  at android.os.Handler.handleCallback(Handler.java:739)
  at android.os.Handler.dispatchMessage(Handler.java:95)
  at android.os.Looper.loop(Looper.java:135)
  at android.app.ActivityThread.main(ActivityThread.java:5221)
  at java.lang.reflect.Method.invoke!(Native method)
  at java.lang.reflect.Method.invoke(Method.java:372)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:898)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:693)

main線程居然是TimedWaiting;
TIMED_WAITING 這個狀態(tài)就是有限的(時間限制)的WAITING, 一般出現(xiàn)在調用wait(long), join(long)等情況下, 另外一個線程sleep后, 也會進入TIMED_WAITING狀態(tài)

private SQLiteConnection waitForConnection(String sql, int connectionFlags,
       CancellationSignal cancellationSignal) {
       // Wait to be unparked (may already have happened), a timeout, or interruption.
       LockSupport.parkNanos(this, busyTimeoutMillis * 1000000L); //這邊就wait掉了
}
  • 解決方案
    本著盡量在上層進行修改的原則,我們還是選擇規(guī)避該問題, 在上層
    “ at com.android.providers.media.MediaProvider$2.onReceive(MediaProvider.java:351)”的時候不去調用update,理論上, 當前情況也不需要update;
主線程循環(huán)調用sleep,造成主線程處于sleep狀態(tài)
  • 問題描述
    打開Call->在dial pad中輸入“*#2886# ”->進入factory mode,按返回鍵,出現(xiàn)MMI ANR
  • 問題分析
    main log: anr發(fā)生在 mmi進程,CPU和IO 正常, 進程ID2148, Input Dispatching ANR;
02-10 13:57:06.492 E/ActivityManager(  884): ANR in com.android.mmi (com.android.mmi/.MMITest)
02-10 13:57:06.492 E/ActivityManager(  884): PID: 2148
02-10 13:57:06.492 E/ActivityManager(  884): Reason: Input dispatching timed out (Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)
02-10 13:57:06.492 E/ActivityManager(  884): Load: 7.08 / 4.38 / 4.11
02-10 13:57:06.492 E/ActivityManager(  884): CPU usage from 4399ms to -5752ms ago:
02-10 13:57:06.492 E/ActivityManager(  884):   35% 884/system_server: 16% user + 19% kernel / faults: 7913 minor 124 major
02-10 13:57:06.492 E/ActivityManager(  884):   27% 1845/com.android.phone: 15% user + 12% kernel / faults: 5880 minor 50 major
02-10 13:57:06.492 E/ActivityManager(  884):   26% 256/logd: 22% user + 4.2% kernel / faults: 4 minor
02-10 13:57:06.492 E/ActivityManager(  884):   11% 1532/com.android.systemui: 5.7% user + 5.3% kernel / faults: 3579 minor 76 major
02-10 13:57:06.492 E/ActivityManager(  884):   8.4% 296/rild: 7% user + 1.4% kernel / faults: 34 minor 1 major
02-10 13:57:06.492 E/ActivityManager(  884):   4.6% 1027/logcat: 1.6% user + 2.9% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0% 295/debuggerd: 0% user + 0% kernel / faults: 3166 minor 33 major
02-10 13:57:06.492 E/ActivityManager(  884):   2.5% 259/servicemanager: 0.5% user + 1.9% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   1% 1791/com.android.server.telecom: 0.3% user + 0.6% kernel / faults: 2209 minor 181 major
02-10 13:57:06.492 E/ActivityManager(  884):   1.9% 184/mmcqd/0: 0% user + 1.9% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   1.6% 1810/com.android.nfc: 1% user + 0.5% kernel / faults: 1849 minor 155 major
02-10 13:57:06.492 E/ActivityManager(  884):   1.2% 1017/reporthelper: 0% user + 1.2% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   1.2% 2148/com.android.mmi: 0.8% user + 0.3% kernel / faults: 1199 minor 56 major
02-10 13:57:06.492 E/ActivityManager(  884):   0.2% 22257/com.qualcomm.telephony: 0% user + 0.1% kernel / faults: 2242 minor 26 major
02-10 13:57:06.492 E/ActivityManager(  884):   1% 379/qmuxd: 0.5% user + 0.4% kernel / faults: 1 minor
02-10 13:57:06.492 E/ActivityManager(  884):   0.9% 261/surfaceflinger: 0.2% user + 0.6% kernel / faults: 26 minor 3 major
02-10 13:57:06.492 E/ActivityManager(  884):   0.3% 1828/com.android.dlnaservice: 0% user + 0.3% kernel / faults: 1548 minor 48 major
02-10 13:57:06.492 E/ActivityManager(  884):   0.8% 31309/kworker/0:2: 0% user + 0.8% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0.7% 158/cfinteractive: 0% user + 0.7% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0.6% 103/kswapd0: 0% user + 0.6% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0.3% 323/sdcard: 0% user + 0.3% kernel / faults: 3 minor
02-10 13:57:06.492 E/ActivityManager(  884):   0.3% 1341/com.tct.calendar: 0% user + 0.2% kernel / faults: 892 minor
02-10 13:57:06.492 E/ActivityManager(  884):   0.3% 2226/com.google.android.apps.plus: 0.2% user + 0% kernel / faults: 964 minor
02-10 13:57:06.492 E/ActivityManager(  884):   0.2% 2441/com.google.process.location: 0.2% user + 0% kernel / faults: 594 minor 8 major
02-10 13:57:06.492 E/ActivityManager(  884):   0% 20346/VosMCThread: 0% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0.1% 27/kworker/1:1: 0% user + 0.1% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0.2% 33/kworker/u9:0: 0% user + 0.2% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0.2% 316/zygote: 0.2% user + 0% kernel / faults: 1521 minor
02-10 13:57:06.492 E/ActivityManager(  884):   0.2% 1829/com.google.android.gm: 0.1% user + 0% kernel / faults: 546 minor 4 major
02-10 13:57:06.492 E/ActivityManager(  884):   0.2% 31286/kworker/u8:2: 0% user + 0.2% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0.1% 3/ksoftirqd/0: 0% user + 0.1% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0.1% 8/rcu_preempt: 0% user + 0.1% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0.1% 12/ksoftirqd/1: 0% user + 0.1% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0.1% 16/ksoftirqd/2: 0% user + 0.1% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0.1% 2196/com.tct.gallery3d: 0% user + 0% kernel / faults: 712 minor
02-10 13:57:06.492 E/ActivityManager(  884):   0.1% 11789/kworker/u8:12: 0% user + 0.1% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0% 20/ksoftirqd/3: 0% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0% 258/lmkd: 0% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0% 298/mediaserver: 0% user + 0% kernel / faults: 20 minor 5 major
02-10 13:57:06.492 E/ActivityManager(  884):   0% 1863/com.tct.launcher: 0% user + 0% kernel / faults: 144 minor 1 major
02-10 13:57:06.492 E/ActivityManager(  884):   0% 20347/VosTXThread: 0% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0% 20348/VosRXThread: 0% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0% 20369/wpa_supplicant: 0% user + 0% kernel / faults: 254 minor 8 major
02-10 13:57:06.492 E/ActivityManager(  884):   0% 22016/com.tct.weather: 0% user + 0% kernel / faults: 1168 minor 9 major
02-10 13:57:06.492 E/ActivityManager(  884):   0% 23402/kworker/2:1: 0% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0% 31280/mdss_fb0: 0% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0% 31308/kworker/u8:3: 0% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   0% 31372/kworker/1:0: 0% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):  +0% 2278/com.android.providers.calendar: 0% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884): 36% TOTAL: 18% user + 15% kernel + 1.4% iowait + 0.9% softirq
02-10 13:57:06.492 E/ActivityManager(  884): CPU usage from 5049ms to 5578ms later:
02-10 13:57:06.492 E/ActivityManager(  884):   56% 256/logd: 43% user + 13% kernel
02-10 13:57:06.492 E/ActivityManager(  884):     43% 1032/logd.reader.per: 30% user + 13% kernel
02-10 13:57:06.492 E/ActivityManager(  884):     15% 276/logd.writer: 11% user + 3.7% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   37% 1845/com.android.phone: 33% user + 3.7% kernel / faults: 36 minor
02-10 13:57:06.492 E/ActivityManager(  884):     5.6% 1860/Binder_1: 5.6% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):     5.6% 3572/Binder_6: 3.7% user + 1.8% kernel
02-10 13:57:06.492 E/ActivityManager(  884):     5.6% 6834/Binder_7: 5.6% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):     3.7% 1845/m.android.phone: 3.7% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):     3.7% 2153/Binder_3: 1.8% user + 1.8% kernel
02-10 13:57:06.492 E/ActivityManager(  884):     3.7% 2167/Binder_4: 3.7% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):     3.7% 2627/Binder_5: 3.7% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):     3.7% 6835/Binder_8: 3.7% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):     1.8% 1974/RILReceiver: 1.8% user + 0% kernel
02-10 13:57:06.492 E/ActivityManager(  884):   12% 1532/com.android.systemui: 7.6% user + 5.1% kernel
02-10 13:57:06.492 D/SubController( 1845): StackTrace - [getPhoneId] subId=-2

traces log: 主線程Sleeping, 看調用堆棧的地方,居然有Thread.sleep,查看代碼,看哪里調用到sleep;

"main" prio=5 tid=1 Sleeping
  | group="main" sCount=1 dsCount=0 obj=0x74b7cbc0 self=0xb88d0088
  | sysTid=17967 nice=0 cgrp=apps sched=0/0 handle=0xb6f21ec8
  | state=S schedstat=( 76988439 75071667 165 ) utm=3 stm=4 core=1 HZ=100
  | stack=0xbe6d5000-0xbe6d7000 stackSize=8MB
  | held mutexes=
  at java.lang.Thread.sleep!(Native method)
  - sleeping on <0x2ea0c232> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:1031)
  - locked <0x2ea0c232> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:985)
  at android.os.SystemClock.sleep(SystemClock.java:125)
  at com.android.mmi.util.JRDClient.<init>(JRDClient.java:72)
  at com.android.mmi.traceability.TraceabilityStruct.<init>(TraceabilityStruct.java:51)
  at com.android.mmi.util.TestItemManager.isDoubleSim(TestItemManager.java:177)
  at com.android.mmi.util.TestItemManager.LoadStaticTestItems(TestItemManager.java:141)
  at com.android.mmi.util.TestItemManager.InitStaticInfo(TestItemManager.java:95)
  at com.android.mmi.CommonActivity.onCreate(CommonActivity.java:64)
  at com.android.mmi.MMITest.onCreate(MMITest.java:43)
  at android.app.Activity.performCreate(Activity.java:5976)
  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2262)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2371)
  at android.app.ActivityThread.access$800(ActivityThread.java:149)
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1289)
  at android.os.Handler.dispatchMessage(Handler.java:102)
  at android.os.Looper.loop(Looper.java:135)
  at android.app.ActivityThread.main(ActivityThread.java:5260)
  at java.lang.reflect.Method.invoke!(Native method)
  at java.lang.reflect.Method.invoke(Method.java:372)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:898)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:693)
  • 代碼分析
private static boolean LoadStaticTestItems(Context context, String product) {
    for(String item : maxItemsArray) {    //在for循環(huán)中調用(isDoubleSim() || getBoardId() == 1)
         if((isDoubleSim() || getBoardId() == 1)){  //堆棧信息可以看出,這個里面調用到了JRDClient
             if(itemInfo[0].trim().equals("Memory Card")){
                 itemHash.put("deftype", "0");
        }
    }
  }
}
//JRDClient構造函數里面有做500ms的sleep, 聯(lián)系之前的代碼,這個是放到一個for循環(huán)里面的, 這樣就會造成主線程一直處于sleep,造成ANR;
public JRDClient() {
        //mSocket = new LocalSocket();
        if (android.os.SystemProperties.get("init.svc.tctd") != "running") {
            android.os.SystemProperties.set("ctl.start", "tctd");
            SystemClock.sleep(500);
        }
    }

  • 解決方案
    將Thread.sleep相關的代碼拉出for循環(huán):
private static boolean LoadStaticTestItems(Context context, String product) {
    boolean flag = (isDoubleSim() || getBoardId() == 1);
    for(String item : maxItemsArray) {   
         if(flag){ //這邊調用flag值,這樣不會循環(huán)調用isDoubleSim了
           if(itemInfo[0].trim().equals("Memory Card")){
             itemHash.put("deftype", "0");
          }
        }
    }
}

最后貼上相應的思維導圖:

ANR分析.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內容

  • 什么是ANR ANR(Application Not Responding)就是應用在規(guī)定的時間內沒有響應用戶輸入...
    lbtrace閱讀 3,405評論 3 9
  • Application Not Responding 1. 產生的原因 主線程任務執(zhí)行時間過長(阻塞), 系統(tǒng)消息...
    Simon_z閱讀 2,949評論 0 1
  • ANR的類型 KeyDispatchTimeout(5 seconds) --主要類型按鍵或觸摸事件在特定時間內無...
    codedreamzone閱讀 941評論 0 0
  • 1、ANR是什么?ANR英文全稱Application Not Responding,通俗來說就是程序未響應!如果...
    __帝華閱讀 1,028評論 0 0
  • 花姐只是微信朋友圈里的昵稱,何姓何名,一概不知。 這十幾日,花姐和丈夫駕車帶著三只金毛犬,從蘭州出發(fā),途徑武威、張...
    王劍的理想國度閱讀 547評論 0 3