Lecture des rapports de bogues

Les bogues sont une réalité dans tout type de développement, et les rapports de bogues sont essentiels pour identifier et résoudre les problèmes. Toutes les versions d'Android prennent en charge la capture de rapports de bogues avec Android Debug Bridge (adb) ; Les versions Android 4.2 et supérieures prennent en charge une option de développeur pour prendre des rapports de bogues et les partager par e-mail, Drive, etc.

Les rapports de bogues Android contiennent des dumpsys , dumpstate et logcat au format texte (.txt), ce qui vous permet de rechercher facilement un contenu spécifique. Les sections suivantes détaillent les composants des rapports de bogues, décrivent les problèmes courants et donnent des conseils utiles et des commandes grep pour rechercher les journaux associés à ces bogues. La plupart des sections incluent également des exemples pour la commande et la sortie grep et/ou la sortie dumpsys .

Logcat

Le journal logcat est un vidage basé sur une chaîne de toutes les informations logcat . La partie système est réservée au framework et a un historique plus long que main qui contient tout le reste. Chaque ligne commence généralement par l' timestamp UID PID TID log-level , bien que l' UID puisse ne pas être répertorié dans les anciennes versions d'Android.

Affichage du journal des événements

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

Les niveaux de journalisation incluent les éléments suivants :

  • V : verbeux
  • D : débogage
  • Moi : informations
  • W : avertissement
  • E : erreur

Pour d'autres balises de journal d'événements utiles, reportez-vous à /services/core/java/com/android/server/EventLogTags.logtags .

ANR et blocages

Les rapports de bogues peuvent vous aider à identifier les causes des erreurs d' application qui ne répondent pas (ANR) et des événements de blocage.

Identification des 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 tue le processus et vide la pile dans /data/anr . Pour découvrir le coupable derrière un ANR, grep pour am_anr dans le journal des événements binaires.

Vous pouvez également grep pour ANR in 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 qui correspondent à un ANR. Assurez-vous que l'horodatage et le PID sur les traces de VM correspondent à l'ANR que vous étudiez, puis vérifiez le thread principal du processus. Gardez à l'esprit:

  • Le thread principal vous indique uniquement ce que le thread faisait au moment de l'ANR, ce qui peut ou non correspondre à la véritable cause de l'ANR. (La pile dans le rapport de bogue peut être innocente ; quelque chose d'autre peut avoir été bloqué pendant longtemps, mais pas assez longtemps pour ANR, avant de se décoller.)
  • Plusieurs ensembles de traces de pile ( VM TRACES JUST NOW et VM TRACES AT LAST ANR ) peuvent exister. Assurez-vous de consulter la bonne section.

Trouver des impasses

Les blocages apparaissent souvent d'abord comme des ANR parce que les threads sont bloqués. Si le blocage frappe le serveur système, le chien de garde finira par le tuer, ce qui conduira à une entrée dans le journal similaire à : 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 d'exécution plutôt que d'un véritable redémarrage.

  • Lors d'un redémarrage d'exécution , le serveur système meurt et est redémarré ; l'utilisateur voit l'appareil revenir à l'animation de démarrage.
  • Lors d'un redémarrage , le noyau a planté ; l'utilisateur voit l'appareil revenir au logo de démarrage de Google.

Pour trouver des interblocages, consultez les sections de suivi de la machine virtuelle pour un modèle de thread A attendant quelque chose détenu par le thread B, qui à son tour attend quelque chose détenu par le thread A.

Activités

Une activité est un composant d'application qui permet aux utilisateurs d'interagir avec un écran pour faire quelque chose comme composer un numéro, prendre une photo, envoyer un e-mail, etc. Du point de vue d'un rapport de bogue, une activité est une chose unique et ciblée qu'un utilisateur peut faire. , ce qui rend la localisation de l'activité qui était au centre de l'attention lors d'un crash très importante. Les activités (via ActivityManager) exécutent des processus, donc la localisation de tous les arrêts et démarrages de processus pour une activité donnée peut également faciliter le dépannage.

Affichage des activités ciblées

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

Le processus de visualisation commence

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

L'appareil s'agite-t-il ?

Pour déterminer si l'appareil se bloque , recherchez une augmentation anormale de l'activité autour de am_proc_died et am_proc_start dans un court laps de temps.

Mémoire

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

Identification d'un manque de mémoire

Une mémoire insuffisante peut provoquer un blocage du système car il tue certains processus pour libérer de la mémoire mais continue à démarrer d'autres processus. Pour afficher des preuves corroborantes d'une mémoire insuffisante, vérifiez les 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 contrecarrer les tentatives de retour (parce que la tâche à laquelle l'utilisateur essayait de revenir a été tuée). Si le lanceur a été tué, il redémarre lorsque l'utilisateur touche le bouton d'accueil et les journaux montrent que le lanceur recharge son contenu.

Visualisation des 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. Après cela, le système commence à tuer les services.

Affichage des indicateurs de raclée

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

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

Obtenir un instantané de la mémoire

L'instantané de mémoire est un état de vidage qui répertorie les processus Java et natifs en cours d'exécution (pour plus de détails, reportez-vous à Affichage des allocations de mémoire globales ). Gardez à l'esprit que l'instantané ne donne que l'état à un moment précis dans le temps ; le système était peut-être en meilleur (ou pire) état avant l'instantané.

Émissions

Les applications génèrent des diffusions pour envoyer des événements au sein de l'application actuelle ou à une autre application. Les récepteurs de diffusion 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 bogue 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.

Affichage des diffusions historiques

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

La section récapitulative est un aperçu des 300 dernières diffusions en premier plan et des 300 dernières diffusions en arrière-plan.

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

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

Affichage des 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 envoyer les diffusions assez rapidement pour suivre le rythme.

Affichage des auditeurs de diffusion

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

Surveiller les conflits

La journalisation des conflits de moniteur peut parfois indiquer un conflit de moniteur réel, mais indique le plus souvent que le système est tellement chargé que tout a ralenti. Vous pouvez voir des événements de surveillance longue consignés par ART dans le système ou le journal des é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 lors du téléchargement des mises à jour de Google Play Store. Dans ce cas, les messages de l'application Google Play Store ( finsky ) et installd apparaissent 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 finsky ou installd .

Récit

É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 bogue pour synchroniser les chronologies sur plusieurs journaux et déterminer l'horodatage exact du rapport de bogue.

Synchronisation des chronologies

Un rapport de bogue 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 en utilisant différentes bases de temps.

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

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 signale :

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, marquant les éléments du journal avec des secondes depuis la fin du chargeur de démarrage. Pour enregistrer cette échelle de temps sur d'autres échelles de temps, recherchez les messages de suspension de sortie et de suspension d'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 de temps pendant la suspension, vous devez enregistrer le journal par morceaux entre les messages d'entrée et de sortie de suspension. 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 bogue

Pour déterminer quand un rapport de bogue a été pris, vérifiez d'abord le journal système (Logcat) pour le dumpstate: begin :

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

Ensuite, vérifiez les horodatages 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 Synchronisation des chronologies . Bien qu'il se passe beaucoup de choses après le lancement du rapport de bogue, la plupart des activités ne sont pas très utiles car le fait de prendre le rapport de bogue charge considérablement le système.

Pouvoir

Le journal des événements contient l'état de l'alimentation de l'écran, où 0 est l'écran éteint, 1 est l'écran allumé et 2 est pour le verrouillage du clavier terminé.

Les rapports de bogue 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 rester allumée. (Pour plus de détails sur les wakelocks, reportez-vous à PowerManager.WakeLock et Keep the CPU on .)

Les statistiques agrégées sur la durée du wakelock suivent uniquement le temps pendant lequel un wakelock est réellement chargé de maintenir l'appareil éveillé et n'incluent pas le temps avec l'écran allumé. De plus, si plusieurs wakelocks sont maintenus simultanément, la durée du wakelock est répartie sur ces wakelocks.

Pour plus d'aide sur la visualisation de l'état de l'alimentation, utilisez Battery Historian , un outil open source de Google pour analyser les consommateurs de batterie à l'aide de fichiers de rapport de bogues Android.

Paquets

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

Processus

Les rapports de bogues contiennent une énorme quantité de données pour les processus, y compris l'heure de démarrage et d'arrêt, la durée d'exécution, les services associés, le score oom_adj , etc. Pour plus de détails sur la façon dont Android gère les processus, reportez-vous à Processes and Threads .

Détermination de 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 un résumé rapide et lisible par l'homme, 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 RAM utilisation formatée comme min-moyenne-max PSS/min-moyenne-max USS.

Pourquoi un processus est-il en cours d'exécution ?

La section dumpsys activity processes répertorie tous les processus en cours d'exécution classés par score oom_adj (Android indique l'importance du processus en attribuant au processus une valeur oom_adj , qui peut être mise à jour dynamiquement par ActivityManager). La sortie est similaire à 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 à la priorité vis (visible) car le processus système est lié à son NetworkLocationService .

Numérisations

Utilisez les étapes suivantes pour identifier les applications effectuant des analyses Bluetooth Low Energy (BLE) excessives :

  • Trouver 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
    
  • Localisez le PID dans les messages du journal. Dans cet exemple, "24840" et "24851" sont 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 exécutant Android 7.0, le système collecte des données pour les analyses BLE et associe ces activités à l'application initiatrice. Pour plus de détails, voir Recherches Low Energy (LE) et Bluetooth .