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 bugs avec Android Debug Bridge (adb). Les versions Android 4.2 et ultérieures prennent en charge une option pour les développeurs permettant de créer des rapports de bugs et de les partager par e-mail, Drive, etc.

Les rapports de bugs 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 des rapports de bugs, décrivent les problèmes courants et fournissent des conseils et des commandes grep utiles pour trouver les journaux associés à ces bugs. La plupart des sections incluent également des exemples de commande et de sortie grep et/ou de sortie dumpsys.

Logcat

Le journal logcat est un vidage basé sur des chaînes 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, bien que UID ne soit pas toujours listé dans les anciennes versions d'Android.

Afficher le journal des événements

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

Les niveaux de journalisation sont les suivants:

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

 

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

ANR et interblocages

Les rapports de bugs peuvent vous aider à identifier l'origine des erreurs ANR (l'application ne répond pas) 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 vide la pile dans /data/anr. Pour découvrir le coupable d'une erreur 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'erreur ANR.

Rechercher des traces de pile

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

  • Le thread principal ne vous indique que ce qu'il faisait au moment de l'erreur ANR, ce qui peut ou non correspondre à la véritable cause de l'erreur ANR. (La pile du rapport de bug peut être innocente. Quelque chose d'autre a peut-être été bloqué pendant une longue période (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 section appropriée.

Rechercher des interblocages

Les interblocages apparaissent souvent d'abord sous la forme d'erreurs ANR, car les threads se bloquent. Si le blocage affecte le serveur système, le chien de garde 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 que techniquement il s'agisse d'un redémarrage d'exécution plutôt que d'un véritable redémarrage.

  • Lors d'un redémarrage au démarrage, 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 kernel a planté. L'utilisateur voit l'appareil revenir au logo de démarrage Google.

Pour trouver des interblocages, recherchez dans les sections de traces de VM un modèle de thread A attendant 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, ce qui rend la localisation de l'activité en cours lors d'un plantage très importante. Les activités (via ActivityManager) exécutent des processus. Il peut donc être utile de localiser tous les arrêts et démarrages de processus pour une activité donnée.

Afficher les activités ciblées

Pour consulter l'historique des activités en mode Concentré, 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 surcharge

Pour déterminer si l'appareil est en thrashing, recherchez une augmentation anormale de l'activité autour de am_proc_died et am_proc_start en peu de temps.

Mémoire

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

Identifier une mémoire insuffisante

Une faible quantité de mémoire peut entraîner une surcharge du système, car il arrête certains processus pour libérer de la mémoire, mais continue de démarrer d'autres processus. Pour obtenir des preuves concordantes d'une 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 insuffisante 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 d'accueil, et 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 mort. Le système commence alors à arrêter les services.

Afficher les indicateurs de fragmentation

D'autres indicateurs de surcharge du système (pagination, récupération directe, etc.) incluent les cycles de consommation de kswapd, kworker et mmcqd. (N'oubliez pas que le rapport de bug collecté peut influencer les indicateurs de fragmentation.)

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

Obtenir un instantané de mémoire

L'instantané de la mémoire est un dumpstate qui liste les processus Java et natifs en cours d'exécution (pour en savoir plus, consultez la section Afficher les allocations de mémoire globales). N'oubliez pas que l'instantané ne donne que l'état à un moment donné. Le système aurait pu être 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 vers une autre application. Les broadcast receivers s'abonnent à des messages spécifiques (via des filtres), ce qui leur permet d'écouter et de répondre à une diffusion. Les rapports de bugs contiennent des informations sur les diffusions envoyées et non envoyées, ainsi qu'un dumpsys de tous les récepteurs qui écoutent une diffusion spécifique.

Afficher les diffusions historiques

Les diffusions historiques sont celles qui ont déjà été envoyées, listées dans l'ordre chronologique inverse.

La section Résumé présente les 300 dernières diffusions au premier plan et les 300 dernières diffusions en arrière-plan.

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

  • 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 des entrées de fichier manifeste. 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 nombre élevé dans la file d'attente signifie que le système ne peut pas distribuer les diffusions assez rapidement pour suivre.

Afficher les auditeurs de la diffusion

Pour afficher la liste des récepteurs qui écoutent 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 conflit réel de moniteur, mais le plus souvent, elle indique que le système est tellement chargé que tout a ralenti. Vous pouvez voir des événements de surveillance longs 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 se produire en arrière-plan lorsque les mises à jour du Google Play Store sont téléchargées. Dans ce cas, les messages de l'application Google Play Store (finsky) et installd s'affichent avant les messages dex2oat.

La compilation peut également se produire 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 journalisation finsky ou installd.

Présentation

Établir le récit d'un problème (comment il a commencé, ce qui s'est passé, comment le système a réagi) nécessite 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 l'horodatage exact du rapport de bug.

Calendriers de synchronisation

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 la batterie, etc. Malheureusement, les chronologies sont souvent signalées à l'aide de bases temporelles différentes.

Les codes temporels du système et du journal des événements sont dans le même fuseau horaire que 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 kernel (dmesg) utilisent une base temporelle différente, en taguant les é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 (suspendre la sortie) et suspend entry (suspendre l'entrée) :

<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 l'heure pendant la suspension, vous devez enregistrer le journal par parties entre les messages d'entrée et de sortie de la suspension. De plus, les journaux du kernel 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é, vérifiez d'abord le journal système (Logcat) pour dumpstate: begin:

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

Vérifiez ensuite les codes temporels du journal du kernel (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 la section Chronologie de la synchronisation. Bien que de nombreuses choses se produisent après le lancement du rapport de bug, la plupart des activités ne sont pas très utiles, car le fait de créer 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, où 0 correspond à l'écran éteint, 1 à l'écran allumé et 2 à la fin du verrouillage des touches.

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

Les statistiques agrégées sur la durée du wakelock 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 pour visualiser l'état de l'alimentation, utilisez Battery Historian, un outil Open Source de Google qui permet d'analyser les consommateurs de batterie à l'aide de fichiers de rapport de bug Android.

Packages

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

Processus

Les rapports de bugs contiennent une énorme quantité de données sur les processus, y compris l'heure de début et d'arrêt, 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 la section Processus et threads.

Déterminer l'environnement 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 dernières heures ou des 24 dernières heures, puis recherchez Summary: pour afficher la liste des processus, la durée pendant laquelle ces processus ont été exécutés à différentes priorités et leur utilisation de la RAM au format min-moyenne-max PSS/min-moyenne-max USS.

Pourquoi un processus est-il 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 du processus en lui attribuant une valeur oom_adj, qui peut être mise à jour dynamiquement par ActivityManager). La sortie est semblable à celle 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 une priorité vis (visible) car le processus système est lié à son NetworkLocationService.

Analyses

Pour identifier les applications effectuant des analyses Bluetooth à basse consommation (BLE) excessives, procédez comme suit:

  • Recherchez les messages de 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 de journal. Dans cet exemple, "24840" et "24851" correspondent au PID (identifiant de processus) et au TID (identifiant de thread).
  • Recherchez 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. Pour en savoir plus, consultez Bluetooth Low Energy (LE) et analyses Bluetooth.