如果應用程式的 UI 執行緒無回應超過 5 秒,就會觸發「應用程式無回應」(ANR) 錯誤。如要進一步瞭解 ANR 和診斷 ANR,請參閱 Android 說明文件。
此外,Crashlytics 可協助找出有問題的特定執行緒。我們會分析 ANR,然後在「DevOps & Engagement」 >「Crashlytics 資訊主頁」中標記適用的執行緒,提供 ANR 偵錯提示。
本頁面後續章節將說明各個 ANR 標記的意義、顯示帶有該標記的 ANR 範例,並提供偵錯 ANR 的建議解決方案。
Triggered ANR
若執行緒阻擋時間過長導致觸發 ANR,就會註明「Triggered ANR」標記。
有問題的執行緒可能是應用程式的主執行緒,或是其他無回應的執行緒。不過,標示為 Triggered ANR 的執行緒不一定是造成 ANR 的「實際」原因。為提供偵錯及修正這些 ANR 的深入分析,Crashlytics 也會標記與 ANR 相關的其他執行緒。在本頁面的後續章節中,您將瞭解可套用至執行緒的其他標記。
Deadlocked
如果發現任何執行緒涉及導致 ANR 的死結,就會加上 Deadlocked 標記。
當某執行緒需要的資源被另一個執行緒佔據而必須進入等待狀態,但是這另一個執行緒也正在等待第一個執行緒佔據的資源時,就會發生死結。如果應用程式的主執行緒有這種情形,就可能發生 ANR。
查看範例
以下是涉及死結的兩個執行緒:
main (unknown): tid=1 systid=1568
com.android.server.pm.PackageManagerService$PackageManagerInternalImpl.getPackage(PackageManagerService.java:22701)
com.android.server.pm.PackageManagerService$PackageManagerInternalImpl.filterOnlySystemPackages(PackageManagerService.java:22787)
...
com.android.server.SystemServer.main(SystemServer.java:368)
java.lang.reflect.Method.invoke(Native method)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:517)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:934)
ActivityManager (unknown): tid=21 systid=1902
com.android.server.pm.PackageManagerService.getPackageSetting(PackageManagerService.java:23618)
com.android.server.pm.PackageManagerService.getPackageUid(PackageManagerService.java:4542)
...
android.os.Handler.handleCallback(Handler.java:907)
android.os.Handler.dispatchMessage(Handler.java:99)
android.os.Looper.loop(Looper.java:216)
android.os.HandlerThread.run(HandlerThread.java:67)
com.android.server.ServiceThread.run(ServiceThread.java:44)
建議
查看死結涉及的執行緒,並檢查這些執行緒取得的資源/鎖定。如需可能的解決方案,請參閱死結和死結防範演算法。
IO Root blocking
如果任何執行緒的 I/O 作業執行速度過慢,且阻擋了Triggered ANR執行緒,就會註明IO Root blocking標記。如果其他執行緒並未封鎖 Triggered ANR 執行緒,則 IO Root blocking 執行緒也是 Root blocking 執行緒。
查看範例
Thread main(THREAD_STATE_TIMED_WAITING)
sun.misc.Unsafe.park( Unsafe.java:0 )
java.util.concurrent.locks.LockSupport.parkNanos( LockSupport.java:230 )
android.database.sqlite.SQLiteConnectionPool.waitForConnection( SQLiteConnectionPool.java:756 )
...
android.app.ActivityThread.main( ActivityThread.java:8192 )
Thread main(THREAD_STATE_NATIVE_WAITING)
Syscall
art::ConditionVariable::WaitHoldingLocks(art::Thread*)
art::GoToRunnable(art::Thread*)
art::JniMethodEnd(unsigned int, art::Thread*)
libcore.io.Linux.fdatasync( Linux.java:0 )
libcore.io.ForwardingOs.fdatasync( ForwardingOs.java:105 )
...
java.io.RandomAccessFile.write( RandomAccessFile.java:559 )
...
android.app.ActivityThread.main( ActivityThread.java:8192 )
建議
一般來說,應用程式不應在主執行緒上執行耗用大量資源的 I/O 作業。如果主執行緒為 IO Root blocking,您也可以使用嚴格模式,找出主執行緒上發生的任何非預期 I/O 作業。
Root blocking
若任何執行緒阻擋了標記為 Triggered ANR 的執行緒,就會註明 Root blocking 標記。如果執行緒同時標記為 Root blocking 和 Triggered ANR,則沒有其他執行緒會封鎖該執行緒。
如果有任何 Triggered ANR 執行緒正在等待其他執行緒 (可能是傳遞),則會Root blocking。執行緒是 ANR 根本原因的理由可能有很多。
查看範例
以下是根據執行緒狀態列舉的幾個例子:
Thread main(THREAD_STATE_RUNNABLE)
android.os.Parcel.createTypedArray( Parcel.java:3086 )
android.content.pm.PackageInfo.<init>( PackageInfo.java:546 )
...
android.app.ActivityThread$H.handleMessage( ActivityThread.java:2166 )
android.os.Handler.dispatchMessage( Handler.java:106 )
android.os.Looper.loop( Looper.java:246 )
android.app.ActivityThread.main( ActivityThread.java:8633 )
Thread main(THREAD_STATE_BLOCKED)
DBHelper.runOnDB( DBHelper.java:97 )
DBHelper.runDb( DBHelper.java:125 )
...
java.lang.reflect.Method.invoke( Method.java:0 )
EventBus.invokeSubscriber( EventBus.java:510 )
postToSubscription( EventBus.java:437 )
...
android.os.Handler.handleCallback( Handler.java:938 )
android.os.Handler.dispatchMessage( Handler.java:99 )
android.os.Looper.loop( Looper.java:268 )
android.app.ActivityThread.main( ActivityThread.java:7904 )
建議
盡量減少主執行緒中耗用大量 CPU 的工作。使用 worker 或背景執行緒執行 CPU 密集工作。
盡量減少主執行緒上的 I/O 密集工作,例如從資料庫載入。
Unknown root cause
如果執行緒觸發了 ANR,但 ANR 發生時其程序卻處於閒置狀態,就會註明 Unknown root cause 標記。Crashlytics 沒有充足的資訊來判斷根本原因,無法明確瞭解為何發生此 ANR 事件。
查看範例
Thread main(THREAD_STATE_NATIVE_WAITING) __epoll_pwait
android::Looper::pollInner(int)
android::Looper::pollOnce(int, int*, int*, void**)
android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)
android.os.MessageQueue.nativePollOnce( MessageQueue.java:0 )
android.os.MessageQueue.next( MessageQueue.java:335 )
android.os.Looper.loop( Looper.java:193 )
android.app.ActivityThread.main( ActivityThread.java:8019 )
建議
請按照一般建議,瞭解如何避免 ANR。舉例來說,找出程式碼中應用程式主執行緒可能忙碌超過 5 秒的部分。
Waiting for binder call
任何等待繫結機制呼叫並封鎖 Triggered ANR 執行緒的執行緒,都會加上 Waiting for binder call 標記。如果其他執行緒並未封鎖 Triggered ANR 執行緒,則 Waiting for binder call 執行緒也是 Root blocking 執行緒。
查看範例
Thread main(THREAD_STATE_NATIVE_WAITING)
syscall
android::IPCThreadState::talkWithDriver(bool)
android::IPCThreadState::waitForResponse(android::Parcel*, int*)
android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
android_os_BinderProxy_transact(_JNIEnv*, _jobject*, int, _jobject*, _jobject*, int)
android.os.BinderProxy.transactNative( BinderProxy.java:0 )
android.os.BinderProxy.transact( BinderProxy.java:540 )
android.app.IActivityManager$Stub$Proxy.getContentProvider( IActivityManager.java:5945 )
android.app.ActivityThread.acquireProvider( ActivityThread.java:7138 )
android.app.ActivityThread$H.handleMessage( ActivityThread.java:1982 )
android.os.Handler.dispatchMessage( Handler.java:106 )
android.os.Looper.loop( Looper.java:236 )
android.app.ActivityThread.main( ActivityThread.java:8037 )
建議
由於繫結器呼叫的延遲時間可能無法預測,因此請將繫結器呼叫視為 I/O 作業,並盡可能避免在主執行緒上執行。將觸發繫結器呼叫的程式碼 (包括導致繫結器交易的平台 API 呼叫) 移至背景執行緒,或在無法避免從主執行緒呼叫時快取結果。