ANR-Fehler („App antwortet nicht“) werden ausgelöst, wenn der UI-Thread der App länger als 5 Sekunden nicht reagiert. Weitere Informationen zu ANR-Fehlern und ihrer Diagnose finden Sie in der Android-Dokumentation.
Außerdem können Sie mit Crashlytics bestimmte problematische Threads identifizieren. Wir analysieren ANR-Fehler und kennzeichnen dann im Dashboard DevOps & Engagement > Crashlytics die entsprechenden Threads, um Hinweise zum Beheben des ANR-Fehlers zu geben.
In den folgenden Abschnitten auf dieser Seite wird erläutert, was die einzelnen ANR-Tags bedeuten. Außerdem wird ein Beispiel-ANR mit dem jeweiligen Tag gezeigt und eine empfohlene Lösung zum Debuggen des ANR angegeben.
Triggered ANR
Ein Thread, der zu lange blockiert wurde und den ANR-Fehler ausgelöst hat, wird mit dem Tag Triggered ANR annotiert.
Der problematische Thread kann der Hauptthread der App oder ein beliebiger Thread sein, der nicht reagiert. Der als Triggered ANR gekennzeichnete Thread ist jedoch möglicherweise nicht die tatsächliche Ursache des ANR-Fehlers. Um Informationen zum Beheben dieser ANR-Fehler bereitzustellen, werden von Crashlytics auch alle anderen Threads getaggt, die an dem 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 diesem Deadlocked-Tag gekennzeichnet.
Ein Deadlock tritt auf, wenn ein Thread in den 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, treten wahrscheinlich ANR-Fehler auf.
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 abgerufen wurden. Mögliche Lösungen finden Sie unter Deadlock und Deadlock-Vermeidungsalgorithmen.
IO Root blocking
Alle Threads, die langsame E/A-Vorgänge ausgeführt und den Triggered ANR-Thread blockiert haben, werden mit dem Tag IO Root blocking versehen. Wenn der Thread Triggered ANR nicht von anderen Threads blockiert wird, ist der Thread IO Root blocking auch ein Root blocking-Thread.
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 sollten in Ihrer App keine rechenintensiven E/A-Vorgänge im Hauptthread ausgeführt werden. Wenn der Hauptthread IO Root blocking ist, können Sie auch den Strict Mode verwenden, um unbeabsichtigte E/A-Vorgänge zu erkennen, die im Hauptthread ausgeführt werden.
Root blocking
Alle Threads, die den mit Triggered ANR gekennzeichneten Thread blockiert haben, werden mit dem Tag Root blocking versehen. Wenn ein Thread sowohl mit Root blocking als auch mit Triggered ANR gekennzeichnet ist, wird er von keinem anderen Thread blockiert.
Wenn Triggered ANR-Threads (möglicherweise transitiv) auf andere Threads gewartet haben, sind sie Root blocking. Es kann verschiedene Gründe dafür geben, dass ein Thread die Ursache für den ANR ist.
Beispiele ansehen
Hier sind einige Beispiele basierend auf dem Threadstatus:
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 Aufgaben im Hauptthread. Verwenden Sie Worker- oder Hintergrund-Threads für CPU-intensive Aufgaben.
Minimieren Sie E/A-intensive Vorgänge 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 ersichtlichen Grund für diesen ANR-Fehler.
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
Befolgen Sie die allgemeinen Ratschläge zum Vermeiden von ANR-Fehlern. Sie können beispielsweise die Stellen in Ihrem Code identifizieren, an denen der Hauptthread der App länger als 5 Sekunden beschäftigt sein kann.
Waiting for binder call
Alle Threads, die auf einen Binder-Aufruf gewartet und den Triggered ANR-Thread blockiert haben, werden mit dem Tag Waiting for binder call annotiert. Wenn der Thread Triggered ANR nicht von anderen Threads blockiert wird, ist der Thread Waiting for binder call 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 möglichst 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 cachen Sie die Ergebnisse, wenn ein Aufruf über den Hauptthread unvermeidlich ist.