The Android Developer Challenge is back! Submit your idea before December 2.

Depurar seu app

O Android Studio oferece um depurador que permite fazer o seguinte e muito mais:

  • Selecionar um dispositivo no qual depurar seu app.
  • Definir pontos de interrupção no seu código Java, Kotlin e C/C++.
  • Examinar as variáveis e avaliar as expressões no tempo de execução.

Esta página inclui instruções para operações básicas do depurador. Para ver outras documentações, consulte também os documentos de depuração IntelliJ IDEA (link em inglês).

Ativar depuração

Antes de começar a depuração, você precisa se preparar da seguinte maneira:

  • Instale o LLDB:

    Se seu projeto incluir o código C/C++, você precisará instalar o LLDB a partir do SDK Manager.

  • Ative a depuração no seu dispositivo:

    Se você estiver usando o emulador, isso estará ativado por padrão. No entanto, em um dispositivo conectado, você precisará ativar a depuração nas opções do desenvolvedor no dispositivo.

  • Execute uma variante de compilação depurável:

    Você precisa usar uma variante de compilação que inclua debuggable true na configuração. Normalmente, é possível selecionar a variante padrão "debug" incluída em todo projeto do Android Studio mesmo que ela não esteja visível no arquivo build.gradle. Porém, se você definir novos tipos de compilação que deveriam ser depuráveis, é necessário adicionar "debuggable true" ao tipo de compilação.

        android {
            buildTypes {
                customDebugType {
                    debuggable true
                    ...
                }
            }
        }
        

    Essa propriedade também se aplica a módulos com código C/C++. A propriedade jniDebuggable não é mais usada.

Observação: se seu app depender de um módulo de biblioteca que você também queira depurar, a biblioteca também precisará ser empacotada com debuggable true para que ela retenha os símbolos de depuração. Para garantir que as variantes depuráveis do seu projeto de app recebam a variante depurável de um módulo de biblioteca, publique versões não padrão da sua biblioteca.

Começar a depurar

É possível começar uma sessão de depuração da seguinte maneira:

  1. Defina alguns pontos de interrupção no código do app.
  2. Na barra de ferramentas, selecione um dispositivo para depurar seu aplicativo no menu suspenso do dispositivo de destino.

    Menu suspenso do dispositivo de destino.

    Se você não tiver nenhum dispositivo configurado, será necessário conectar um dispositivo via USB ou criar um AVD para usar o Android Emulator.

  3. Na barra de ferramentas, clique em Debug. .

    Se você vir uma caixa de diálogo perguntando se você quer "switch from Run to Debug", isso significa que seu app já está sendo executado no dispositivo e será reiniciado para começar a depuração. Se você preferir manter a mesma instância do app em execução, clique em Cancel Debug e anexe o depurador a um app em execução.

    Caso contrário, um APK será criado, assinado com uma chave de depuração, instalado no dispositivo selecionado e executado pelo Android Studio. Se você adicionar um código C e C++ ao seu projeto, o Android Studio também executará o depurador LLDB (link em inglês) na janela Debug para depurar seu código nativo.

  4. Se a janela Debug não estiver aberta, selecione View > Tool Windows > Debug ou clique em Debug na barra da janela de ferramentas e depois na guia Debugger, como mostrado na Figura 1.

    Figura 1. A janela Debugger, mostrando a linha de execução atual e a árvore de objetos de uma variável

Anexar o depurador a um app em execução

Se o app já estiver em execução no dispositivo, você poderá começar a depuração sem reiniciá-lo:

  1. Clique em Attach debugger to Android process .
  2. Na caixa de diálogo Choose Process, selecione o processo a que você quer conectar o depurador.

    Se estiver usando um emulador ou um dispositivo com acesso root, selecione Show all processes para ver todos os processos.

    No menu suspenso Debugger, é possível selecionar outro tipo de depuração. Por padrão, o Android Studio usa o tipo de depuração Auto para selecionar a melhor opção de depurador para você, com base na presença de código Java ou C/C++ no seu projeto.

  3. Clique em OK.

    A janela Debug será exibida.

Observação: o depurador e o coletor de lixo do Android Studio são relativamente integrados. A máquina virtual do Android garante que qualquer objeto que o depurador conheça não seja coletado até que o depurador seja desconectado. Isso pode resultar em um acúmulo de objetos ao longo do tempo enquanto o depurador estiver conectado. Por exemplo, se o depurador detectar uma linha de execução em funcionamento, o objeto Thread associado não será coletado até que o depurador seja desconectado, mesmo se a linha de execução for encerrada.

Alterar o tipo de depurador

Como as diferentes ferramentas do depurador são necessárias para depurar código Java/Kotlin e código C/C++, o depurador do Android Studio permite selecionar o tipo de depurador a ser usado. Por padrão, o Android Studio decide qual depurador usar com base em quais idiomas ele detecta no seu projeto com o tipo de depurador Auto. No entanto, é possível selecionar manualmente o depurador na configuração de depuração, clicando em Run > Edit Configurations ou na caixa de diálogo que aparece quando você clica em Run > Attach debugger to Android process.

Os tipos de depuração disponíveis incluem:

  • Auto: selecione esse tipo se quiser que o Android Studio escolha automaticamente a melhor opção para o código que você está depurando. Por exemplo, se seu projeto inclui código C ou C++, o Android Studio usa o tipo de depuração Dual automaticamente. Do contrário, o Android Studio usa o tipo de depuração Java.
  • Java: selecione esse tipo se quiser depurar apenas código em Java ou Kotlin. O depurador Java ignora qualquer ponto de interrupção ou controle definido no seu código nativo.
  • Native (disponível apenas para código C/C++): selecione esse tipo se quiser usar apenas o LLDB para depurar seu código. Ao usar esse tipo de depuração, a visualização da sessão do depurador Java não é disponibilizada. Por padrão, o LLDB inspeciona apenas seu código nativo e ignora os pontos de interrupção no seu código Java. Se também quiser depurar o código Java, use o tipo de depuração Auto ou Dual.

    Observação: a depuração nativa não funciona no Windows de 32 bits no Android Studio 3.0 e versões posteriores. Se você estiver usando um Windows de 32 bits e precisar depurar código nativo, use o Android Studio 2.3.

  • Dual (disponível apenas para código C/C++): selecione esse tipo para alternar entre depurar código Java e código nativo. O Android Studio conecta os depuradores Java e LLDB ao processo do seu app. Assim, é possível inspecionar os pontos de interrupção no código Java e no código nativo sem reiniciar o app ou alterar a configuração de depuração.

    Na Figura 2, observe as duas guias à direita do título da janela Debug. Como o app tem código Java e C++, uma guia é para depurar o código nativo e a outra para o código Java, conforme indicado por -java.

    Figura 2. Guia para depuração de código nativo e guia para depuração de código Java

Observação: se estiver depurando código nativo otimizado pelo compilador, você poderá receber a seguinte mensagem de aviso: This function was compiled with optimizations enabled. Some debugger features may not be available. Ao usar sinalizações de otimização, como -O, o compilador altera seu código compilado para torná-lo mais eficiente. Isso pode fazer com que o depurador passe informações inesperadas e incorretas, já que é difícil para o depurador mapear o código compilado otimizado de volta para o código-fonte original. Por esse motivo, desative as otimizações de compilador quando estiver depurando seu código nativo.

Usar o registro do sistema

O registro do sistema mostra mensagens do sistema enquanto você depura seu app. Essas mensagens incluem informações sobre os apps em execução no dispositivo. Se quiser usar o registro do sistema para depurar seu app, seu código precisa gravar mensagens de registro e imprimir o rastreamento de pilha para exceções enquanto seu app estiver na fase de desenvolvimento.

Gravar mensagens de registro no código

Para gravar mensagens de registro no seu código, use a classe Log. Mensagens de registro ajudam você a entender o fluxo de execução, coletando a saída de depuração do sistema enquanto você interage com seu app. Elas podem informar qual parte do seu app apresenta falhas. Para saber mais sobre registros, consulte Gravar e visualizar registros.

O exemplo a seguir mostra como adicionar mensagens de registro para determinar se há informações de estado anterior disponíveis quando sua atividade for iniciada:

Kotlin

    import android.util.Log
    ...
    private val TAG: String = MyActivity::class.java.simpleName
    ...
    class MyActivity : Activity() {
        ...
        override fun onCreate(savedInstanceState: Bundle?) {
            ...
            if (savedInstanceState != null) {
                Log.d(TAG, "onCreate() Restoring previous state")
                /* restore state */
            } else {
                Log.d(TAG, "onCreate() No saved state available")
                /* initialize app */
            }
        }
    }
    

Java

    import android.util.Log;
    ...
    public class MyActivity extends Activity {
        private static final String TAG = MyActivity.class.getSimpleName();
        ...
        @Override
        public void onCreate(Bundle savedInstanceState) {
           ...
           if (savedInstanceState != null) {
                Log.d(TAG, "onCreate() Restoring previous state");
                /* restore state */
            } else {
                Log.d(TAG, "onCreate() No saved state available");
                /* initialize app */
            }
        }
    }
    

Durante o desenvolvimento, seu código também pode identificar exceções e gravar o rastreamento de pilha no registro do sistema:

Kotlin

    fun someOtherMethod() {
        try {
            ...
        } catch (e : SomeException) {
            Log.d(TAG, "someOtherMethod()", e)
        }
    }
    

Java

    void someOtherMethod() {
        try {
            ...
        } catch (SomeException e) {
            Log.d(TAG, "someOtherMethod()", e);
        }
    }
    

Observação: remova as mensagens de registro de depuração e as chamadas de impressão de rastreamento de pilha do seu código quando estiver tudo pronto para publicar o app. Isso pode ser feito ao definir uma sinalização DEBUG e inserir mensagens de registro de depuração em declarações condicionais.

Ver o registro do sistema

É possível ver e filtrar mensagens de depuração e outras mensagens de sistema na janela Logcat. Por exemplo, é possível ver mensagens quando a coleta de lixo ocorre ou ver as mensagens adicionadas ao app com a classe Log.

Para usar o logcat, inicie a depuração e selecione a guia Logcat na barra de ferramentas inferior, conforme mostrado na Figura 3.

Figura 3. Janela do Logcat com configurações de filtro

Consulte Gravar e visualizar registros com o Logcat para ver descrições do logcat e as opções de filtragem dele.

Trabalhar com pontos de interrupção

O Android Studio é compatível com diversos tipos de pontos de interrupção que acionam diferentes ações de depuração. O tipo mais comum é um ponto de interrupção de linha que interrompe a execução do seu app quando ele chega a uma linha de código especificada. Durante a pausa, é possível examinar variáveis, avaliar expressões e continuar a execução linha por linha para determinar as causas de erros no ambiente de execução.

Para adicionar um ponto de interrupção de linha, faça o seguinte:

  1. Localize a linha de código em que você quer pausar a execução e clique na margem esquerda dessa linha ou posicione o cursor na linha e pressione Ctrl+F8 (em computadores Mac, pressione Command+F8).
  2. Se seu app já estiver em execução, não será preciso atualizá-lo para adicionar o ponto de interrupção. Basta clicar em Attach Debugger to Android Process . Caso contrário, clique em Debug para iniciar a depuração.

Figura 3. Um ponto vermelho é exibido ao lado da linha depois de definir um ponto de interrupção.

Quando a execução do seu código atinge o ponto de interrupção, o Android Studio pausa a execução do aplicativo. Depois disso, é possível usar as ferramentas na guia Debugger para identificar o estado do app:

  • Para examinar a árvore de objetos de uma variável, expanda-a na visualização Variables. Se a visualização Variables não estiver disponível, clique em Restore Variables View .

  • Para avaliar uma expressão no ponto de execução atual, clique em Evaluate Expression .

  • Para avançar para a próxima linha do código sem inserir um método, clique em Step Over .

  • Para avançar para a primeira linha dentro de uma chamada de método, clique em Step Into .

  • Para avançar para a próxima linha fora do método atual, clique em Step Out .

  • Para continuar executando o app normalmente, clique em Resume Program .

Se seu projeto usar código nativo, por padrão, o tipo de depuração Auto conecta o depurador Java e o LLDB ao seu aplicativo como dois processos separados, assim, você pode alternar entre inspecionar os pontos de interrupção Java e C/C++ sem reiniciar o aplicativo ou alterar as configurações.

Observação: para que o Android Studio detecte pontos de interrupção no seu código C ou C++, use um tipo de depuração compatível com o LLDB, como Auto, Native ou Dual. Altere o tipo de depuração usado pelo Android Studio editando sua configuração de depuração. Para saber mais sobre os diferentes tipos de depuração, leia a seção sobre como usar outros tipos de depuração.

Quando o Android Studio implanta seu app no dispositivo de destino, a janela Debug é aberta com uma guia ou com uma visualização de sessão de depuração para cada processo de depuração, conforme mostrado na Figura 4.

Figura 4. Como depurar código nativo com LLDB

  1. O Android Studio alterna para a guia <your-module> quando o depurador LLDB encontra um ponto de interrupção no seu código C/C++. Os painéis Frames, Variables e Watches também estão disponíveis e funcionam exatamente como funcionariam se você estivesse depurando código Java. Apesar de o painel Threads não estar disponível na visualização da sessão do LLDB, é possível acessar os processos do seu app com a lista suspensa no painel Frames. Saiba mais sobre esses painéis nas seções sobre como depurar frames de janela e inspecionar variáveis.

    Observação: ao inspecionar um ponto de interrupção no seu código nativo, o sistema Android suspende a máquina virtual que executa o bytecode Java do app. Isso significa que não é possível interagir com o depurador Java nem recuperar informações de estado da sessão de depuração Java ao inspecionar um ponto de interrupção no código nativo.

  2. O Android Studio alterna para a guia <your-module>java quando o depurador Java encontra um ponto de interrupção no código Java.
  3. Ao depurar com o LLDB, é possível usar o terminal do LLDB na visualização da sessão do LLDB para passar opções de linha de comando para o LLDB (link em inglês). Se quiser que o LLDB execute comandos específicos sempre que você iniciar a depuração do seu app, imediatamente antes ou depois de conectar o depurador ao processo do app, é possível adicionar esses comandos à configuração de depuração.

Enquanto você depura o código C/C++, também é possível definir tipos especiais de pontos de interrupção, chamados pontos de controle, que podem suspender o processo do seu app quando ele interage com um bloco de memória específico. Para saber mais, leia a seção sobre como adicionar pontos de controle.

Ver e configurar pontos de interrupção

Para ver todos os pontos de interrupção e definir as configurações deles, clique em View Breakpoints no lado esquerdo da janela Debug. A janela Breakpoints será exibida, conforme mostrado na Figura 5.

Figura 5. A janela Breakpoints lista todos os pontos de interrupção atuais e inclui as configurações de comportamento para cada um

A janela Breakpoints permite ativar ou desativar cada ponto de interrupção da lista à esquerda. Se um ponto de interrupção for desativado, o Android Studio não pausará seu app quando chegar a ele. Selecione um ponto de interrupção na lista para definir as configurações dele. É possível configurar um ponto de interrupção para ser desativado inicialmente e fazer com que o sistema o ative depois que outro ponto de interrupção for alcançado. Também é possível configurar se um ponto de interrupção precisa ser desativado depois de ser alcançado. Para definir um ponto de interrupção para qualquer exceção, selecione Exception Breakpoints na lista de pontos de interrupção.

Depurar frames de janela

Na janela Debugger, o painel Frames permite inspecionar o frame da pilha que fez com que o ponto de interrupção atual fosse alcançado. Assim, é possível navegar e examinar o frame da pilha e inspecionar a lista de linhas de execução no seu app Android. Para selecionar uma linha de execução, use a lista suspensa do seletor e veja o frame da pilha. Clicar nos elementos do frame abre a fonte no editor. Também é possível personalizar a apresentação da linha de execução e exportar o frame da pilha conforme discutido no Guia de frames de janela (link em inglês).

Inspecionar variáveis

Na janela Debugger, o painel Variables permite inspecionar variáveis quando o sistema interrompe seu app em um ponto de interrupção e você seleciona um frame no painel Frames. O painel Variables também permite avaliar expressões ad-hoc usando métodos e/ou variáveis estáticos disponíveis no frame selecionado.

O painel Watches oferece recursos semelhantes, exceto que as expressões adicionadas ao painel Watches persistem entre sessões de depuração. Adicione pontos de controle para variáveis e campos que você acesse com frequência ou que ofereçam estados úteis para a sessão de depuração atual. Os painéis Variables e Watches são exibidos conforme mostrado na Figura 6.

Para adicionar uma variável ou expressão à lista Watches, siga estas etapas:

  1. Inicie a depuração.
  2. No painel Watches, clique em Add .
  3. Na caixa de texto exibida, digite o nome da variável ou da expressão que você quer controlar e pressione Enter.

Para remover um item da lista Watches, selecione-o e clique em Remove .

Para reordenar os elementos na lista Watches, selecione um item e clique em Up ou Down .

Figura 6. Painéis Variables e Watches na janela Debugger

Adicione pontos de controle

Durante a depuração do código C/C++, é possível definir tipos especiais de pontos de interrupção chamados pontos de controle, que podem suspender o processo do app quando ele interage com um bloco de memória específico. Por exemplo: se você definir dois pontos para um bloco de memória e atribuir um ponto de controle, o uso de qualquer um desses pontos para acessar esse bloco de memória acionará o ponto de controle.

No Android Studio, é possível selecionar uma variável específica para criar um ponto de controle no ambiente de execução, mas o LLDB atribui o ponto de controle apenas para o bloco de memória que o sistema aloca para a variável, não para a variável em si. Isso é diferente de adicionar uma variável ao painel Watches, o que permite observar o valor de uma variável, mas não suspender o processo do app quando o sistema ler ou alterar o valor dele na memória.

Observação: quando o processo do app sai de uma função e o sistema desaloca da memória as variáveis locais, é necessário reatribuir todos os pontos de controle criados para essas variáveis.

Para definir um ponto de controle, é preciso atender aos seguintes requisitos:

  • Seu dispositivo físico ou emulador de destino usa uma CPU x86 ou x86_64. Se ele usar uma CPU ARM, será preciso alinhar o limite do endereço da variável na memória para 4 bytes, no caso de processadores de 32 bits, ou 8 bytes, no caso de processadores de 64 bits. Especifique __attribute__((aligned(num_bytes))) na desaceleração da variável para alinhar uma variável no seu código nativo, conforme mostrado abaixo:
        // For a 64-bit ARM processor
        int my_counter __attribute__((aligned(8)));
        
  • Você já alinhou três pontos de controle ou menos. O Android Studio aceita até quatro pontos de controle em dispositivos de destino de x86 ou x86_64. Outros dispositivos podem aceitar menos pontos de controle.

Se você atender aos requisitos acima, poderá adicionar um ponto de controle da seguinte maneira:

  1. Enquanto seu app estiver suspenso em um ponto de interrupção, acesse o painel Variables na visualização da sua sessão do LLDB.
  2. Clique com o botão direito do mouse em uma variável que ocupe o bloco de memória que você quer rastrear e selecione Add Watchpoint. Será exibida uma caixa de diálogo para configurar seu ponto de controle, conforme mostrado na Figura 7.

    Figura 7. Adição de um ponto de controle a uma variável na memória

  3. Configure seu ponto de controle com as seguintes opções:
    • Enabled: desmarque essa opção se quiser que o Android Studio ignore o ponto de controle por enquanto. O Android Studio ainda salvará seu ponto de controle para que seja possível acessá-lo posteriormente na sessão de depuração.
    • Suspend: por padrão, o sistema Android suspende o processo do seu app quando ele acessa um bloco de memória atribuído a um ponto de controle. Desmarque essa opção se não quiser que isso aconteça. Isso revela outras opções, que podem ser úteis para personalizar o comportamento do sistema quando ele interage com um ponto de controle: Log message to console e Remove [the watchpoint] when hit.
    • Access Type: selecione se seu app precisa acionar seu ponto de controle quando tentar ler ou gravar no bloco de memória que o sistema alocar para a variável. Para acionar seu ponto de controle em uma ação de leitura ou de gravação, selecione Any.
  4. Clique em Done.

Para ver todos os pontos de controle e definir as configurações, clique em View Breakpoints no lado esquerdo da janela Debug. Será exibida a caixa de diálogo Breakpoints, conforme mostrado na Figura 8.

Figura 8. A caixa de diálogo Breakpoints lista os pontos de controle atuais e inclui as configurações de comportamento de cada um

Depois de adicionar um ponto de controle, clique em Resume Program no lado esquerdo da janela Debug para retomar o processo do seu app. Por padrão, se o app tentar acessar um bloco de memória para o qual você atribuiu um ponto de controle, o sistema Android suspenderá o processo do app, e um ícone de ponto de controle será exibido ao lado da linha de código que seu app executou por último, conforme mostrado na Figura 9.

Figura 9. O Android Studio indica a linha de código executada pelo app imediatamente antes do acionamento de um ponto de controle

Veja e altere o formato de exibição dos valores de recursos

No modo de depuração, é possível ver os valores dos recursos e selecionar um formato de exibição diferente para variáveis no seu código Java. Com a guia Variables exibida e um frame selecionado, faça o seguinte:

  1. Na lista Variables, clique com o botão direito do mouse em qualquer lugar de uma linha de recurso para exibir a lista suspensa.
  2. Na lista suspensa, selecione View as e o formato que você quer usar.

    Os formatos disponíveis dependem do tipo de dado do recurso selecionado. Você poderá ver qualquer uma ou mais das seguintes opções:

    • Class: exibe a definição da classe.
    • toString: exibe o formato da string.
    • Object: exibe a definição de objeto (uma instância de uma classe).
    • Array: exibe em um formato de matriz.
    • Timestamp: exibe a data e a hora como aaaa-mm-dd hh:mm:ss.
    • Auto: o Android Studio escolhe o melhor formato com base no tipo de dado.
    • Binary: exibe um valor binário usando 0 e 1.
    • MeasureSpec: o valor passado do pai para o filho selecionado. Consulte MeasureSpec.
    • Hex: exibe como um valor hexadecimal.
    • Primitive: exibe como um valor numérico usando um tipo de dado primitivo.
    • Integer: exibe um valor numérico do tipo Integer.

Você pode criar um formato personalizado (renderizador de tipo de dado) da seguinte maneira:

  1. Clique no valor do recurso com o botão direito do mouse.
  2. Selecione View as.
  3. Selecione Create. A caixa de diálogo Java Data Type Renderers será exibida.
  4. Siga as instruções em Renderizadores de tipos de dados Java (link em inglês).