Android DDMS: um guia para o Ultimate Android Console
Publicados: 2022-03-11Desenvolver é um negócio complicado. O alvo continua se movendo, novas tecnologias e domínios periodicamente ganham vida, novas ferramentas aparecem de vez em quando e os idiomas mudam no que parece ser um caos gerenciado.
Ainda assim, mesmo com todas essas mudanças, as regras fundamentais permanecem as mesmas. Uma das mais importantes dessas regras subjacentes afirma que, para criar um software realmente incrível, você deve obter uma introspecção profunda, contínua e detalhada em seu sistema em execução. Diagnóstico , depuração e criação de perfil são termos às vezes usados nesse contexto, mas a regra é mais profunda. Um desenvolvedor de alto nível literalmente “sente” seu sistema. Ele sabe o que causará é a espera de mais memória para liberar, o que levará seus threads à fome da CPU, quais ações resultarão em extensa E / S ou acesso à rede, portanto, retardará toda a operação.
Não há realmente nenhuma maneira de contornar isso. Você pode ser um desenvolvedor muito inteligente escrevendo código incrível, mas, até que você não tenha a habilidade acima, ou seja, ser capaz de monitorar e estudar os detalhes do comportamento de tempo de execução do seu sistema, você ainda ficará para trás quando se trata de entregar realmente alto nível formulários.
De fato, depois de ganhar alguma experiência, você detectará toda uma categoria de “doenças de código” que podem ser atribuídas a negligenciar a regra da introspecção: resumindo, escrever código (às vezes código inteligente) sem monitoramento contínuo de seus efeitos na plataforma real .
DDMS no Android: minha arma preferida para introspecção
Felizmente para nós, a comunidade Android conseguiu entregar tantas ferramentas de introspecção de primeira qualidade. O Stetho do Facebook está entre os melhores, o ARO ("Application Resource Optimizer") da AT&T é um pouco mais antigo, mas ainda de alto nível, com provavelmente o melhor console de monitoramento de rede existente, enquanto o LeakCanary adota uma abordagem muito mais limitada, concentrando-se (e se saindo muito bem em it) na biblioteca de detecção de vazamento de memória em tempo de execução. Para encurtar a história, não há escassez de ferramentas de depuração do Android por aí.
Ainda assim, o diamante na coroa, a ferramenta de introspecção para confiar quando dados cruciais, precisos e bem formatados precisam ser extraídos em relação ao comportamento de tempo de execução do seu aplicativo ainda é o bom e velho Dalvik Debug Monitor Server (DDMS) no Android Studio, que tem estado conosco (infelizmente subutilizado por tantas equipes) desde os dias do plugin Eclipse Android.
Qual a importância do DDMS no desenvolvimento Android? Bem, saber o que sei agora sobre DDMS e monitoramento de aplicativos móveis em geral, digamos 5-6 anos atrás, como um desenvolvedor Android menos experiente, teria me poupado muitas dores de cabeça e noites de depuração.
E o fato é que o DDMS é tão simples de dominar!
Claro, uma grande parte de usá-lo corretamente, como acontece com qualquer outra ferramenta de software, vem com a experiência. Você precisa aprimorar suas habilidades profissionais por algum tempo até se tornar realmente bom em monitoramento de desempenho em tempo de execução. Mas mesmo em questão de horas, digamos depois de ler este artigo, se você seguir minhas sugestões e aplicá-las em seu próximo aplicativo, os resultados serão incríveis! Criar perfis e ajustar até mesmo sistemas complexos não é tão difícil. Pode ser divertido também!
Uma pergunta geralmente é feita sobre a diferença entre desenvolvedores móveis iniciantes e de nível mestre. Dominar o DDMS no Android – ou em termos gerais, perfis de aplicativos e recursos de introspecção – é uma dessas diferenças importantes.
Observação: a maior parte de se tornar um desenvolvedor de primeira linha é usar as melhores bibliotecas disponíveis em seu domínio. Em um artigo anterior da Toptal, listei algumas das melhores bibliotecas de desenvolvedores disponíveis para Android. De certa forma, este artigo é uma continuação do artigo “biblioteca” e abrange uma das muitas ferramentas do Android. Escusado será dizer que, se você pretende melhorar suas habilidades de desenvolvedor Android, leia agora!
Um guia rápido para DDMS no Android Studio
E agora, sem mais delongas, vamos nos aprofundar na descrição do DDMS, uma das melhores ferramentas para desenvolvedores Android.
Ao pesar o esforço contra o benefício, provavelmente nenhuma outra ferramenta pode melhorar a qualidade do seu aplicativo e ajudá-lo a localizar os erros realmente confusos e indescritíveis que ele pode conter. Mas ainda assim, por algum motivo (preguiça, alguém?), muitas equipes falham em usar o DDMS.
Vamos começar com um curso intensivo em DDMS:
O DDMS pode ser acessado via Studio > Tools > Android > Android Device Monitor e clicando no botão DDMS no menu. Você também pode colocar is como um ícone de atalho (eu faço) no painel superior.
Uma vez aberto, isto é o que você verá:
O painel esquerdo permite a seleção de dispositivo/aplicativo e o console direito fornece várias visualizações, cada uma em sua própria guia, cada uma exibindo uma visualização específica do seu aplicativo.
Os principais serviços fornecidos pelo Dalvik Debug Monitor Server são:
- Estatísticas de uso de memória do aplicativo (heap total e estatísticas de alocação de objetos)
- Estatísticas de conversas do aplicativo
- Captura de tela do dispositivo
- Explorador de arquivos do dispositivo
- Falsificação de chamadas e SMS recebidas
- Falsificação de dados de localização
- Logcat
Para obter o valor de memória heap atual usado pelo seu aplicativo, faça o seguinte:
- Conecte o dispositivo no qual seu aplicativo está sendo executado
- Clique no botão Update Heap para habilitar a coleta de estatísticas de heap
- Abra a guia Heap
- Clique em “Cause GC” para forçar uma execução de GC. Somente após essa execução a coleta de dados de heap começará
- Mantenha a guia aberta, continue trabalhando em seu aplicativo e clique novamente periodicamente em “Causa GC” para atualizar os dados de estatísticas de heap
Esta última linha provavelmente requer explicação adicional. O uso da memória é um daqueles valores analíticos onde sua dinâmica é muito mais importante que o valor inicial. Para a maioria dos aplicativos, não nos importaremos muito com o valor inicial de uso do heap. Vamos nos preocupar muito com o progresso desse valor, pois ele nos fornecerá uma indicação clara de um dos verdadeiros pesadelos que aguardam os desenvolvedores móveis - vazamentos de memória do Android:
Meu uso do módulo heap stat é simples; como parte do ciclo de vida de desenvolvimento do aplicativo, depois de introduzir alterações que devem afetar o uso de heap, ativarei o módulo "Causa GC" para iniciar a coleta de estatísticas, ativar (geralmente mais de uma vez) as posições de uso intensivo de heap do meu aplicativo, e periodicamente “Fazer GC” para atualizar. Se o uso de heap continuar crescendo, tenho um vazamento de memória em minhas mãos e preciso resolvê-lo (detalhes sobre como - abaixo). Se não, e independentemente do tamanho real do heap, estou bem.
Se for detectado um vazamento de memória, a próxima ferramenta que usarei é o Object Allocation Tracker. Vamos ver o que ele pode fazer pelo gerenciamento de memória no Android.
Rastreador de alocação de objetos
O rastreador de alocação, em poucas palavras, fornecerá as informações necessárias para descobrir quem é a parte “culpada” pelo tamanho do heap atual. Este módulo informará de quais threads e métodos os comandos de alocação vieram em tempo real, tornando-o inestimável para análise de memória no Android.
Para iniciar o rastreamento, faça o seguinte:
- Selecione o dispositivo/processo relevante como antes
- Alterne para a guia Allocation Tracker e clique em Start Tracking para começar.
- A partir daqui, todas as novas alocações serão rastreadas
- Clique em “Obter alocações” para obter uma visualização de lista de todas as alocações mais recentes (mais recentes desde o último “início”)
- Para descobrir quem é a autoridade de alocação, clique em uma linha específica na lista
Agora, pela minha própria experiência, executar ações de alocação intensiva em seu aplicativo seguidas de clicar em “Obter alocações” para visualizar os contadores de alocação normalmente deve direcioná-lo ao vazamento de maneira direta; às vezes, quando o vazamento não é linear (ou seja, acontece de vez em quando) OU quando seu aplicativo contém vários vazamentos que podem não funcionar. Nesses casos, e não encontrei muitos deles, você precisará recorrer à criação manual de um arquivo HPROF de despejo e analisá-lo. A análise de memória e o gerenciamento de memória do Android não serão abordados em profundidade neste artigo. Veja aqui algumas pistas.
Console de informações de thread: uso da CPU Android facilitado
Bem conhecido por qualquer desenvolvedor, os caminhos síncronos de lógica de execução são agrupados em threads, cada um compondo um fluxo serial de execução em seu aplicativo. Literalmente, todos os aplicativos usam mais de um único thread de execução. Alguns deles usam dezenas.
Um exame geral de possíveis problemas ao usar threads está fora do escopo deste artigo. Vamos nos concentrar então em um único, ou seja, fome de encadeamento, que é o principal problema para o qual você visitaria o console de informações de encadeamento.
Em todos os aplicativos móveis, diferentes threads competirão pelo tempo de CPU. Simplesmente não há o suficiente deles para circular. O que acontece se, por qualquer motivo, uma ou mais threads não obtiverem o tempo de execução de que precisam? Geralmente coisas ruins. O sistema não se comportará como você planejou, o que é sempre uma má ideia. Os possíveis motivos para esse problema podem ser a definição de baixa prioridade, outros threads executando simultaneamente a configuração com prioridade excessivamente alta, gastando muito tempo em monitores de sincronização e muito mais. Tudo notoriamente difícil de detectar apenas pela revisão de código.
Console de threads do Android DDMS para o resgate!
Ao entrar na visualização de encadeamentos, você verá uma lista composta de registros de encadeamentos, cada um contendo o nome e o ID do encadeamento, e dois contadores adicionais chamados utime e stime. O Utime mede o tempo total gasto pelo thread executando o código do usuário (pense em suas funções e bibliotecas de terceiros), enquanto o stime mede o tempo total gasto no código do sistema (suspensão, sincronização, chamadas do sistema – o lote). O primeiro - utime - geralmente será mais interessante para nós, embora eu possa pensar em problemas que se manifestarão principalmente pelo contador de tempo.
OK, temos nosso código em execução, incluindo vários threads, e queremos garantir que todos os nossos threads recebam sua parte do tempo de CPU. Para isso, primeiro deixamos nosso sistema funcionar por um tempo e, em seguida, abrimos a guia de thread e começamos a procurar por valores de utime “peculiares”. Zero certamente pode representar um problema - o encadeamento literalmente não tem tempo de CPU e nenhuma utilização de CPU. Mas valores excessivamente altos podem representar um aspecto diferente do mesmo problema: ou seja, threads cuja prioridade é tão alta que faz com que outros passem fome.
Observe que, para um tipo de encadeamento, o valor utime zero ou próximo de zero não indicará um problema real. Esses são os encadeamentos vinculados à E/S, encadeamentos que geralmente fazem acesso à rede ou ao disco (ou banco de dados). Esses threads devem passar a maior parte do tempo aguardando a chegada de dados ou bloqueando chamadas de sistema pendentes, nenhuma dessas ações aumenta o contador de utime. Conheça seus tópicos!
Dica: Nunca use o nome padrão do thread. Isso não significa nada e você normalmente falhará em detectá-lo nas visualizações do DDMS. em vez disso, sempre que criar um encadeamento ou buscá-lo em um conjunto de encadeamentos, inicie sua interação atribuindo-lhe um nome autoexplicativo. Isso tornará sua vida muito mais fácil do que depurar/criar o perfil do seu sistema. Eu costumo prefixar o nome do aplicativo para distinguir entre thread gerado pelo Android e aqueles gerados pelo meu próprio código, exemplo: MyApp-server-connector, MyApp-db-interactor, etc.

Dica: A prioridade de um thread denota (falando vagamente) a quantidade de tempo de CPU que será concedida pelo escalonador. A prioridade atribuída aos seus threads de trabalho é de importância crítica para o desempenho geral e a "suavidade" do seu aplicativo e, em muitos casos, pode ser a diferença entre um comportamento rápido e um comportamento lento e irregular. A regra aqui é simples: a prioridade padrão atribuída pelo Android, que é NORMAL=5, quase sempre não é aquela que você deseja usar. Em vez disso, para a maioria dos threads de trabalho, você deseja um impacto muito menor no uso geral da CPU. Para fazer isso, na inicialização de um thread, defina sua prioridade para um valor menor, costumo usar prioridade=3.
Console de estatísticas de rede
As estatísticas de rede permitem que você monitore os canais de comunicação de entrada e saída para seu aplicativo de maneira razoavelmente legível por humanos.
O eixo y no gráfico de rede representa a velocidade de transferência da transmissão medida em KB/segundo, enquanto o eixo x representa o tempo decorrido em segundos. Portanto, para obter uma estimativa rápida do tamanho da transmissão, tente estimar a área do pico relevante. Depois de um tempo, isso se torna bastante fácil.
Observe que, após entrar neste console, você precisará clicar no botão superior “habilitar” para que as medições de rede comecem a aparecer.
Antes que o console de rede amadurecesse para o nível em que está agora, os desenvolvedores geralmente precisavam recorrer ao uso de aplicativos sniffer (alguns ainda o fazem) para obter informações semelhantes.
O melhor desse console é a maneira como ele visualiza um dos principais comportamentos de consumo de bateria - o da comunicação contínua de pequenos pacotes. Como muitos de vocês sabem, o que tornará seu aplicativo um esgotador de bateria não são os cinco minutos de rede intensiva que ele faz, mas sim os longos períodos de rede curta e repetida, por exemplo, para manter a atividade, diagnósticos ou atualizações de status.
Uma vez que tal padrão é detectado, e a exibição visual de pacotes do console de rede facilita muito, pense imediatamente em lotes. Posso agrupar várias pequenas transmissões em uma única grande? O impacto dessa mudança na bateria está destinado a mover os aplicativos de um esgotador de bateria para uma categoria bem comportada!
Dica: Nunca carregue uma imagem na memória como está. Este é um acidente de falta de memória esperando para acontecer. Em vez disso, execute o carregamento reduzido ou, melhor ainda, use uma biblioteca de terceiros para gerenciar o dimensionamento para você.
Embora você raramente use essas informações, observe que o DDMS depende da pilha Android Debug Bridge (ADB) para transmitir dados de volta/do dispositivo. Se o DDMS não mostrar seu aplicativo ou travar no meio de uma sessão do DDMS, sua melhor aposta será abrir um console e digitar:
adb devicespara garantir que seu dispositivo esteja acessível e autorizado pelo ADB. Se não for o caso, em muitos casos, reiniciar o servidor ADB local deve resolver o problema:
adb kill-server adb devices # restarts the adb server and displays all detected devicesSe você ainda estiver com problemas e seu aplicativo estiver instalado em um dispositivo físico, tente desconectar todas as instâncias do emulador. Por quê? Como o DDMS se conecta a instâncias de dispositivo e emulador de dispositivos físicos, o padrão é o último.
Exemplo de uso do DDMS na vida real: um aplicativo é interrompido (não trava, apenas para). O usuário imediatamente corre para a estação de trabalho próxima, conecta-se ao USB e abre o DDMS na visualização de encadeamento para descobrir a pilha de encadeamentos » encadeamento com falha » rastreamento de pilha - no meu caso, devido ao impasse de sincronização que, uma vez detectado, foi facilmente resolvido por comutação.
Dica: se a memória RAM padrão alocada para seu aplicativo pelo Android não for suficiente, como pode acontecer para, por exemplo, aplicativos com uso intensivo de mídia, observe que você pode ganhar cerca de 15 a 20% de memória adicional na maioria dos dispositivos levantando o sinalizador de manifesto _ largeHeap : https://developer.android.com/guide/topics/manifest/application-element.html_
Emulação de estado do dispositivo no Android DDMS
Como regra, os aplicativos móveis não são construções lineares. Em vez disso, eles implantam estratégias de conscientização que permitem monitorar e reagir a mudanças no estado do dispositivo. Um aplicativo pode, por exemplo, ouvir chamadas ou mensagens de texto recebidas, realinhar seu estado de acordo com o estado da rede e rastrear e reagir a alterações na localização do dispositivo.
Um exemplo trivial para o último seria um aplicativo GPS. A maioria de nós não desenvolve esses aplicativos (infelizmente, o mercado não é grande o suficiente…), mas ainda assim, em muitos casos, implantamos lógica, que depende da localização, seja uma simples visualização de mapa da posição atual do usuário, rastreamento de rotas , ou uma exibição de dados sensível ao local.
Testar essas condições sensíveis ao estado é notoriamente complexo, às vezes mais do que escrever o código real. Se tiver um dispositivo físico com SIM pode, claro, emitir e receber chamadas e SMSs. Alterar o status de telefonia do seu dispositivo é muito mais difícil, mas ainda pode ser feito. As mudanças no local de teste podem ser mais complicadas, embora passear pela cidade com seu laptop seja uma opção…
Mas ainda assim, como lidaríamos com instâncias de emulador? Como podemos testá-los para essas mudanças?
DDMS para o resgate, mais uma vez. Um dos recursos mais fortes, mas muitas vezes esquecidos, do DDMS é sua capacidade de emitir eventos simulados (“spoof”) em uma instância de emulador em execução. O DDMS pode fazer uma chamada de um número específico para o emulador, enviar um SMS, alterar dados de status de telefonia e muito mais.
Ao chegar no emulador, todos esses eventos falsificados não serão mais distinguíveis dos eventos “reais”, ou seja, como se fossem recebidos pelos sensores de hardware subjacentes. Especificamente, todos os receptores relevantes do seu aplicativo serão ativados da mesma maneira que seriam ao receber uma chamada/mensagem SMS real.
A ativação do status e das ações de telefonia é bastante simples:
Para testar seu aplicativo para casos de baixa conectividade de rede (o que você deve em qualquer aplicativo centrado na rede), vá para a seção Status da Telefonia e defina os valores de velocidade e latência para os valores desejados. Eu costumo usar o valor GPRS para ambos como uma maneira eficaz de emular baixa conectividade, mas fique à vontade para definir seus próprios valores.
Para simular chamadas telefônicas ou SMS, vá para a seção Ação de Telefonia, defina o número de telefone de origem, adicione uma mensagem de texto, se necessário, e dispare. Essa ferramenta é especialmente eficaz quando você definiu uma rota de código dedicada para chamadas do exterior e deseja testá-la dentro do orçamento.
As coisas ficam mais interessantes quando se trata de zombar de um novo local.
Se tudo o que você deseja é definir um novo local para sua instância do emulador, escolha Manual, defina os valores de latitude/longitude desejados e clique em Enviar.
Mas e se, em vez de definir um local fixo, você quiser que seu aplicativo siga uma rota predefinida - digamos, examine seu comportamento enquanto o usuário está viajando de uma cidade para outra? Esse teste pode ter grande valor para qualquer aplicativo baseado em mapa, bem como outros aplicativos sensíveis à localização que definem sua janela de dados por localização do usuário. Aqui, você desejará ver que a mudança de localização em velocidades diferentes manterá a janela de dados exibida atualizada.
Para isso, utilizaremos um formato especial chamado KML, que foi desenvolvido especificamente para ser utilizado com o Google Earth, e que representa rotas, ou caminhos, como um conjunto de pontos conectados no espaço, que podem ser por dispositivos habilitados para GPS.
GPX é um formato de caminho alternativo suportado pelo DDMS. Para todos os propósitos práticos, esses dois devem ser considerados intercambiáveis quando usados para falsificação de localização móvel.
Vamos agora percorrer os estágios de configuração de uma rota simulada no emulador.
- Crie uma rota. De longe, a maneira mais simples seria usar a opção de direção do Google Maps definindo a origem e o destino apropriados.
Depois que a rota for exibida no mapa, vá para a linha de endereço e copie o URL
Com o URL na área de transferência, vá para o Visualizador GPS, cole-o na caixa de texto “Fornecer URL” e clique no botão Converter:
e clique para baixar o arquivo GPX resultante (com um nome um pouco confuso, por exemplo, 20170520030103-22192-data.gpx)
- Voltando ao DDMS Location Control, abra a guia GPX, clique em Load GPX e selecione o arquivo recém-baixado
- Foram realizadas! Agora você pode navegar entre os diferentes locais de rota clicando nos botões voltar e avançar ou clicando no botão Reproduzir para percorrer automaticamente a rota a uma velocidade definida.
Você não precisa criar sua própria rota. Muitas rotas para download de sites como o OpenStreetMap (consulte a seção 'Rastros GPS').
Por fim, observe que, diferentemente das versões mais antigas do DDMS, nas quais o carregamento do arquivo de rota era muito fácil, as versões mais recentes podem exigir algumas tentativas e erros ao carregar uma rota específica.
Por exemplo, parece que apenas o GPX 1.1 é suportado pelo DDMS. Novas versões do GPX podem exigir algum ajuste manual.
Além disso, o formato de waypoint GPX não é mais suportado. Em vez disso, use o formato GPX Track:
<trk> <name /> <cmt /> <trkseg> <trkpt lat="27.0512" lon="-80.4324"> <ele>0</ele> <time>2017-02-02T08:01:41Z</time> </trkpt> </trkseg> </trk>Depuração do Android: uma hora por semana faz a diferença!
Chega de teoria! Agora é hora de alguma prática. Sugiro, supondo que você seja um desenvolvedor Android, que a partir de seu próximo projeto dedique apenas uma hora por semana para obter introspecção sobre o desempenho do seu aplicativo via DDMS.
Você ficará surpreso com a quantidade de informações de qualidade (ou seja, informações que podem ser usadas para melhorar imediatamente o estado do seu aplicativo) que isso fornecerá!
O Android DDMS, como testemunhei várias vezes com desenvolvedores iniciantes, é uma ferramenta que pode melhorar muito os recursos de um desenvolvedor, desde que seja dominada e empregada adequadamente. A capacidade de um desenvolvedor Android de fornecer sistemas de alto nível aumentará literalmente um ou dois níveis assim que explorar todo o potencial do DDMS no desenvolvimento Android. Portanto, reservar algumas horas para fazer bom uso do DDMS parece um investimento inteligente, pois pode melhorar muito o desempenho e a eficiência do Android.
Seja um dos caras inteligentes. Use-o.
