Diagnostiquer et corriger les erreurs ANR

Lorsque le thread UI d'une application Android est bloqué trop longtemps, le système déclenche une erreur ANR (« L'application ne répond pas »). Cette page décrit les différents types d'erreurs ANR, explique comment les diagnostiquer et propose des solutions pour les résoudre. Toutes les plages de délais avant expiration par défaut s'appliquent aux appareils AOSP et Pixel. Ces délais peuvent varier selon les OEM.

Notez bien que, lorsque vous déterminez la cause des erreurs ANR, il est utile de faire la distinction entre les problèmes du système et ceux de l'application.

Lorsque le système est dans un état défectueux, les problèmes suivants peuvent entraîner des erreurs ANR :

  • Les problèmes temporaires sur le serveur système ralentissent généralement les appels de liaison.
  • Des problèmes liés au serveur système et à une charge élevée de l'appareil empêchent la planification des threads d'application.

Le cas échéant, un bon moyen de faire la distinction entre les problèmes du système et ceux de l'application consiste à utiliser des traces de Perfetto :

  • Vérifiez si le thread principal de l'application est planifié en consultant le suivi de l'état du thread dans Perfetto pour voir s'il est en cours d'exécution ou exécutable.
  • Recherchez d'éventuels problèmes dans les threads system_server, tels que les conflits de verrouillage.
  • Pour les appels de liaison lents, examinez le thread de réponse s'il est présent pour en comprendre la raison.

Délai avant expiration de distribution des entrées

Les erreurs ANR de distribution des entrées se produisent lorsque le thread principal de l'application ne répond pas à temps à un événement d'entrée, tel qu'un balayage ou une pression sur une touche. Étant donné que l'application est exécutée au premier plan lorsque des délais avant expiration de distribution des entrées se produisent, ils sont presque toujours visibles par l'utilisateur, et il est important de les limiter.

Délai avant expiration par défaut : 5 secondes.

Les erreurs ANR de distribution des entrées sont généralement causées par des problèmes sur le thread principal. Si le thread principal a été bloqué en attendant l'obtention d'un verrou, le thread du conteneur peut également être impliqué.

Pour éviter les erreurs ANR de distribution des entrées, suivez ces bonnes pratiques :

  • N'effectuez pas d'opérations bloquantes ou de longue durée sur le thread principal. Envisagez d'utiliser StrictMode pour détecter toute activité accidentelle sur le thread principal.
  • Minimisez les conflits de verrouillage entre le thread principal et les autres threads.
  • Réduisez les tâches autres que celles liées à l'interface utilisateur sur le thread principal, par exemple lors de la gestion des broadcasts ou de l'exécution de services.

Causes courantes

Voici quelques causes courantes et suggestions de solutions pour les erreurs ANR de distribution des entrées.

Cause Que se passe-t-il Solutions suggérées
Appel de liaison lent Le thread principal effectue un long appel de liaison synchrone. Déplacez l'appel en dehors du thread principal ou essayez de l'optimiser, si vous êtes propriétaire de l'API.
Nombreux appels de liaison consécutifs Le thread principal effectue de nombreux appels de liaison synchrones consécutifs. N'effectuez pas d'appels de liaison dans une boucle étroite.
E/S bloquantes Le thread principal effectue des appels d'E/S bloquants, tels que l'accès à la base de données ou au réseau. Retirez toutes les E/S bloquantes du thread principal.
Conflits de verrouillage Le thread principal est bloqué en attendant d'obtenir un verrou. Réduisez les conflits de verrouillage entre le thread principal et un thread différent. Optimisez le code lent dans un thread différent.
Frame coûteux en ressources Trop d'affichages sur un seul frame, ce qui entraîne de graves à-coups Simplifiez l'affichage du frame. N'utilisez pas les algorithmes n2. Utilisez des composants efficaces pour le défilement ou la pagination, comme la bibliothèque Paging de Jetpack.
Bloqué par un autre composant Un autre composant, tel qu'un broadcast receiver, est en cours d'exécution et bloque le thread principal. Retirez autant que possible les tâches qui ne sont pas liées à l'UI du thread principal. Exécutez des broadcast receivers sur un thread différent.
Blocage du GPU Le blocage du GPU est un problème système ou matériel qui entraîne le blocage de l'affichage et, par conséquent, une erreur ANR de distribution des entrées. Malheureusement, il n'existe généralement pas de solutions du côté de l'application. Si possible, contactez l'équipe chargée du matériel pour résoudre le problème.

Comment déboguer

Commencez le débogage en examinant la signature du groupe d'erreurs ANR dans la Google Play Console ou dans Firebase Crashlytics. Le groupe contient généralement les frames supérieurs susceptibles de provoquer l'erreur ANR.

L'organigramme suivant montre comment déterminer la cause d'une erreur ANR du délai avant expiration de distribution des entrées.

Image 1. Déboguer une erreur ANR de distribution des entrées.

Play Vitals peut détecter et déboguer certaines de ces causes d'erreurs ANR courantes. Par exemple, si Vitals détecte qu'une erreur ANR s'est produite en raison d'un conflit de verrouillage, l'appli peut résumer le problème et la solution recommandée dans la section Insights sur les erreurs ANR.

Image 2. Détection des erreurs ANR par Play Vitals

Aucune fenêtre sélectionnée

Alors que les événements tels que les gestes tactiles sont envoyés directement à la fenêtre appropriée en fonction des tests de positionnement, les événements comme les touches ont besoin d'une cible. Cette cible est appelée fenêtre sélectionnée. Il n'y a qu'une seule fenêtre sélectionnée par écran, qui correspond généralement à celle avec laquelle l'utilisateur interagit actuellement. Si une fenêtre sélectionnée ne peut être trouvée, l'entrée génère une erreur ANR de fenêtre sans sélection. Une erreur ANR de fenêtre sans sélection est un type d'erreur ANR de distribution des entrées.

Délai avant expiration par défaut : 5 secondes.

Causes courantes

Les erreurs ANR de fenêtre sans sélection sont généralement causées par l'un des problèmes suivants :

  • L'appli effectue trop de tâches et est trop lente pour dessiner le premier frame.
  • La fenêtre principale n'est pas sélectionnable. Si une fenêtre est signalée par l'icône FLAG_NOT_FOCUSABLE, l'utilisateur ne peut pas lui envoyer d'événements de touche ou de bouton.

Kotlin

override fun onCreate(savedInstanceState: Bundle) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)
  window.addFlags(WindowManager.LayoutParams.FLAG_FLAG_NOT_FOCUSABLE)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
}

Délai avant expiration du broadcast receiver

Une erreur ANR de broadcast receiver se produit lorsqu'un broadcast receiver ne gère pas une diffusion à temps. Pour les récepteurs synchrones ou qui n'appellent pas goAync(), un délai avant expiration signifie que onReceive() ne s'est pas terminé à temps. Pour les récepteurs asynchrones, ou les récepteurs qui appellent goAsync(), un délai avant expiration signifie que PendingResult.finish() n'a pas été appelé à temps.

Les erreurs ANR du broadcast receiver se produisent souvent dans les threads suivants :

  • Thread principal, en cas de démarrage lent de l'application.
  • Thread exécutant un broadcast receiver, si le problème est une lenteur du code onReceive().
  • Diffusion des threads de travail, si le problème est une lenteur du code de diffusion goAsync().

Pour éviter les erreurs ANR du broadcast receiver, suivez ces bonnes pratiques :

  • Assurez-vous que l'application démarre rapidement, car elle est comptabilisée dans le délai avant expiration de l'erreur ANR si l'application est lancée pour gérer la diffusion.
  • Si goAsync() est utilisé, assurez-vous que PendingResult.finish() est appelé rapidement. Elle est soumise au même délai avant expiration de l'erreur ANR que les broadcast receivers synchrones.
  • Si goAsync() est utilisé, assurez-vous que le ou les threads de travail ne sont pas partagés avec d'autres opérations de longue durée ou bloquantes.
  • Envisagez d'utiliser registerReceiver() pour exécuter des broadcast receivers dans un thread non principal afin d'éviter de bloquer le code de l'interface utilisateur exécuté dans le thread principal.

Délais avant expiration

Les délais avant expiration des broadcast receivers varient selon que l'indicateur d'intent de premier plan est défini ou non, et selon la version de la plate-forme.

Type d'intent Android 13 ou version antérieure Android 14 ou version ultérieure

Intent de priorité au premier plan

(FLAG_RECEIVER_FOREGROUND défini)

10 secondes

10 à 20 secondes, selon que le processus manque de ressources de processeur ou non

Intent de priorité en arrière-plan

(FLAG_RECEIVER_FOREGROUND non défini)

60 secondes

60 à 120 secondes, selon que le processus manque de ressources de processeur ou non

Pour savoir si l'indicateur FLAG_RECEIVER_FOREGROUND est défini, recherchez "flg=" dans l'objet de l'erreur ANR et vérifiez la présence de 0x10000000. Si ce bit est défini, FLAG_RECEIVER_FOREGROUND est défini pour l'intent, ce qui réduit le délai avant expiration.

Exemple d'objet de l'erreur ANR avec un délai avant expiration de diffusion court (10 à 20 secondes) :

Broadcast of Intent { act=android.inent.action.SCREEN_ON flg=0x50200010 }

Exemple d'objet de l'erreur ANR avec un délai avant expiration de diffusion long (de 60 à 120 secondes) :

Broadcast of Intent { act=android.intent.action.TIME_SET flg=0x25200010 }

Comment les temps de diffusion sont-ils mesurés ?

La mesure de la durée de diffusion commence lorsque la diffusion est envoyée depuis system_server vers l'application et se termine lorsque l'application a terminé le traitement de la diffusion. Si le processus de l'application n'était pas déjà en cours d'exécution, elle doit également effectuer un démarrage à froid pendant le délai avant expiration de l'erreur ANR. Par conséquent, un démarrage lent de l'application peut entraîner des erreurs ANR du broadcast receiver.

L'image suivante illustre la chronologie des erreurs ANR du broadcast receiver sur certains processus d'application.

Image 3. Chronologie des erreurs ANR du broadcast receiver.

La mesure du délai avant expiration de l'erreur ANR se termine lorsque le récepteur termine le traitement de la diffusion. Le moment exact où cela se produit dépend du type de récepteur synchrone ou asynchrone.

  • Pour les récepteurs synchrones, la mesure s'arrête lorsque onReceive() est renvoyé.
  • Pour les récepteurs asynchrones, la mesure s'arrête lorsque PendingResult.finish() est appelé.
Image 4. Les points de terminaison de mesure du délai avant expiration de l'erreur ANR pour les récepteurs synchrones et asynchrones.

Causes courantes

Voici quelques causes courantes et suggestions de solutions pour les erreurs ANR du broadcast receiver.

Cause S'applique à Que s'est-il passé Solution suggérée
Démarrage lent de l'appli Tous les récepteurs L'application a mis trop de temps à effectuer un démarrage à froid. Optimisez le démarrage lent de l'application.
onReceive() non planifié Tous les récepteurs Le thread du broadcast receiver était occupé à effectuer d'autres tâches et n'a pas pu démarrer la méthode onReceive(). N'effectuez pas de tâches de longue durée sur le thread récepteur (ou déplacez le récepteur vers un thread dédié).
onReceive() lent Tous les récepteurs, mais principalement les récepteurs synchrones La méthode onReceive() a démarré, mais a été bloquée ou lente, et ne s'est donc pas terminée à temps. Optimisez le code du récepteur lent.
Tâches du récepteur asynchrone non planifiées Récepteurs goAsync() La méthode onReceive() a tenté d'exécuter une tâche sur un pool de threads de travail bloqué. Par conséquent, la tâche n'a jamais démarré. Optimisez les appels lents ou bloquants, ou utilisez des threads différents pour les workers de diffusion par rapport aux autres tâches de longue durée.
Workers lents ou bloqués Récepteurs goAsync() Une opération bloquante ou lente s'est produite dans le pool de threads de travail lors du traitement de la diffusion. PendingResult.finish n'a donc pas été appelé à temps. Optimisez le code lent du récepteur async.
Vous avez oublié d'appeler PendingResult.finish Récepteurs goAsync() Il manque l'appel à finish() dans le chemin de code. Assurez-vous que finish() est toujours appelé.

Comment déboguer

Sur la base de la signature du groupe et du rapport ANR, vous pouvez localiser le thread sur lequel le récepteur s'exécute, puis le code spécifique qui est manquant ou qui s'exécute lentement.

L'organigramme suivant montre comment déterminer la cause d'une erreur ANR sur le broadcast receiver.

Image 5. Déboguer une erreur ANR d'un broadcast receiver.

Trouver le code du récepteur

La Google Play Console affiche la classe du récepteur et l'intent de diffusion dans la signature de l'erreur ANR. Recherchez les éléments suivants :

  • cmp=<receiver class>
  • act=<broadcast_intent>

Voici un exemple de signature de l'erreur ANR d'un broadcast receiver :

com.example.app.MyClass.myMethod
Broadcast of Intent { act=android.accounts.LOGIN_ACCOUNTS_CHANGED
cmp=com.example.app/com.example.app.MyAccountReceiver }

Rechercher le thread qui exécute la méthode onReceive()

Si vous utilisez Context.registerReceiver pour spécifier un gestionnaire personnalisé, c'est le thread qui exécute ce gestionnaire. Sinon, il s'agit du thread principal.

Exemple : Tâches de récepteur asynchrone non planifiées

Cette section présente un exemple de débogage d'une erreur ANR d'un broadcast receiver.

Supposons que la signature de l'erreur ANR se présente comme suit :

com.example.app.MyClass.myMethod
Broadcast of Intent {
act=android.accounts.LOG_ACCOUNTS_CHANGED cmp=com.example.app/com.example.app.MyReceiver }

D'après la signature, il semble que l'intent de diffusion soit android.accounts.LOG_ACCOUNTS_CHANGED et que la classe du récepteur soit com.example.app.MyReceiver.

À partir du code du récepteur, vous pouvez déterminer que le pool de threads "BG Thread [0,1,2,3]" effectue la tâche principale pour traiter cette diffusion. En examinant les vidages de pile, vous pouvez constater que les quatre threads d'arrière-plan (BG) ont le même schéma ; ils exécutent un appel bloquant, getDataSync. Étant donné que tous les threads de BG étaient occupés, la diffusion n'a pas pu être traitée à temps, ce qui a entraîné une erreur ANR.

BG Thread #0 (tid=26) Waiting

at jdk.internal.misc.Unsafe.park(Native method:0)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture:563)
at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture:68)
at com.example.app.getDataSync(<MyClass>:152)

...

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at com.google.android.libraries.concurrent.AndroidExecutorsModule.lambda$withStrictMode$5(AndroidExecutorsModule:451)
at com.google.android.libraries.concurrent.AndroidExecutorsModule$$ExternalSyntheticLambda8.run(AndroidExecutorsModule:1)
at java.lang.Thread.run(Thread.java:1012)
at com.google.android.libraries.concurrent.ManagedPriorityThread.run(ManagedPriorityThread:34)

Il existe plusieurs façons de résoudre le problème :

  • Découvrez pourquoi getDataSync est lent et comment l'optimiser.
  • N'exécutez pas getDataSync sur les quatre threads de BG.
  • Plus généralement, assurez-vous que le pool de threads de BG n'est pas saturé d'opérations de longue durée.
  • Utilisez un pool de threads dédié pour les tâches de workers goAsync.
  • Utiliser un pool de threads illimité au lieu du pool de threads de BG limité

Exemple : Démarrage lent de l'application

Un démarrage lent de l'application peut entraîner plusieurs types d'erreurs ANR, en particulier pour le broadcast receiver et l'exécution d'erreurs ANR de service. Une erreur ANR est probablement due au démarrage lent de l'application si ActivityThread.handleBindApplication apparaît dans les piles de threads principales.

Délai avant expiration d'exécution du service

Une erreur ANR de service d'exécution se produit lorsque le thread principal de l'application ne démarre pas de service à temps. Plus précisément, un service ne termine pas son exécution onCreate() et onStartCommand() ou onBind() au cours du délai avant expiration.

Délai avant expiration par défaut : 20 secondes pour le service de premier plan et 200 secondes pour le service d'arrière-plan. Le délai avant expiration de l'erreur ANR inclut le démarrage à froid de l'application, si nécessaire, et les appels à onCreate(), onBind() ou onStartCommand().

Pour éviter d'exécuter des erreurs ANR de service, suivez ces bonnes pratiques générales :

  • Assurez-vous que l'application démarre rapidement, car elle est comptabilisée dans le délai avant expiration de l'erreur ANR si l'application est lancée pour exécuter le composant de service.
  • Assurez-vous que les méthodes onCreate(), onStartCommand() et onBind() du service sont rapides.
  • Évitez d'exécuter des opérations lentes ou bloquantes sur le thread principal à partir d'autres composants. Ces opérations peuvent empêcher un service de démarrer rapidement.

Causes courantes

Le tableau suivant présente les causes courantes d'erreurs ANR de service d'exécution et les solutions suggérées.

Cause Quoi Solution suggérée
Démarrage lent de l'appli L'application prend trop de temps pour effectuer un démarrage à froid. Optimisez le démarrage lent de l'application.
Méthode onCreate(), onStartCommand() ou onBind() lente La méthode onCreate(), onStartCommand() ou onBind() du composant de service prend trop de temps à s'exécuter sur le thread principal. Optimisez le code lent. Dans la mesure du possible, éliminez les opérations lentes du chemin critique.
Non planifié (thread principal bloqué avant onStart()) Le thread principal de l'application est bloqué par un autre composant avant que le service puisse être démarré. Retirez les tâches d'un autre composant du thread principal. Optimisez le code bloquant de l'autre composant.

Comment déboguer

À partir de la signature du groupe et du rapport ANR de la Google Play Console ou dans Firebase Crashlytics, vous pouvez souvent déterminer la cause de l'erreur ANR en fonction de ce que fait le thread principal.

L'organigramme suivant explique le débogage d'une erreur ANR de service d'exécution.

Image 6. Déboguer une erreur ANR de service d'exécution.

Si vous avez déterminé que l'erreur ANR de service d'exécution est exploitable, procédez comme suit pour résoudre le problème :

  1. Recherchez la classe du composant de service dans la signature de l'erreur ANR. Dans la Google Play Console, la classe du composant de service est affichée dans la signature de l'erreur ANR. Dans l'exemple suivant de détails de l'erreur ANR, il s'agit de com.example.app/MyService.

    com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly
    Executing service com.example.app/com.example.app.MyService
    
  2. Déterminez si l'opération lente ou bloquée fait partie du démarrage de l'application, du composant de service ou d'un autre élément en vérifiant la présence du ou des appels de fonction importants suivants dans les threads principaux.

    Appel(s) de fonction dans les piles de threads principaux Signification
    android.app.ActivityThread.handleBindApplication L'application démarrait. L'erreur ANR a été causée par un démarrage lent de cette appli.

    <ServiceClass>.onCreate()

    [...]

    android.app.ActivityThread.handleCreateService

    Le service était en cours de création. L'erreur ANR est probablement causée par un code onCreate() lent.

    <ServiceClass>.onBind()

    [...]

    android.app.ActivityThread.handleBindService

    Le service était lié. L'erreur ANR était probablement causée par un code onBind() lent.

    <ServiceClass>.onStartCommand()

    [...]

    android.app.ActivityThread.handleServiceArgs

    Le service était en cours de démarrage. L'erreur ANR était probablement causée par un code onStartCommand() lent.

    Par exemple, si la méthode onStartCommand() de la classe MyService est lente, les threads principaux se présenteront comme suit :

    at com.example.app.MyService.onStartCommand(FooService.java:25)
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4820)
    at android.app.ActivityThread.-$$Nest$mhandleServiceArgs(unavailable:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2289)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8176)
    at java.lang.reflect.Method.invoke(Native method:0)
    

    Si vous ne voyez aucun des appels de fonction importants, il existe plusieurs autres possibilités :

    • Le service est en cours d'exécution ou en cours d'arrêt, ce qui signifie que les piles sont prises trop tard. Dans ce cas, vous pouvez ignorer l'ANR en tant que faux positif.
    • Un autre composant d'application est en cours d'exécution, comme un broadcast receiver. Dans ce cas, le thread principal est probablement bloqué dans ce composant, ce qui empêche le démarrage du service.
  3. Si vous voyez un appel de fonction clé et pouvez déterminer où l'erreur ANR se produit généralement, vérifiez le reste des piles de threads principaux pour identifier l'opération lente, et optimisez-la ou retirez-la du chemin critique.

Pour en savoir plus sur les services, consultez les pages suivantes :

Le fournisseur de contenu ne répond pas

Une erreur ANR de fournisseur de contenu se produit lorsqu'un fournisseur de contenu distant prend plus de temps que le délai avant expiration pour répondre à une requête et qu'il est arrêté.

Délai avant expiration par défaut : Spécifié par le fournisseur de contenu à l'aide de ContentProviderClient.setDetectNotResponding. Le délai avant expiration de l'erreur ANR inclut la durée totale d'exécution d'une requête de fournisseur de contenu distant, ce qui comprend le démarrage à froid de l'application à distance si elle n'était pas déjà en cours d'exécution.

Pour éviter les erreurs ANR de fournisseur de contenu, suivez ces bonnes pratiques :

  • Assurez-vous que l'application démarre rapidement, car elle est comptabilisée dans le délai avant expiration de l'erreur ANR si l'application est lancée pour exécuter le fournisseur de contenu.
  • Assurez-vous que les requêtes du fournisseur de contenu sont rapides.
  • N'effectuez pas de nombreux appels de liaison bloquants simultanés qui peuvent bloquer tous les threads de liaison de l'application.

Causes courantes

Le tableau suivant présente les causes courantes d'erreurs ANR de fournisseur de contenu et les solutions suggérées.

Cause Que se passe-t-il Signal Solution suggérée
Requête du fournisseur de contenu lente L'exécution du fournisseur de contenu prend trop de temps ou est bloquée. Le frame android.content.ContentProvider$Transport.query se trouve dans le thread de liaison. Optimisez la requête du fournisseur de contenu. Identifiez ce qui bloque le thread de liaison.
Démarrage lent de l'appli Le démarrage de l'application du fournisseur de contenu prend trop de temps. Le frame ActivityThread.handleBindApplication se trouve dans le thread principal. Optimisez le démarrage de l'application.
Épuisement du thread de liaison : Tous les threads de liaison sont occupés Tous les threads de liaison étant occupés à diffuser d'autres requêtes synchrones, l'appel de liaison du fournisseur de contenu ne peut pas s'exécuter. L'application ne démarre pas, tous les threads de liaison sont occupés et le fournisseur de contenu n'est pas en cours d'exécution. Réduisez la charge sur les threads de liaison. Autrement dit, effectuez moins d'appels de liaison sortants synchrones ou réduisez vos tâches lors de la gestion des appels entrants.

Comment déboguer

Pour déboguer les erreurs ANR d'un fournisseur de contenu à l'aide de la signature du groupe et du rapport ANR dans la Google Play Console ou dans Firebase Crashlytics, examinez ce que font le thread principal et le ou les threads de liaison.

L'organigramme suivant explique le débogage d'une erreur ANR de fournisseur de contenu :

Image 7. Déboguer une erreur ANR d'un fournisseur de contenu.

L'extrait de code suivant montre à quoi ressemble le thread de liaison lorsqu'il est bloqué en raison d'une requête du fournisseur de contenu lente. Dans ce cas, la requête du fournisseur de contenu attend le verrouillage lors de l'ouverture d'une base de données.

binder:11300_2 (tid=13) Blocked

Waiting for osm (0x01ab5df9) held by at com.google.common.base.Suppliers$NonSerializableMemoizingSupplier.get(Suppliers:182)
at com.example.app.MyClass.blockingGetOpenDatabase(FooClass:171)
[...]
at com.example.app.MyContentProvider.query(MyContentProvider.java:915)
at android.content.ContentProvider$Transport.query(ContentProvider.java:292)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:107)
at android.os.Binder.execTransactInternal(Binder.java:1339)
at android.os.Binder.execTransact(Binder.java:1275)

L'extrait de code suivant montre à quoi ressemble le thread principal lorsqu'il est bloqué en raison d'un démarrage lent de l'application. Dans ce cas, le démarrage de l'application est lent en raison d'un conflit de verrouillage lors de l'initialisation de Dagger.

main (tid=1) Blocked

[...]
at dagger.internal.DoubleCheck.get(DoubleCheck:51)
- locked 0x0e33cd2c (a qsn)at dagger.internal.SetFactory.get(SetFactory:126)
at com.myapp.Bar_Factory.get(Bar_Factory:38)
[...]
at com.example.app.MyApplication.onCreate(DocsApplication:203)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1316)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6991)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(unavailable:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2235)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8170)
at java.lang.reflect.Method.invoke(Native method:0)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)

Réponse de tâche lente

Une erreur ANR de réponse de tâche est lente lorsque l'application met trop de temps à répondre à JobService.onStartJob() ou JobService.onStopJob(), ou met trop de temps à fournir une notification à l'aide de JobService.setNotification(). Cela laisse supposer que le thread principal de l'application est bloqué et qu'il n'effectue pas d'autre action.

En cas de problème avec JobService.onStartJob() ou JobService.onStopJob(), vérifiez ce qui se passe sur le thread principal. En cas de problème avec JobService.setNotification(), veillez à l'appeler aussi rapidement que possible. Ne faites pas trop de tâches avant d'envoyer la notification.

ANR mystères

Parfois, la raison pour laquelle une erreur ANR se produit n'est pas claire, ou il n'y a pas assez d'informations pour la déboguer dans la signature du groupe et le rapport ANR. Dans ce cas, vous pouvez toujours prendre certaines mesures pour déterminer si l'erreur ANR est exploitable ou non.

File d'attente de messages inactive ou nativePollOnce

Si vous voyez le frame android.os.MessageQueue.nativePollOnce dans les piles, cela signifie souvent que le thread qui ne répondait pas était en réalité inactif et attendait les messages du looper. Dans la Google Play Console, les informations détaillées sur l'ANR se présentent comme suit :

Native method - android.os.MessageQueue.nativePollOnce
Executing service com.example.app/com.example.app.MyService

Par exemple, si le thread principal est inactif, les piles se présentent comme suit :

"main" tid=1 NativeMain threadIdle

#00  pc 0x00000000000d8b38  /apex/com.android.runtime/lib64/bionic/libc.so (__epoll_pwait+8)
#01  pc 0x0000000000019d88  /system/lib64/libutils.so (android::Looper::pollInner(int)+184)
#02  pc 0x0000000000019c68  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
#03  pc 0x000000000011409c  /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
at android.os.MessageQueue.nativePollOnce (Native method)
at android.os.MessageQueue.next (MessageQueue.java:339)  at android.os.Looper.loop (Looper.java:208)
at android.app.ActivityThread.main (ActivityThread.java:8192)
at java.lang.reflect.Method.invoke (Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:626)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1015)

Le thread soupçonné de ne pas répondre peut être inactif pour plusieurs raisons :

  • Vidage tardif de la pile. Le thread a été récupéré pendant la courte période entre le déclenchement de l'ANR et le vidage des piles. La latence dans Pixels sur Android 13 est d'environ 100 ms, mais peut dépasser 1 s. Sous Android 14, la latence dans Pixels est généralement inférieure à 10 ms.
  • Erreur d'attribution du thread. Le thread utilisé pour créer la signature de l'erreur ANR n'était pas celui qui n'a pas répondu à l'origine de l'erreur ANR. Dans ce cas, essayez de déterminer si l'erreur ANR est de l'un des types suivants :
  • Problème au niveau du système. Le processus n'a pas été planifié en raison d'une charge système importante ou d'un problème au niveau du serveur système.

Aucun bloc de pile

Certains rapports ANR n'incluent pas les piles contenant les erreurs ANR, ce qui signifie que le vidage de la pile a échoué lors de la génération du rapport ANR. L'absence de blocs de pile peut s'expliquer par plusieurs raisons :

  • La pile prend trop de temps et dépasse le délai.
  • Le processus a expiré ou a été arrêté avant la prise des piles.
[...]

--- CriticalEventLog ---
capacity: 20
timestamp_ms: 1666030897753
window_ms: 300000

libdebuggerd_client: failed to read status response from tombstoned: timeout reached?

----- Waiting Channels: pid 7068 at 2022-10-18 02:21:37.<US_SOCIAL_SECURITY_NUMBER>+0800 -----

[...]

Les erreurs ANR sans bloc de pile ne sont pas exploitables à partir de la signature du groupe ou du rapport ANR. Pour effectuer le débogage, examinez les autres groupes de l'application. En effet, si un problème est suffisamment important, elle dispose généralement de son propre groupe contenant des blocs de pile. Vous pouvez également examiner les traces de Perfetto.

Problèmes connus

Le maintien d'un minuteur dans le processus de votre application afin de terminer le traitement de la diffusion avant le déclenchement d'une erreur ANR peut ne pas fonctionner correctement en raison de la manière asynchrone dont le système surveille les erreurs ANR.