Les erreurs ANR (Application Not Responding) se déclenchent lorsque le thread UI de l'application ne répond pas pendant plus de 5 secondes. Pour en savoir plus sur les erreurs ANR et leur diagnostic, consultez la documentation Android.
De plus, Crashlytics peut vous aider à identifier les fils de discussion problématiques. Nous analysons les erreurs ANR, puis, dans le tableau de bord DevOps et engagement > Crashlytics, nous taguons les threads applicables pour vous aider à déboguer l'erreur ANR.
Les sections suivantes de cette page expliquent la signification de chaque tag ANR, présentent un exemple d'ANR avec ce tag et fournissent une solution recommandée pour déboguer l'ANR.
Triggered ANR
Un thread bloqué trop longtemps et ayant déclenché l'ANR est annoté avec le tag Triggered ANR.
Le thread problématique peut être le thread principal de l'application ou tout thread jugé non responsif. Toutefois, le thread tagué comme Triggered ANR peut ou non être la cause réelle de l'ANR. Pour fournir des informations permettant de déboguer et de corriger ces ANR, Crashlytics tague également tous les autres threads impliqués dans l'ANR. Dans les sections suivantes de cette page, découvrez les autres tags qui peuvent être appliqués à un fil de discussion.
Deadlocked
Tous les threads impliqués dans un interblocage qui a entraîné l'ANR sont annotés avec le tag Deadlocked.
Un interblocage se produit lorsqu'un thread passe à l'état d'attente, car une ressource requise est détenue par un autre thread, qui attend également une ressource détenue par le premier thread. Si le thread principal de l'application se trouve dans cette situation, il est probable que des erreurs ANR se produisent.
Voir un exemple
Voici deux threads impliqués dans un blocage :
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)
Recommandation
Examinez les threads impliqués dans l'interblocage et vérifiez les ressources/verrous acquis par ces threads. Pour connaître les solutions possibles, consultez les articles Interblocage et Algorithmes de prévention des interblocages.
IO Root blocking
Tout thread qui exécutait des opérations d'E/S lentes et bloquait le thread Triggered ANR est annoté avec le tag IO Root blocking. Si le thread Triggered ANR n'est pas bloqué par d'autres threads, le thread IO Root blocking est également un thread Root blocking.
Voir des exemples
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 )
Recommandation
En général, votre application ne doit pas exécuter d'opérations d'E/S coûteuses sur le thread principal. Si le thread principal est IO Root blocking, vous pouvez également utiliser le mode Strict pour identifier les opérations d'E/S involontaires qui se produisent sur le thread principal.
Root blocking
Tout thread ayant bloqué le thread tagué comme Triggered ANR est annoté avec le tag Root blocking. Si un thread est tagué à la fois comme Root blocking et Triggered ANR, cela signifie qu'aucun autre thread ne le bloque.
Si des threads Triggered ANR étaient en attente (peut-être de manière transitive) d'autres threads, ils sont Root blocking. Plusieurs raisons peuvent expliquer qu'un thread soit à l'origine de l'ANR.
Voir des exemples
Voici quelques exemples basés sur l'état du fil de discussion :
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 )
Recommandation
Minimisez les tâches gourmandes en ressources processeur dans le thread principal. Utilisez des threads de nœud de calcul ou d'arrière-plan pour effectuer des tâches qui sollicitent fortement le processeur.
Réduisez les tâches gourmandes en E/S, comme le chargement à partir d'une base de données, sur le thread principal.
Unknown root cause
Un thread est associé au tag Unknown root cause s'il a déclenché l'ANR, mais qu'il était inactif dans le processus au moment où l'ANR s'est produite. Crashlytics ne dispose pas de suffisamment d'informations pour déterminer la cause première. Aucune raison évidente n'explique cette ANR.
Voir un exemple
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 )
Recommandation
Suivez les conseils généraux pour éviter les erreurs ANR. Par exemple, identifiez les emplacements de votre code où le thread principal de l'application peut être occupé pendant plus de cinq secondes.
Waiting for binder call
Tout thread qui attendait un appel Binder et bloquait le thread Triggered ANR est annoté avec le tag Waiting for binder call. Si le thread Triggered ANR n'est pas bloqué par d'autres threads, le thread Waiting for binder call est également un thread Root blocking.
Voir un exemple
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 )
Recommandation
Étant donné que la latence d'un appel de liaison peut être imprévisible, traitez les appels de liaison comme des opérations d'E/S et évitez de les effectuer sur le thread principal lorsque cela est possible. Déplacez le code qui déclenche les appels de liaison (y compris les appels d'API de plate-forme qui entraînent des transactions de liaison) vers un thread en arrière-plan, ou mettez les résultats en cache si l'appel à partir du thread principal est inévitable.