ANRs

Quando a linha de execução de interface de um app Android é bloqueada por muito tempo, o erro "O app não está respondendo" (ANR) é acionado. O Android vitals rastreia e informa métricas de ANR no Google Play Console para ajudar você a monitorar a estabilidade e a capacidade de resposta do app em vários dispositivos.

Métricas e limites do Android vitals

O Android vitals pode ajudar você a monitorar e melhorar a taxa de ANRs do seu app. O Android vitals mede várias taxas de ANRs:

  • Taxa de ANR:é a porcentagem de usuários ativos por dia que tiveram qualquer tipo de ANR.
  • Taxa de ANR percebido pelo usuário:é a porcentagem de usuários ativos por dia que perceberam pelo menos um ANR. Atualmente, apenas ANRs do tipo Input dispatching timed out são considerados percebidos pelo usuário.
  • Taxa de ANRs múltiplos: é a porcentagem de usuários ativos por dia que tiveram pelo menos dois ANRs.

Um usuário ativo por dia é um usuário único que usa seu app em um único dia em um único dispositivo, possivelmente em várias sessões. Se um usuário usar o app em mais de um dispositivo em um único dia, cada dispositivo vai contribuir para o número de usuários ativos nesse dia.

A taxa de ANR percebido pelo usuário é uma das principais métricas, ou seja, ela afeta a possibilidade de descoberta do app no Google Play. Isso é importante porque os ANRs que ela conta sempre ocorrem quando o usuário está engajado com o app, o que causa mais interrupções.

O Google Play definiu dois limites de mau comportamento nessa métrica:

  • Limite de mau comportamento geral: pelo menos 0,47% dos usuários ativos por dia percebem um ANR em todos os modelos de dispositivos.
  • Limite de mau comportamento por dispositivo:pelo menos 8% dos usuários ativos por dia percebem um ANR percebido pelo usuário em um único modelo de dispositivo.

Se o app exceder o limite de mau comportamento geral, ele provavelmente terá menos facilidade de descoberta em todos os dispositivos. Se o app excede o limite de mau comportamento por dispositivo em alguns dispositivos, ele provavelmente tem menos facilidade de descoberta nesses dispositivos, e um aviso pode ser mostrado na página de detalhes do app.

O Android vitals pode enviar alertas pelo Play Console quando o app está apresentando muitos ANRs.

Para informações sobre como o Google Play coleta dados do Android vitals, consulte a documentação do Play Console.

Detectar o problema

Se o app estiver em primeiro plano quando um ANR ocorrer, o sistema vai mostrar uma caixa de diálogo ao usuário, como na figura 1. A caixa de diálogo ANR dá ao usuário a oportunidade de forçar saída do app.

Caixa de diálogo ANR mostrada ao usuário.
Figura 1. Caixa de diálogo ANR mostrada ao usuário

ANRs são um problema porque fazem com que a linha de execução principal do app, que é responsável por atualizar a IU, não processe eventos de entrada ou não seja renderizada, causando frustração ao usuário. Para mais informações sobre a linha de execução principal do app, consulte Visão geral de processos e linhas de execução.

Um ANR é acionado para o app quando uma das seguintes condições ocorre:

  • Tempo de entrega de entradas esgotado: se o app não respondeu a um evento de entrada (como pressionamento de tecla ou toque na tela) em até cinco segundos.
  • Serviço executado: se um serviço declarado pelo app não consegue terminar a execução de Service.onCreate e Service.onStartCommand ou Service.onBind em alguns segundos.
  • Service.startForeground não chamado:se o app usa Context.startForegroundService para iniciar um novo serviço em primeiro plano, mas o serviço não chama startForeground dentro de cinco segundos.
  • Transmissão de intent:se uma BroadcastReceiver não termina de ser executada dentro de um período definido. Se o app tem alguma atividade em primeiro plano, esse tempo limite é de 10 segundos.
  • Interações do JobScheduler: se um JobService não retornar de JobService.onStartJob ou JobService.onStopJob em alguns segundos, ou se um job iniciado pelo usuário começar e seu app não chamar JobService.setNotification alguns segundos depois de JobService.onStartJob ser chamado. Em apps destinados ao Android 13 e versões anteriores, os ANRs são silenciosos e não são informados ao app. Para apps direcionados ao Android 14 e versões mais recentes, os ANRs são explícitos e informados ao app.

Além do Android vitals, você pode usar outras ferramentas para detectar ANRs em campo, mas as ferramentas de terceiros não podem reportar ANRs no Android 10 (nível da API 29) e versões anteriores.

Diagnosticar ANRs

Há alguns padrões comuns que precisam ser observados ao diagnosticar ANRs:

  • O app está fazendo operações lentas envolvendo E/S na linha de execução principal.
  • O app está fazendo um cálculo longo na linha de execução principal.
  • A linha de execução principal está fazendo uma chamada de vinculação síncrona para outro processo, e esse outro processo está demorando muito para retornar.
  • A linha de execução principal está bloqueada e esperando um bloco sincronizado para uma operação longa que está acontecendo em outra linha de execução.
  • A linha de execução principal está em um impasse com outra linha, seja em um processo ou em uma chamada de vinculação. A linha de execução principal não está apenas aguardando uma operação longa terminar, mas está em uma situação de impasse.

As técnicas a seguir podem ajudar a determinar a causa dos ANRs.

HealthStats

HealthStats fornece métricas sobre a integridade do app, coletando informações sobre tempo total de uso do usuário e do sistema, tempo de CPU, rede, estatísticas de rádio, tempo com a tela ativada e desativada e alarmes de ativação. Com esse elemento, é possível medir o uso geral de CPU e o consumo de bateria.

Depuração

Debug ajuda a inspecionar apps Android durante o desenvolvimento, fazendo uso de rastreamento e contagens de alocação para identificar instabilidade e pontos de atraso nos apps. Também é possível usar Debug para receber contadores relacionados à memória nativa e ao tempo de execução, além de métricas de memória que podem ajudar a identificar o consumo de memória por um processo específico.

ApplicationExitInfo

ApplicationExitInfo está disponível no Android 11 (nível 30 da API) e versões mais recentes e fornece informações sobre o motivo do encerramento do app. Os motivos incluem ANRs, pouca memória, falhas no app, uso excessivo da CPU, interrupções do usuário, interrupções do sistema e mudanças na permissão de execução.

Modo restrito

Usar StrictMode ajuda a encontrar operações acidentais de E/S na linha de execução principal durante o desenvolvimento do app. Você pode usar StrictMode no nível do aplicativo ou da atividade.

Ativar caixas de diálogo ANR em segundo plano

O Android mostra caixas de diálogo ANR para apps que levam muito tempo para processar a mensagem de transmissão apenas se você ativar Mostrar todos os ANRs nas Opções do desenvolvedor do dispositivo. Por esse motivo, as caixas de diálogo ANR em segundo plano nem sempre são mostradas para o usuário, mesmo quando o app está com problemas de desempenho.

Criar perfis de rastreamentos do sistema e da CPU

Use o CPU Profiler do Android Studio para gravar rastreamentos do sistema e atividades da CPU enquanto o jogo é executado. Inspecionar a linha de execução principal Activity com as linhas de execução de renderização, áudio e worker do mecanismo de jogo ajuda a identificar frames longos, carregamentos de recursos síncronos e contenção de linhas de execução antes que eles acionem um ANR.

Extrair um arquivo de rastreamento

O Android armazena informações de rastros quando passa por um ANR. Em versões mais antigas do Android, há um único arquivo /data/anr/traces.txt no dispositivo. Nas versões mais recentes do Android, há vários arquivos /data/anr/anr_*. Você pode acessar os rastros de ANR em um dispositivo ou emulador usando o Android Debug Bridge (adb) como raiz:

adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>

Você pode capturar um relatório de bug de um dispositivo físico usando a opção "Opções do desenvolvedor" no dispositivo ou o comando adb bugreport na máquina de desenvolvimento. Para mais informações, consulte Capturar e ler relatórios de bugs.

Corrigir os problemas

Depois de identificar o problema, você pode usar as dicas desta seção para corrigir problemas encontrados com frequência.

Código lento na linha de execução principal

Identifique os lugares no código em que a linha de execução principal do app está ocupada por mais de cinco segundos. Procure os casos de uso suspeitos no jogo e tente reproduzir o ANR.

Em jogos, as interrupções da linha de execução principal geralmente acontecem quando a descompactação síncrona de recursos, a compilação de sombreadores ou a inicialização pesada do estado do jogo são executadas na linha de execução principal Activity do Android (como em callbacks onCreate, onResume ou JNI invocados na linha de execução de interface). Mova a execução do loop de jogo, o processamento de recursos e a inicialização de cenas para linhas de execução dedicadas de mecanismo, renderização ou worker em segundo plano para que a linha de execução principal permaneça livre para processar eventos de entrada e de ciclo de vida.

E/S na linha de execução principal

A execução de operações de E/S na linha de execução principal é uma causa comum de operações lentas, o que pode causar ANRs.

Mova todas as leituras de pacotes de recursos, serializações de jogos salvos, acessos a SharedPreferences e solicitações de rede da linha de execução principal Activity para linhas de execução de worker em segundo plano. Assim, o armazenamento ou a latência de rede não podem bloquear o envio de entradas.

Impasses

Um impasse ocorre quando uma linha de execução entra em um estado de espera porque um recurso necessário é retido por outra linha, que também está aguardando um recurso retido pela primeira. Se a linha de execução principal do app estiver nessa situação, é provável que ANRs aconteçam.

Em jogos, deadlocks e contenção de bloqueio ocorrem com frequência entre a linha de execução principal Activity do Android (que processa callbacks de ciclo de vida, superfície ou entrada) e as linhas de execução nativas de renderização, lógica ou áudio em C ou C++. Evite esperas síncronas na linha de execução principal para bloqueios de mecanismo nativo e use uma ordem de bloqueio consistente ou filas de mensagens sem bloqueio ao se comunicar entre as linhas de execução JNI e do mecanismo.

Os impasses são um fenômeno bem estudado na ciência da computação e existem algoritmos de prevenção que você pode usar para os evitar.

Para mais informações, consulte Impasse e Algoritmos de prevenção de impasse na Wikipedia (em inglês).

Broadcast receivers lentos

Os apps podem responder a mensagens de transmissão, como ativar ou desativar o modo avião ou mudar o status de conectividade usando broadcast receivers. Um ANR ocorre quando um app demora muito para processar a mensagem de transmissão.

Um ANR ocorre nestes casos:

  • Após um período considerável, um broadcast receiver ainda não concluiu a execução do método onReceive.
  • Um broadcast receiver chamou goAsync e falhou ao chamar finish no objeto PendingResult.

O app só pode executar operações curtas no método onReceive de um BroadcastReceiver. No entanto, se o app exigir processamento mais complexo como resultado de uma mensagem de transmissão, adie a tarefa para uma linha de execução de worker em segundo plano se ela levar no máximo alguns segundos ou para WorkManager se ela levar mais tempo.

GameActivity

A biblioteca GameActivity reduziu os ANRs em estudos de caso de jogos e apps escritos em C ou C++. Se você substituir a atividade nativa existente por GameActivity, poderá reduzir o bloqueio de linhas de execução de interface e impedir que alguns ANRs ocorram.

Se você estiver criando seu jogo com o Unity, consulte Depurar ANRs para jogos do Unity, ANRs comuns de jogos do Unity e Simbolizar falhas do Android e o erro ANR para jogos do Unity.

Para mais informações sobre ANRs, consulte Manter o app responsivo. Para mais informações sobre linhas de execução, consulte Melhor performance usando linhas de execução.