DDMS Android: una guida alla console Android definitiva

Pubblicato: 2022-03-11

Lo sviluppo è un affare complicato. L'obiettivo continua a muoversi, nuove tecnologie e domini prendono periodicamente vita, nuovi strumenti spuntano ogni tanto e le lingue cambiano in quello che sembra essere un caos gestito.

Tuttavia, anche con tutti questi cambiamenti, le regole fondamentali rimangono le stesse. Una delle più importanti di queste regole sottostanti afferma che per creare un software davvero eccezionale, devi ottenere un'introspezione profonda, continua e dettagliata nel tuo sistema di esecuzione. Diagnostica , debug e profilatura sono termini talvolta utilizzati in questo contesto, ma la regola va più in profondità. Uno sviluppatore di prim'ordine "sente" letteralmente il suo sistema. Sa che ciò che causerà è un blocco in attesa del rilascio di più memoria, cosa farà funzionare i suoi thread in una carenza di CPU, quali azioni comporteranno un ampio I/O o un accesso alla rete, quindi rallenteranno l'intera operazione.

Non c'è davvero modo di aggirarlo. Potresti essere uno sviluppatore molto intelligente che scrive codice fantastico, ma, finché non avrai le abilità di cui sopra, ovvero essere in grado di monitorare e studiare i dettagli del comportamento di runtime del tuo sistema, continuerai a non riuscire a fornire il massimo applicazioni.

Infatti, dopo aver acquisito una certa esperienza, rileverai un'intera categoria di "malattie del codice" che possono essere ricondotte a trascurare la regola dell'introspezione: in poche parole, scrivere codice (a volte codice intelligente) senza monitorare continuamente i suoi effetti sulla piattaforma reale .

DDMS in Android: la mia arma preferita per l'introspezione

Fortunatamente per noi, la community Android è riuscita a fornire così tanti strumenti di introspezione di prim'ordine. Lo Stetho di Facebook è tra i migliori, l'ARO ("Application Resource Optimizer") di AT&T è un po' più vecchio ma ancora di prim'ordine, con probabilmente la migliore console di monitoraggio della rete in circolazione, mentre LeakCanary adotta un approccio molto più limitato concentrandosi (e facendo benissimo a it) sulla libreria di rilevamento delle perdite di memoria di runtime. Per farla breve, non mancano gli strumenti di debug Android là fuori.

Tuttavia, il diamante nella corona, lo strumento di introspezione di cui fidarsi quando è necessario estrarre dati cruciali, accurati e ben formattati per quanto riguarda il comportamento di runtime della tua app è ancora il buon vecchio Dalvik Debug Monitor Server (DDMS) in Android Studio, che è stato con noi (purtroppo poco utilizzato da così tanti team) dai tempi del plug-in Eclipse per Android.

Quanto è importante il DDMS nello sviluppo di Android? Bene, sapere quello che so ora sul DDMS e sul monitoraggio delle app mobili in generale, diciamo 5-6 anni fa, come sviluppatore Android meno esperto, mi avrebbe risparmiato molti mal di testa e notti di debug.

Illustrazione della copertina del DDMS Android: debug degli sviluppatori con DDMS.

E il fatto è che il DDMS è così semplice da padroneggiare!

Naturalmente, gran parte dell'utilizzo corretto, come con qualsiasi altro strumento software, deriva dall'esperienza. Devi affinare le tue capacità professionali per un po' di tempo finché non diventi davvero bravo nel monitoraggio delle prestazioni in runtime. Ma anche nel giro di poche ore, diciamo dopo aver letto questo articolo, se segui i miei suggerimenti e li applichi alla tua prossima app, i risultati saranno sorprendenti! Profilare e mettere a punto anche sistemi complessi non è così difficile. Può essere anche divertente!

Viene spesso posta una domanda sulla differenza tra sviluppatori mobili principianti e master. La padronanza del DDMS in Android, o in termini generali, la profilazione delle applicazioni e le capacità di introspezione, è una di queste differenze sostanziali.

Nota: una parte importante per diventare uno sviluppatore di prim'ordine consiste nell'utilizzare le migliori librerie disponibili nel tuo dominio. In un precedente articolo di Toptal, ho elencato alcune delle migliori librerie per sviluppatori disponibili per Android. In un certo senso, questo articolo è un sequel dell'articolo "libreria" e copre uno dei tanti strumenti Android. Inutile dire che se miri a migliorare le tue capacità di sviluppatore Android, leggilo ora!

Una guida rapida al DDMS in Android Studio

E ora, senza ulteriori indugi, analizziamo ora la descrizione di DDMS, uno degli strumenti per sviluppatori Android per eccellenza.

Quando si valuta lo sforzo contro il vantaggio, probabilmente nessun altro strumento può migliorare la qualità della tua app e aiutarti a individuare i bug davvero disordinati ed elusivi che potrebbe contenere. Ma ancora, per qualche ragione (pigrizia, qualcuno?), così tanti team non riescono a utilizzare DDMS.

Iniziamo con un corso accelerato in DDMS:

DDMS è accessibile tramite Studio > Strumenti > Android > Monitor dispositivo Android e facendo clic sul pulsante DDMS nel menu. Puoi anche posizionare è come un'icona di collegamento (lo faccio) nel pannello superiore.

Una volta aperto, ecco cosa vedrai:

Screenshot: accesso a DDMS tramite Android Device Monitor

Il pannello di sinistra consente la selezione del dispositivo/app e la console di destra ti offre più visualizzazioni, ognuna nella propria scheda, ognuna con una visualizzazione specifica della tua app.

I principali servizi forniti da Dalvik Debug Monitor Server sono:

  • Statistiche sull'utilizzo della memoria dell'app (statistiche sull'heap totale e sull'allocazione degli oggetti)
  • Statistiche del thread dell'app
  • Cattura dello schermo del dispositivo
  • Esplora file del dispositivo
  • Chiamate in arrivo e spoofing SMS
  • Spoofing dei dati di posizione
  • Logcat

Per ottenere il valore della memoria heap corrente utilizzato dalla tua app, procedi come segue:

  • Collega il dispositivo su cui è in esecuzione la tua app
  • Fare clic sul pulsante Aggiorna heap per abilitare la raccolta delle statistiche dell'heap
  • Apri la scheda Heap
  • Fare clic su "Cause GC" per forzare un'analisi GC. Solo dopo tale esecuzione inizierà la raccolta dei dati dell'heap
  • Tieni la scheda aperta, continua a lavorare sulla tua app e fai di nuovo clic periodicamente su "Cause GC" per aggiornare i dati delle statistiche dell'heap

Quest'ultima riga probabilmente richiede una spiegazione aggiuntiva. L'utilizzo della memoria è uno di quei valori analitici in cui la sua dinamica è molto più importante del valore iniziale. Per la maggior parte delle app, non ci preoccuperemo molto del valore di utilizzo iniziale dell'heap. Ci preoccuperemo molto del progresso di questo valore, in quanto ci fornirà una chiara indicazione di uno dei veri incubi che attendono gli sviluppatori mobili: perdite di memoria Android:

Schermata: i dati dell'heap vengono utilizzati per identificare una perdita di memoria Android in DDMS

Il mio utilizzo del modulo delle statistiche dell'heap è semplice; come parte del ciclo di vita dello sviluppo dell'app, dopo aver introdotto modifiche che dovrebbero influire sull'utilizzo dell'heap, attiverò il modulo "Cause GC" per avviare la raccolta delle statistiche, attivare (di solito più di una volta) le posizioni ad alta intensità di heap della mia app, e periodicamente "Causa GC" per aggiornare. Se l'utilizzo dell'heap continua a crescere, ho una perdita di memoria tra le mani e devo risolverla (dettagli su come - sotto). In caso contrario, e indipendentemente dalle dimensioni effettive dell'heap, sono a posto.

Se viene rilevata una perdita di memoria, il prossimo strumento che utilizzerò è Object Allocation Tracker. Vediamo cosa può fare per la gestione della memoria in Android.

Localizzatore di allocazione degli oggetti

Il tracker di allocazione, in poche parole, ti fornirà le informazioni necessarie per capire chi è la parte da "incolpare" per l'attuale dimensione dell'heap. Questo modulo ti dirà da quali thread e metodi provengono i comandi di allocazione in tempo reale, rendendolo prezioso per l'analisi della memoria in Android.

Per iniziare il monitoraggio, procedi come segue:

  • Selezionare il dispositivo/processo pertinente come prima
  • Passa alla scheda Tracker allocazione e fai clic su Avvia monitoraggio per iniziare.
  • Da qui in poi verranno tracciate tutte le nuove assegnazioni
  • Fai clic su "Ottieni allocazioni" per visualizzare un elenco di tutte le ultime allocazioni (le ultime dall'ultimo "inizio")
  • Per scoprire chi è l'autorità di assegnazione, fare clic su una riga specifica nell'elenco

Object Allocation Tracker in DDMS, interfaccia utente

Ora, per esperienza personale, l'esecuzione di azioni ad alta intensità di allocazione sulla tua app seguita dal clic su "Ottieni allocazioni" per visualizzare i contatori di allocazione dovrebbe in genere indirizzarti alla perdita in modo semplice; a volte, quando la perdita non è lineare (ovvero si verifica ogni tanto) OPPURE quando l'app contiene più perdite che potrebbero non funzionare. In questi casi, e non ne ho incontrati molti, dovrai ricorrere alla creazione manuale di un file HPROF dump e all'analisi. L'analisi della memoria e la gestione della memoria Android non verranno trattate in modo approfondito in questo articolo. Vedi qui per alcuni contatti.

Thread Info Console: utilizzo della CPU Android semplificato

Ben noto a qualsiasi sviluppatore, i percorsi sincroni di esecuzione della logica sono raggruppati in thread, ciascuno dei quali costituisce un flusso seriale di esecuzione all'interno dell'app. Letteralmente tutte le app utilizzano più di un singolo thread di esecuzione. Alcuni ne usano dozzine.

Un esame generale dei potenziali problemi quando si utilizzano i thread esula dallo scopo di questo articolo. Concentriamoci quindi su uno solo, vale a dire la fame di thread, che è il problema principale per cui visiteresti la console delle informazioni sui thread.

In tutte le applicazioni mobili, thread diversi si contenderanno il tempo della CPU. Semplicemente non ce ne sono abbastanza per andare in giro. Cosa succede se, per qualsiasi motivo, uno o più thread non ottengono il tempo di esecuzione di cui hanno bisogno? Di solito cose brutte. Il sistema non si comporterà come previsto, il che è sempre una cattiva idea. I potenziali motivi di questo problema potrebbero essere l'impostazione di una priorità bassa, l'esecuzione simultanea di altri thread che si impostano con una priorità eccessivamente alta, il trascorrere molto tempo sui monitor di sincronizzazione e altro ancora. Tutto notoriamente difficile da rilevare dalla sola revisione del codice.

Console thread DDMS Android in soccorso!

Thread Info Console in DDMS, interfaccia utente

Quando accedi alla visualizzazione del thread, vedrai un elenco composto da record di thread, ciascuno contenente il nome e l'ID del thread, e due contatori aggiuntivi chiamati utime e s. Utime misura il tempo totale impiegato dal thread nell'esecuzione del codice utente (pensa alle tue funzioni e alle librerie di terze parti), mentre misura il tempo totale speso per il codice di sistema (sleep, sincronizzazione, chiamate di sistema, il lotto). Il primo, utime, di solito sarà più interessante per noi, anche se posso pensare a problemi che si manifesteranno principalmente con il contatore delle cifre.

OK, abbiamo il nostro codice in esecuzione, inclusi diversi thread, e vogliamo assicurarci che tutti i nostri thread ottengano la loro quota di tempo di CPU. Per questo, prima lasciamo funzionare il nostro sistema per un po', quindi apriamo la scheda del thread e iniziamo a cercare valori utime "particolari". Zero può certamente rappresentare un problema: il thread non ha letteralmente avuto tempo di CPU e nessun utilizzo della CPU. Ma valori troppo alti potrebbero rappresentare un aspetto diverso dello stesso problema: vale a dire, thread la cui priorità è così alta da far morire di fame gli altri.

Nota che per un tipo di thread, il valore utime zero o vicino a zero non indicherà un problema reale. Questi sono i thread legati all'I/O, thread che eseguono principalmente l'accesso alla rete o al disco (o al database). Questi thread dovrebbero trascorrere la maggior parte del loro tempo in attesa dell'arrivo dei dati o bloccando le chiamate di sistema in sospeso, nessuna di queste azioni aumenta il contatore di utime. Conosci i tuoi thread!

Suggerimento: non utilizzare mai il nome predefinito del thread. Non significa nulla e in genere non riuscirai a rilevarlo nelle viste DDMS. invece, ogni volta che crei un thread o lo prelevi da un pool di thread, inizia la tua interazione assegnandogli un nome autoesplicativo. Questo ti semplificherà la vita rispetto al debug/profilazione del tuo sistema. Di solito antepongo il nome dell'app in modo da distinguere tra i thread generati da Android e quelli generati dal mio codice, ad esempio: MyApp-server-connector, MyApp-db-interactor, ecc.

Suggerimento: la priorità di un thread denota (in parole povere) la quantità di tempo CPU che verrà concesso dallo scheduler. La priorità assegnata ai thread di lavoro è di fondamentale importanza per le prestazioni complessive e la "fluidità" della tua app e in molti casi può fare la differenza tra un comportamento fluido e veloce e uno irregolare e lento. La regola qui è semplice: la priorità predefinita assegnata da Android, che è NORMALE=5, non è quasi sempre quella che si desidera utilizzare. Invece, per la maggior parte dei thread di lavoro, si desidera un impatto molto minore sull'utilizzo complessivo della CPU. Per fare ciò, all'avvio di un thread, imposta la sua priorità su un valore inferiore, di solito vado con priority=3.

Console delle statistiche di rete

Le statistiche di rete consentono di monitorare i canali di comunicazione in entrata e in uscita verso la tua app in modo ragionevolmente leggibile.

L'asse y nel grafico di rete rappresenta la velocità di trasferimento della trasmissione misurata in KB/secondo, mentre l'asse x rappresenta il tempo trascorso in secondi. Pertanto, per ottenere una rapida stima della dimensione della trasmissione, provare a stimare l'area del picco rilevante. Dopo un po', questo diventa piuttosto facile.

Si noti che, dopo aver inserito questa console, sarà necessario fare clic sul pulsante "abilita" in alto affinché le misurazioni di rete inizino a comparire.

Prima che la console di rete raggiungesse il livello attuale, gli sviluppatori di solito dovevano ricorrere all'utilizzo di app sniffer (alcuni lo fanno ancora) per ottenere informazioni simili.

La cosa grandiosa di questa console è il modo in cui visualizza uno dei principali comportamenti di consumo della batteria: quello della comunicazione continua di piccole dimensioni. Come molti di voi sanno, ciò che renderà la vostra app un consumo di batteria non sono i cinque minuti di rete intensiva che fa, ma piuttosto i lunghi periodi di rete breve e ripetuta, ad esempio per il mantenimento in vita, la diagnostica o gli aggiornamenti di stato.

Una volta che un tale schema viene rilevato e la visualizzazione visiva dei pacchetti della console di rete lo rende così semplice, pensa immediatamente al batch. Posso raggruppare più trasmissioni piccole in un'unica trasmissione grande? L'impatto sulla batteria di questo cambiamento è destinato a spostare le app da un scaricatore di batteria a una categoria ben educata!

Console delle statistiche di rete in DDMS

Suggerimento: non caricare mai un'immagine in memoria così com'è. Questo è un crash di memoria insufficiente in attesa di verificarsi. Invece, esegui il caricamento ridotto o, ancora meglio, utilizza una libreria di terze parti per gestire il ridimensionamento per te.

Anche se utilizzerai raramente queste informazioni, tieni presente che il DDMS si basa sullo stack Android Debug Bridge (ADB) per trasferire i dati indietro/dal dispositivo. Se il DDMS non mostra la tua app o si blocca nel mezzo di una sessione DDMS, la soluzione migliore sarà aprire una console e digitare:

 adb devices

per assicurarti che il tuo dispositivo sia accessibile e autorizzato con ADB. In caso contrario, in molti casi, il riavvio del server ADB locale dovrebbe risolvere il problema:

 adb kill-server adb devices # restarts the adb server and displays all detected devices

Se i problemi persistono e la tua app è installata su un dispositivo fisico, prova a disconnettere tutte le istanze dell'emulatore. Come mai? Poiché DDMS si connette sia ai dispositivi fisici che alle istanze dell'emulatore, l'impostazione predefinita è quest'ultima.

Esempio di utilizzo DDMS nella vita reale: un'app si interrompe (non si arresta in modo anomalo, ma si interrompe). L'utente si precipita immediatamente alla workstation vicina, si connette a USB e apre DDMS in visualizzazione thread per scoprire lo stack di thread » thread non riuscito » traccia dello stack, nel mio caso, a causa di un deadlock di sincronizzazione che, una volta rilevato, è stato facilmente risolto cambiando.

Suggerimento: se la memoria RAM standard assegnata alla tua app da Android non è sufficiente, come potrebbe accadere, ad esempio, per le app ad alta intensità di contenuti multimediali, tieni presente che puoi guadagnare circa il 15-20% di memoria aggiuntiva sulla maggior parte dei dispositivi alzando il flag manifest _ largeHeap : https://developer.android.com/guide/topics/manifest/application-element.html_

Emulazione dello stato del dispositivo in DDMS Android

Di norma, le app mobili non sono costrutti lineari. Al contrario, implementano strategie di consapevolezza che consentono loro di monitorare e reagire ai cambiamenti nello stato del dispositivo. Un'app può, ad esempio, ascoltare chiamate o messaggi di testo in arrivo, riallineare il proprio stato in base allo stato della rete e tracciare e reagire ai cambiamenti nella posizione del dispositivo.

Un banale esempio per quest'ultimo sarebbe un'app GPS. La maggior parte di noi non sviluppa tali app (ahimè, il mercato non è abbastanza grande...) ma comunque, in molti casi, distribuiamo la logica, che dipende dalla posizione, che si tratti di una semplice visualizzazione della mappa della posizione attuale dell'utente, del tracciamento del percorso o una visualizzazione dei dati sensibili alla posizione.

Il test per tali condizioni sensibili allo stato è notoriamente complesso, a volte più che scrivere il codice effettivo. Se hai un dispositivo fisico con SIM puoi, ovviamente, emettere e ricevere chiamate e SMS. Modificare lo stato della telefonia del dispositivo è molto più difficile, ma è ancora possibile. Le modifiche alla posizione del test potrebbero essere più complicate, anche se passeggiare per la città con il tuo laptop è un'opzione...

Ma ancora, come gestiremmo le istanze dell'emulatore? Come possiamo testarli per queste modifiche?

Esempio di emulazione dello stato del dispositivo in DDMS

DDMS in soccorso, ancora una volta. Una delle caratteristiche più forti ma spesso trascurate del DDMS è la sua capacità di emettere ("spoofing") eventi fittizi in un'istanza di emulatore in esecuzione. Il DDMS può inviare una chiamata da un numero specifico all'emulatore, inviare un SMS, modificare i dati sullo stato della telefonia e altro ancora.

Una volta arrivati ​​nell'emulatore, tutti questi eventi falsificati non saranno più distinguibili dagli eventi “reali”, cioè come se fossero ricevuti dai sensori hardware sottostanti. Nello specifico, tutti i ricevitori della tua app rilevante verranno attivati ​​nello stesso modo in cui avrebbero ricevuto una chiamata/un SMS reale.

L'attivazione dello stato e delle azioni della telefonia è piuttosto semplice:

Per testare la tua app per casi di connettività di rete bassa (cosa che dovresti in qualsiasi app centrata sulla rete) vai alla sezione Stato telefonia e imposta i valori di velocità e latenza sui valori desiderati. Di solito uso il valore GPRS per entrambi come un modo efficace per emulare una bassa connettività, ma sentiti libero di impostare i tuoi valori.

Per simulare telefonate o SMS, vai alla sezione Azione telefonia, imposta il numero di telefono di origine, aggiungi un messaggio di testo se necessario e spara. Questo strumento è particolarmente efficace quando hai impostato un percorso di codice dedicato per le chiamate dall'estero e vuoi testarlo nel rispetto del budget.

Le cose si fanno più interessanti quando si tratta di prendere in giro una nuova posizione.

Se tutto ciò a cui miri è impostare una nuova posizione per l'istanza dell'emulatore, scegli Manuale, imposta i valori di latitudine/longitudine desiderati e premi Invia.

Controlli di posizione manuali utilizzati per lo spoofing in DDMS

Ma cosa succede se, invece di impostare una posizione fissa, desideri che la tua app segua un percorso preimpostato, ad esempio esaminandone il comportamento mentre l'utente viaggia da una città all'altra? Un tale test può avere un grande valore per qualsiasi app supportata dalla mappa, nonché altre app sensibili alla posizione che impostano la loro finestra di dati in base alla posizione dell'utente. Qui, vorrai vedere che lo spostamento della posizione a velocità diverse manterrà aggiornata la finestra dei dati visualizzata.

Per questo utilizzeremo un formato speciale chiamato KML, che è stato sviluppato specificatamente per essere utilizzato con Google Earth e che rappresenta percorsi, o percorsi, come un insieme di punti collegati nello spazio, che possono essere abilitati da dispositivi GPS.

GPX è un formato di percorso alternativo supportato da DDMS. Per tutti gli scopi pratici, questi due dovrebbero essere considerati intercambiabili se utilizzati per lo spoofing della posizione mobile.

Esaminiamo ora le fasi dell'impostazione di un percorso fittizio nell'emulatore.

  1. Crea un percorso. Di gran lunga il modo più semplice sarebbe utilizzare l'opzione di direzione di Google Maps impostando l'origine e la destinazione appropriate.

Spoofing della posizione in DDMS con Google Maps

  1. Una volta visualizzato il percorso sulla mappa, vai alla riga dell'indirizzo e copia l'URL

  2. Con l'URL negli appunti, vai su GPS Visualizer, incollalo nella casella di testo "Fornisci URL" e fai clic sul pulsante Converti:

Spoofing della posizione DDMS: configurazione di GPS Wisualizer

e fare clic per scaricare il file GPX risultante (con un nome un po' disordinato, ad esempio 20170520030103-22192-data.gpx)

  1. Tornando a DDMS Location Control, apri la scheda GPX, fai clic su Carica GPX e seleziona il file appena scaricato

Importazione di GPX nel controllo della posizione DDMS

  1. Sono state fatte! Ora puoi navigare tra le diverse posizioni del percorso facendo clic sui pulsanti avanti e indietro o facendo clic sul pulsante Riproduci per attraversare automaticamente il percorso a una velocità impostata.

Non è necessario creare il proprio percorso. Un sacco di percorsi da scaricare da siti come OpenStreetMap (vedi la sezione "Tracce GPS").

Infine, tieni presente che, a differenza delle versioni precedenti di DDMS, in cui il caricamento dei file di percorso era un gioco da ragazzi, le versioni più recenti potrebbero richiedere alcuni tentativi ed errori durante il caricamento di un percorso specifico.

Ad esempio, sembra che solo GPX 1.1 sia supportato da DDMS. Le nuove versioni GPX potrebbero richiedere alcune regolazioni manuali.

Inoltre, il formato waypoint GPX non è più supportato. Invece, usa il formato traccia GPX:

 <trk> <name /> <cmt /> <trkseg> <trkpt lat="27.0512" lon="-80.4324"> <ele>0</ele> <time>2017-02-02T08:01:41Z</time> </trkpt> </trkseg> </trk>

Debug di Android: un'ora alla settimana fa la differenza!

Basta teoria! È ora di fare un po' di pratica. Suggerisco, supponendo che tu sia uno sviluppatore Android, che all'inizio del tuo prossimo progetto dedichi solo un'ora alla settimana per ottenere un'introspezione sulle prestazioni della tua app tramite DDMS.

Rimarrai sorpreso dalla quantità di informazioni di qualità (ovvero informazioni che possono essere utilizzate per migliorare immediatamente lo stato della tua app) che questo ti fornirà!

Android DDMS, come ho visto più e più volte con sviluppatori principianti, è uno strumento che può migliorare notevolmente le capacità di uno sviluppatore, a condizione che sia padroneggiato e utilizzato correttamente. La capacità di uno sviluppatore Android di fornire sistemi di prim'ordine aumenterà letteralmente di una o due tacche una volta sfruttato tutto il potenziale del DDMS nello sviluppo di Android. Pertanto, dedicare qualche ora per fare buon uso del DDMS sembra un investimento intelligente, in quanto può migliorare notevolmente le prestazioni e l'efficienza di Android.

Sii uno dei ragazzi intelligenti. Usalo.