ANR-Fehler („App antwortet nicht“) werden ausgelöst, wenn der UI-Thread der Anwendung länger als 5 Sekunden nicht reagiert. Weitere Informationen zu ANR-Fehlern und ihrer Diagnose finden Sie in der Android-Dokumentation.
Außerdem kann Crashlytics dabei helfen, bestimmte problematische Threads zu identifizieren. Wir analysieren ANR-Fehler und kennzeichnen dann im Dashboard DevOps & Engagement > Crashlytics die entsprechenden Threads, um Hinweise zur Fehlerbehebung zu geben.
In den folgenden Abschnitten auf dieser Seite wird die Bedeutung der einzelnen ANR-Tags erläutert, ein Beispiel für einen ANR-Fehler mit diesem Tag gezeigt und eine empfohlene Lösung zum Debuggen des ANR-Fehlers bereitgestellt.
Triggered ANR
Ein Thread, der zu lange blockiert war und den ANR-Fehler ausgelöst hat, wird mit dem Tag Triggered ANR gekennzeichnet.
Der problematische Thread kann der Hauptthread der App oder ein beliebiger Thread sein, der nicht reagiert. Der mit Triggered ANR gekennzeichnete Thread ist jedoch möglicherweise nicht die tatsächliche Ursache des ANR-Fehlers. Um Informationen zum Beheben dieser ANR-Fehler bereitzustellen, taggt Crashlytics auch alle anderen Threads, die am ANR-Fehler beteiligt sind. In den folgenden Abschnitten dieser Seite erfahren Sie mehr über die anderen Tags, die auf einen Thread angewendet werden können.
Deadlocked
Alle Threads, die an einem Deadlock beteiligt sind, der zum ANR-Fehler geführt hat, werden mit dem Tag Deadlocked gekennzeichnet.
Ein Deadlock tritt auf, wenn ein Thread in einen Wartestatus wechselt, weil eine erforderliche Ressource von einem anderen Thread gehalten wird, der ebenfalls auf eine Ressource wartet, die vom ersten Thread gehalten wird. Wenn sich der Hauptthread der App in dieser Situation befindet, sind ANR-Fehler wahrscheinlich.
Beispiel ansehen
Hier sind zwei Threads, die an einem Deadlock beteiligt sind:
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)
Empfehlung
Sehen Sie sich die Threads an, die am Deadlock beteiligt sind, und prüfen Sie die Ressourcen/Sperren, die von diesen Threads erworben wurden. Mögliche Lösungen finden Sie unter Deadlock und Algorithmen zur Deadlock-Prävention.
IO Root blocking
Alle Threads, die langsame E/A-Vorgänge ausgeführt und den Thread Triggered ANR blockiert haben, sind mit dem Tag IO Root blocking gekennzeichnet. Wenn der Thread Triggered ANR nicht durch andere Threads blockiert wird, ist der Thread IO Root blocking auch ein Thread vom Typ Root blocking.
Beispiele ansehen
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 )
Empfehlung
Im Allgemeinen sollte deine App keine rechenintensiven E/A-Vorgänge im Hauptthread ausführen. Wenn der Hauptthread IO Root blocking ist, können Sie auch den strikten Modus verwenden, um unbeabsichtigte E/A-Vorgänge im Hauptthread zu identifizieren.
Root blocking
Jeder Thread, der den mit Triggered ANR gekennzeichneten Thread blockiert hat, wird mit dem Tag Root blocking annotiert. Wenn ein Thread sowohl als Root blocking als auch als Triggered ANR getaggt ist, gibt es keine anderen Threads, die diesen Thread blockieren.
Wenn Triggered ANR-Threads (möglicherweise transitiv) auf andere Threads gewartet haben, werden sie Root blocking. Es kann verschiedene Gründe dafür geben, dass ein Thread die Ursache für den ANR-Fehler ist.
Beispiele ansehen
Hier einige Beispiele, die auf dem Threadstatus basieren:
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 )
Empfehlung
Minimieren Sie CPU-intensive Arbeit im Hauptthread. Verwenden Sie Worker- oder Hintergrundthreads, um CPU-intensive Aufgaben auszuführen.
Minimieren Sie E/A-intensive Aufgaben wie das Laden aus einer Datenbank im Hauptthread.
Unknown root cause
Ein Thread wird mit dem Tag Unknown root cause gekennzeichnet, wenn er den ANR-Fehler ausgelöst hat, aber im Prozess inaktiv war, als der ANR-Fehler aufgetreten ist. Crashlytics hat nicht genügend Informationen, um die Ursache zu ermitteln. Es gibt keinen offensichtlichen Grund, warum dieser ANR-Fehler aufgetreten ist.
Beispiel ansehen
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 )
Empfehlung
Folgen Sie den allgemeinen Empfehlungen zur Vermeidung von ANR-Fehlern. Ermitteln Sie beispielsweise die Stellen im Code, an denen der Hauptthread der App länger als 5 Sekunden beschäftigt sein kann.
Waiting for binder call
Jeder Thread, der auf einen Binder-Aufruf gewartet und den Thread Triggered ANR blockiert hat, wird mit dem Tag Waiting for binder call gekennzeichnet. Wenn der Triggered ANR-Thread nicht durch andere Threads blockiert wird, ist der Waiting for binder call-Thread auch ein Root blocking-Thread.
Beispiel ansehen
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 )
Empfehlung
Da die Latenz eines Binder-Aufrufs unvorhersehbar sein kann, sollten Sie Binder-Aufrufe wie E/A-Vorgänge behandeln und sie nach Möglichkeit nicht im Hauptthread ausführen. Verschieben Sie Code, der Binder-Aufrufe auslöst (einschließlich Plattform-API-Aufrufe, die zu Binder-Transaktionen führen), in einen Hintergrundthread oder speichern Sie die Ergebnisse im Cache, wenn ein Aufruf über den Hauptthread unvermeidlich ist.