Lire les rapports de bugs

Les bugs sont une réalité dans tout type de développement, et les rapports de bugs sont essentiels pour identifier et résoudre les problèmes. Toutes les versions d'Android permettent de capturer des rapports de bug avec Android Debug Bridge (adb). Les versions 4.2 et ultérieures d'Android sont compatibles avec une option pour les développeurs permettant de générer des rapports de bug et de les partager par e-mail, sur Drive, etc.

Les rapports de bug Android contiennent des données dumpsys, dumpstate et logcat au format texte (.txt), ce qui vous permet de rechercher facilement du contenu spécifique. Les sections suivantes détaillent les composants d'un rapport de bug, décrivent les problèmes courants et fournissent des conseils utiles ainsi que des commandes grep pour trouver les journaux associés à ces bugs. La plupart des sections incluent également des exemples de commandes et de résultats grep et/ou de résultats dumpsys.

Logcat

Le journal logcat est un dump basé sur une chaîne de toutes les informations logcat. La partie system est réservée au framework et a une histoire plus longue que main, qui contient tout le reste. Chaque ligne commence généralement par timestamp UID PID TID log-level, mais il est possible que UID ne soit pas indiqué dans les anciennes versions d'Android.

Afficher le journal des événements

Ce journal contient des représentations sous forme de chaîne des messages du journal au format binaire. Il est moins bruyant que le journal logcat, mais aussi un peu plus difficile à lire. Lorsque vous consultez les journaux d'événements, vous pouvez rechercher un ID de processus (PID) spécifique dans cette section pour voir ce qu'un processus a fait. Le format de base est le suivant : timestamp PID TID log-level log-tag tag-values.

Voici les niveaux de journalisation :

  • V : verbeux
  • D : débogage
  • I : information
  • W : avertissement
  • E : erreur

 

Pour d'autres tags de journaux d'événements utiles, consultez /services/core/java/com/android/server/EventLogTags.logtags.

ANR et blocages

Les rapports de bug peuvent vous aider à identifier les causes des erreurs Application Not Responding (ANR) et des événements de blocage.

Identifier les applications qui ne répondent pas

Lorsqu'une application ne répond pas dans un certain délai, généralement en raison d'un thread principal bloqué ou occupé, le système arrête le processus et transfère la pile vers /data/anr. Pour identifier la cause d'une ANR, recherchez am_anr dans le journal des événements binaires.

Vous pouvez également rechercher ANR in dans le journal logcat, qui contient plus d'informations sur ce qui utilisait le processeur au moment de l'ANR.

Trouver des traces de pile

Vous pouvez souvent trouver des traces de pile correspondant à une ANR. Assurez-vous que le code temporel et le PID des traces de la VM correspondent à l'ANR que vous examinez, puis vérifiez le thread principal du processus. À noter :

  • Le thread principal vous indique uniquement ce que le thread faisait au moment de l'ANR, ce qui peut correspondre ou non à la véritable cause de l'ANR. (La pile du rapport de bug peut être innocente. Il est possible qu'un autre élément soit bloqué depuis longtemps, mais pas assez longtemps pour générer une erreur ANR, avant de se débloquer.)
  • Il peut exister plusieurs ensembles de traces de pile (VM TRACES JUST NOW et VM TRACES AT LAST ANR). Assurez-vous de consulter la bonne section.

Identifier les blocages

Les blocages se manifestent souvent d'abord sous la forme d'erreurs ANR, car les threads sont bloqués. Si le blocage se produit sur le serveur système, le watchdog finira par l'arrêter, ce qui entraînera une entrée dans le journal semblable à : WATCHDOG KILLING SYSTEM PROCESS. Du point de vue de l'utilisateur, l'appareil redémarre, bien qu'il s'agisse techniquement d'un redémarrage du runtime plutôt que d'un véritable redémarrage.

  • Lors d'un redémarrage du temps d'exécution, le serveur système s'arrête et redémarre. L'utilisateur voit l'appareil revenir à l'animation de démarrage.
  • Lors d'un redémarrage, le noyau a planté et l'utilisateur voit l'appareil revenir au logo de démarrage Google.

Pour trouver les blocages, recherchez dans les sections de traces de VM un schéma où le thread A attend quelque chose détenu par le thread B, qui attend à son tour quelque chose détenu par le thread A.

Activités

Une activité est un composant d'application qui fournit un écran avec lequel les utilisateurs interagissent pour effectuer une action (par exemple, composer un numéro, prendre une photo, envoyer un e-mail, etc.). Du point de vue d'un rapport de bug, une activité est une action unique et ciblée qu'un utilisateur peut effectuer. Il est donc très important de localiser l'activité qui était au premier plan lors d'un plantage. Les activités (via ActivityManager) exécutent des processus. Par conséquent, la localisation de tous les arrêts et démarrages de processus pour une activité donnée peut également aider à résoudre les problèmes.

Afficher les activités ciblées

Pour afficher l'historique des activités ciblées, recherchez am_focused_activity.

Début du processus de visionnage

Pour afficher l'historique des démarrages de processus, recherchez Start proc.

Déterminer si l'appareil est en thrashing

Pour déterminer si l'appareil est en thrashing, vérifiez s'il y a une augmentation anormale de l'activité autour de am_proc_died et am_proc_start sur une courte période.

Mémoire

Étant donné que les appareils Android disposent souvent d'une mémoire physique limitée, la gestion de la mémoire vive (RAM) est essentielle. Les rapports de bug contiennent plusieurs indicateurs de mémoire insuffisante, ainsi qu'un dumpstate qui fournit un instantané de la mémoire.

Identifier une mémoire faible

Une mémoire insuffisante peut entraîner une surcharge du système, car il arrête certains processus pour libérer de la mémoire, mais continue d'en démarrer d'autres. Pour trouver des preuves corroborantes de mémoire insuffisante, recherchez des concentrations d'entrées am_proc_died et am_proc_start dans le journal des événements binaires.

Une mémoire faible peut également ralentir le changement de tâche et empêcher les tentatives de retour (car la tâche à laquelle l'utilisateur essayait de revenir a été arrêtée). Si le lanceur a été arrêté, il redémarre lorsque l'utilisateur appuie sur le bouton Accueil. Les journaux indiquent que le lanceur recharge son contenu.

Afficher les indicateurs historiques

L'entrée am_low_memory dans le journal des événements binaires indique que le dernier processus mis en cache est terminé. Après cela, le système commence à arrêter les services.

Afficher les indicateurs de thrashing

D'autres indicateurs de thrashing du système (pagination, récupération directe, etc.) incluent les cycles de consommation kswapd, kworker et mmcqd. (Gardez à l'esprit que le rapport de bug collecté peut influencer les indicateurs de thrashing.)

Les journaux ANR peuvent fournir un instantané mémoire similaire.

Obtenir un instantané de mémoire

L'instantané de mémoire est un dumpstate qui liste les processus Java et natifs en cours d'exécution (pour en savoir plus, consultez Afficher les allocations de mémoire globales). N'oubliez pas que l'instantané ne donne que l'état à un moment précis. Le système peut avoir été en meilleure (ou pire) forme avant l'instantané.

Diffusions

Les applications génèrent des diffusions pour envoyer des événements dans l'application actuelle ou dans une autre application. Les broadcast receivers s'abonnent à des messages spécifiques (via des filtres), ce qui leur permet à la fois d'écouter et de répondre à une diffusion. Les rapports de bug contiennent des informations sur les diffusions envoyées et non envoyées, ainsi qu'un dumpsys de tous les récepteurs écoutant une diffusion spécifique.

Afficher les diffusions précédentes

Les diffusions historiques sont celles qui ont déjà été envoyées. Elles sont listées par ordre chronologique inverse.

La section Résumé présente un aperçu des 300 dernières diffusions au premier plan et des 300 dernières diffusions en arrière-plan.

La section Détails contient des informations complètes sur les 50 dernières diffusions au premier plan et les 50 dernières diffusions en arrière-plan, ainsi que sur les récepteurs de chaque diffusion. Récepteurs disposant :

  • Les entrées BroadcastFilter sont enregistrées au moment de l'exécution et ne sont envoyées qu'aux processus déjà en cours d'exécution.
  • Les entrées ResolveInfo sont enregistrées via les entrées de fichier manifeste. L'ActivityManager démarre le processus pour chaque ResolveInfo s'il n'est pas déjà en cours d'exécution.

Afficher les diffusions actives

Les diffusions actives sont celles qui n'ont pas encore été envoyées. Un grand nombre dans la file d'attente signifie que le système ne peut pas distribuer les diffusions assez rapidement pour suivre le rythme.

Afficher les auditeurs de la diffusion

Pour afficher la liste des récepteurs à l'écoute d'une diffusion, consultez le tableau du résolveur de récepteurs dans dumpsys activity broadcasts. L'exemple suivant affiche tous les récepteurs à l'écoute de USER_PRESENT.

Contrôle des conflits

La journalisation des conflits de moniteur peut parfois indiquer un véritable conflit de moniteur, mais le plus souvent, elle indique que le système est tellement chargé que tout a ralenti. Vous pouvez voir de longs événements de surveillance consignés par ART dans le journal système ou d'événements.

Dans le journal système :

10-01 18:12:44.343 29761 29914 W art     : Long monitor contention event with owner method=void android.database.sqlite.SQLiteClosable.acquireReference() from SQLiteClosable.java:52 waiters=0 for 3.914s

Dans le journal des événements :

10-01 18:12:44.364 29761 29914 I dvm_lock_sample: [com.google.android.youtube,0,pool-3-thread-9,3914,ScheduledTaskMaster.java,138,SQLiteClosable.java,52,100]

Compilation en arrière-plan

La compilation peut être coûteuse et charger l'appareil.

La compilation peut avoir lieu en arrière-plan lorsque les mises à jour du Google Play Store sont en cours de téléchargement. Dans ce cas, les messages de l'application Google Play Store (finsky) et installd s'affichent avant les messages dex2oat.

La compilation peut également avoir lieu en arrière-plan lorsqu'une application charge un fichier dex qui n'a pas encore été compilé. Dans ce cas, vous ne verrez pas de journaux finsky ni installd.

Présentation

Pour établir le récit d'un problème (comment il a commencé, ce qui s'est passé, comment le système a réagi), il faut une chronologie solide des événements. Vous pouvez utiliser les informations du rapport de bug pour synchroniser les chronologies de plusieurs journaux et déterminer le code temporel exact du rapport de bug.

Synchroniser les timelines

Un rapport de bug reflète plusieurs chronologies parallèles : journal système, journal des événements, journal du noyau et plusieurs chronologies spécialisées pour les diffusions, les statistiques de batterie, etc. Malheureusement, les chronologies sont souvent signalées à l'aide de bases de temps différentes.

Les codes temporels du journal système et des événements sont dans le même fuseau horaire que celui de l'utilisateur (comme la plupart des autres codes temporels). Par exemple, lorsque l'utilisateur appuie sur le bouton d'accueil, le journal système indique :

10-03 17:19:52.939  1963  2071 I ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.google.android.googlequicksearchbox/com.google.android.launcher.GEL (has extras)} from uid 1000 on display 0

Pour la même action, le journal des événements indique :

10-03 17:19:54.279  1963  2071 I am_focused_activity: [0,com.google.android.googlequicksearchbox/com.google.android.launcher.GEL]

Les journaux du noyau (dmesg) utilisent une base de temps différente, en ajoutant des éléments de journal avec des secondes depuis la fin du bootloader. Pour enregistrer cette échelle de temps sur d'autres échelles de temps, recherchez les messages suspend exit et suspend entry :

<6>[201640.779997] PM: suspend exit 2015-10-03 19:11:06.646094058 UTC
…
<6>[201644.854315] PM: suspend entry 2015-10-03 19:11:10.720416452 UTC

Étant donné que les journaux du noyau peuvent ne pas inclure d'heure en mode veille, vous devez enregistrer le journal par morceaux entre les messages d'entrée et de sortie du mode veille. De plus, les journaux du noyau utilisent le fuseau horaire UTC et doivent être ajustés au fuseau horaire de l'utilisateur.

Identifier l'heure du rapport de bug

Pour déterminer quand un rapport de bug a été généré, commencez par consulter le journal système (Logcat) pour dumpstate: begin :

10-03 17:19:54.322 19398 19398 I dumpstate: begin

Ensuite, vérifiez les codes temporels du journal du noyau (dmesg) pour le message Starting service 'bugreport' :

<5>[207064.285315] init: Starting service 'bugreport'...

Travaillez à rebours pour corréler les deux événements, en gardant à l'esprit les mises en garde mentionnées dans Synchroniser les chronologies. Bien que de nombreuses choses se passent après le lancement du rapport de bug, la plupart des activités ne sont pas très utiles, car l'action de prendre le rapport de bug charge considérablement le système.

Puissance

Le journal des événements contient l'état de l'alimentation de l'écran (0 = écran éteint, 1 = écran allumé et 2 = Keyguard terminé).

Les rapports de bug contiennent également des statistiques sur les verrous de réveil, un mécanisme utilisé par les développeurs d'applications pour indiquer que leur application doit maintenir l'appareil allumé. (Pour en savoir plus sur les wakelocks, consultez PowerManager.WakeLock et Maintenir le processeur actif.)

Les statistiques agrégées sur la durée des wakelocks ne suivent que le temps pendant lequel un wakelock est réellement responsable du maintien de l'appareil en veille et n'incluent pas le temps pendant lequel l'écran est allumé. De plus, si plusieurs wakelocks sont maintenus simultanément, la durée du wakelock est répartie entre ces wakelocks.

Pour obtenir de l'aide supplémentaire pour visualiser l'état de l'alimentation, utilisez Battery Historian, un outil Open Source de Google permettant d'analyser les consommateurs de batterie à l'aide de fichiers bugreport Android.

Packages

La section DUMP OF SERVICE package contient les versions de l'application (et d'autres informations utiles).

Processus

Les rapports de bug contiennent une grande quantité de données pour les processus, y compris l'heure de début et de fin, la durée d'exécution, les services associés, le score oom_adj, etc. Pour en savoir plus sur la façon dont Android gère les processus, consultez Processus et threads.

Déterminer la durée d'exécution du processus

La section procstats contient des statistiques complètes sur la durée d'exécution des processus et des services associés. Pour obtenir un résumé rapide et lisible, recherchez AGGREGATED OVER pour afficher les données des trois ou 24 dernières heures, puis recherchez Summary: pour afficher la liste des processus, la durée d'exécution de ces processus à différentes priorités et leur utilisation de la RAM au format min-moyenne-max PSS/min-moyenne-max USS.

Raisons pour lesquelles un processus est en cours d'exécution

La section dumpsys activity processes liste tous les processus en cours d'exécution, classés par score oom_adj (Android indique l'importance d'un processus en lui attribuant une valeur oom_adj, qui peut être mise à jour de manière dynamique par ActivityManager). Le résultat est semblable à celui d'un instantané de mémoire, mais inclut des informations supplémentaires sur ce qui provoque l'exécution du processus. Dans l'exemple ci-dessous, les entrées en gras indiquent que le processus gms.persistent s'exécute avec la priorité vis (visible) parce que le processus système est lié à son NetworkLocationService.

Analyses

Pour identifier les applications qui effectuent un nombre excessif d'analyses Bluetooth Low Energy (BLE) :

  • Recherchez les messages du journal pour BluetoothLeScanner :
    $ grep 'BluetoothLeScanner' ~/downloads/bugreport.txt
    07-28 15:55:19.090 24840 24851 D BluetoothLeScanner: onClientRegistered() - status=0 clientIf=5
    
  • Recherchez le PID dans les messages du journal. Dans cet exemple, "24840" et "24851" sont les PID (ID de processus) et TID (ID de thread).
  • Localisez l'application associée au PID :
    PID #24840: ProcessRecord{4fe996a 24840:com.badapp/u0a105}
    

    Dans cet exemple, le nom du package est com.badapp.

  • Recherchez le nom du package sur Google Play pour identifier l'application responsable : https://play.google.com/store/apps/details?id=com.badapp.

Remarque : Pour les appareils équipés d'Android 7.0, le système collecte des données pour les analyses BLE et associe ces activités à l'application à l'origine de l'analyse. Pour en savoir plus, consultez Scans Bluetooth et Low Energy (LE).