1. Conhecimento básico de ANR
1.1. Causa da ocorrência
Resumindo em uma frase: ANR ocorrerá se você não conseguir concluir o que precisa dentro do prazo especificado.
1.2. Classificação ANR
Classificação da cena que aconteceu:
- O evento Input não foi processado por mais de 5 segundos.
- Tempo limite de processamento do serviço, 20s em primeiro plano, 200s em segundo plano
- Tempo limite de processamento do BroadcastReceiver, 10s em primeiro plano, 60s em segundo plano
- Tempo limite de execução do ContentProvider, relativamente raro
De acordo com os motivos pelos quais isso aconteceu:
- O thread principal possui operações demoradas, como layout complexo, operações de IO, etc.
- Bloqueado pelo par do Binder
- Bloco de bloqueio de sincronização de linha acolchoada
- O Binder está cheio, fazendo com que o thread principal não consiga se comunicar com o SystemServer
- Não é possível obter recursos do sistema (CPU/RAM/IO)
Do ponto de vista do processo:
- O problema está no processo atual:
o thread principal em si é demorado ou a fila de mensagens do thread principal tem operações demoradas,
o thread principal é bloqueado por outros threads filhos deste processo; - O problema está no processo remoto (geralmente chamada de binder ou soquete e outros métodos de comunicação)
2. Análise de log de ANR
2.1. Classificação de registros
Quando ocorre um problema de ANR, um relatório de bug geralmente será arquivado.
adb bugreprot xxx
O mais importante é que o bugreport gerado tenha o traço de anr. Se quiser retirá-lo separadamente, tudo bem.
adb pull /data/anr/traces.txt xxx
Um relatório de bug completo contém as seguintes informações, que são críticas para analisar problemas de ANR
Nome do registro |
efeito |
Obter comando |
registro do sistema |
Contém informações de ponto de tempo de ocorrência de ANR, informações de CPU antes da ocorrência de ANR e também contém um grande número de informações de saída de serviço do sistema |
adb logcat –b sistema |
principal.log |
Contém as informações geradas pelo próprio aplicativo antes que o ANR ocorra, que pode ser usado para analisar se o aplicativo está anormal; também contém as informações de saída do GC, que podem ser usadas para analisar a velocidade de reciclagem da memória e determinar se o sistema está em um estado de pouca memória ou fragmentação de memória. |
adb logcat –b principal |
evento.log |
Contém informações sobre o ciclo de vida do aplicativo geradas por AMS e WMS, que podem ser usadas para analisar a velocidade de criação de janelas e o status de transição de foco |
evento adb logcat –b |
kernel.log |
Incluindo informações impressas pelo kernel, processos de eliminação do LowMemoryKiller, fragmentação de memória ou memória insuficiente e exceções do driver mmc podem ser encontradas aqui. |
nenhum |
Então, o que você acha desses registros? Veja o caso um abaixo
2.2. Caso 1: Problema demorado de SP leva à aplicação de ANR
Geralmente, pesquise ANR primeiro para obter as informações mais intuitivas, como segue:
06-16 16: 16: 28.590 1853 2073 E ActivityManager: ANR em com.android.camera (com.android.camera/.Camera) 06-16 16: 16: 28.590 1853 2073 E ActivityManager: PID: 27661 06-16 16 :16:28.590 1853 2073 E ActivityManager: Motivo: tempo limite de envio de entrada expirou (com.android.camera/com.android.camera.Camera, aguardando para enviar evento não-chave porque a janela tocada não concluiu o processamento de certos eventos de entrada que foram entregue a ele há mais de 500,0 ms. Comprimento da fila de espera: 24. Idade do cabeçalho da fila de espera: 5511,1 ms.) 06-16 16:16:28.590 1853 2073 E ActivityManager: Carga: 16,25/29,48/38,33 06-16 16:16: 28.590 1853 2073 E ActivityManager: uso da CPU de 0 ms a 8.058 ms depois: 06-16 16:16: 28.590 1853 2073 E ActivityManager: 58% 291/mediaserver: 51% usuário + 6,7% kernel/falhas: 2457 menor 4 maior 06-16 16: 16: 28.590 1853 2073 E ActivityManager: 27% 317 / mm-qcamera-daemon: 21% usuário + 5,8% kernel / falhas: 15965 menores 06-16 16: 16: 28.590 1853 2073 E ActivityManager: 0,4 % 288/debuggerd: 0% usuário + 0,3% kernel/falhas: 21615 secundário 87 principal 06-16 16:16:28.590 1853 2073 E ActivityManager: 17% 27661/com.android.camera: 10% usuário + 6,8% kernel/falhas : 2412 secundário 34 principal 06-16 16:16:28.590 1853 2073 E ActivityManager: 16% 1853/system_server: 10% usuário + 6,4% kernel/falhas: 1754 secundário 87 principal 06-16 16:16:28.590 1853 2073 E 06-16 16:16:28.590 1853 2073 E ActivityManager: 10% 539/sensors.qcom: 7,8% usuário + 2,6% kernel/ faltas: 16 menores ActivityManager : 4,4% 277/surfaceflinger: 1,8% usuário + 2,6% kernel/falhas: 14 menores 06-16 16:16:28.590 1853 2073 E ActivityManager: 4% 203/mmcqd/0: 0% usuário + 4% kernel 2073 E ActivityManager: 2,6% 3510/com. android.phone: 1,9% usuário + 0,6% kernel/falhas: 1148 menores 8 principais 06-16 16:16:28.590 1853 2073 E ActivityManager: 2,1% 2902/com.android.systemui: 1,6% usuário + 0,4% kernel/falhas : 1272 menor 32 maior 06-16 16:16:28.590 1853 2073 E ActivityManager: 1,6% 3110/com.miui.whetstone: 1,6% usuário + 0% kernel/falhas: 2614 menor 22 maior 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,8% 99/kswapd0: 0% usuário + 0,8% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 1,4% 217/jbd2/mmcblk0p25: 0% usuário + 1,4% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 1,4% 223/logd: 0,7% usuário + 0,7% kernel/falhas: 4 menores 06-16 16:16:28.590 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,6% 29336/kworker/u:7: 0% usuário + 0,6% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,9% 12808/kworker/0:1: 0% usuário + 0,9% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,8% 35/kworker/u:2: 0% usuário + 0,8% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0% 3222/com.miui .sysbase: 0% usuário + 0% kernel/falhas: 1314 secundário 12 principal 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,8% 3446/com.android.nfc: 0,4% usuário + 0,3% kernel/falhas: 1223 menor 9 maior 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,7% 10866/kworker/u:1: 0% usuário + 0,7% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,6% 642 /mdss_fb0: 0% usuário + 0,6% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,4% 6/kworker/u:0: 0% usuário + 0,4% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,4% 22924/kworker/u:6: 0% usuário + 0,4% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,3% 4421/mpdecision: 0% usuário + 0,3% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,2% 276/servicemanager: 0,1% usuário + 0,1 % kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,2% 289/rild: 0,2% usuário + 0% kernel / falhas: 20 menores 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,1% 4161/ mcd: 0% usuário + 0% kernel / falhas: 9 menores 1 principais 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,1% 3/ksoftirqd/0: 0% usuário + 0,1% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,1% 5/kworker/0:0H: 0% usuário + 0,1% de núcleo 06-16 16:16 :28.590 1853 2073 E ActivityManager: 0,1% 7/kworker/u:0H: 0% usuário + 0,1% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0% 215/flush-179:0: 0% usuário + 0% de núcleo 1853 2073 E ActivityManager: 0,1% 321/displayfeature: 0,1 % usuário + 0% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,1% 368/irq/33-cpubw_hw: 0% usuário + 0,1% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,1 % 403/qmuxd: 0% usuário + 0,1% kernel/falhas: 60 menores 06-16 16:16:28.590 1853 2073 E ActivityManager: 0% 3491/com.xiaomi.finddevice: 0% usuário + 0% kernel/falhas: 706 menor 16/06 16:16:28.590 1853 2073 E ActivityManager: 0,1% 29330/ksoftirqd/1: 0% usuário + 0,1% kernel 06-16 16:16:28.590 1853 2073 E ActivityManager: 96% TOTAL: 56% usuário + 29% de kernel + 6,3% de iowait + 4,1% de softirq
Ao encontrar um problema de ANR, o rastreamento à nossa frente é a primeira cena do crime? Se muitas informações forem emitidas quando ocorrer um ANR, e os recursos de CPU e E/S forem relativamente escassos naquele momento, então o ponto no tempo de essa saída de log pode ser atrasada . Pode levar de 10 a 20 segundos , então às vezes precisamos estar mais vigilantes. Vamos dar um exemplo e explicá-lo linha por linha:
06-16 16: 16: 28.590 1853 2073 E ActivityManager: ANR em com.android.camera (com.android.camera/.Camera) .
Esta linha aprende que o horário em que ocorreu o ANR é 16/06 16:16:28.590, e o processo que ocorreu é com.android.camera, especificamente em com.android.camera/.Camera, onde 1853 é o pid do servidor do sistema e 2073 é o thread do ActivityManager. O pid do ActivityManager é um thread do sistema. Na verdade, há informações correspondentes no log de eventos , procure a palavra-chave am_anr
06-16 16: 16: 20.536 1853 2073 I am_anr: [0,27661, com.android.camera, 952745541, tempo limite de envio de entrada expirou (com.android.camera/com.android.camera.Camera, aguardando para enviar não- evento chave porque a janela tocada não concluiu o processamento de determinados eventos de entrada que foram entregues a ela há mais de 500,0 ms. Comprimento da fila de espera: 24. Idade do cabeçalho da fila de espera: 5511,1 ms.)]
A partir disso, você também pode determinar o ponto no tempo, o tipo, o pid do processo, o nome do processo, etc. do ANR. Continue para a próxima linha.
06-16 16:16:28.590 1853 2073 E ActivityManager: PID: 27661
Esta linha aprende que o pid do processo ANR é 27661. Em casos especiais, se o pid for 0, significa que o processo foi eliminado pelo LowMemoryKiller ou travou antes da ocorrência do ANR. Nesse caso, a transmissão do sistema não pode ser recebida. Ou uma mensagem chave, para que ocorra ANR.
06-16 16: 16: 28.590 1853 2073 E ActivityManager: Motivo: o tempo limite do despacho de entrada expirou (com.android.camera/com.android.camera.Camera, aguardando o envio de um evento não-chave porque a janela tocada não concluiu o processamento de determinados eventos de entrada que foram entregues a ele há mais de 500,0 ms. Comprimento da fila de espera: 24. Idade do cabeçalho da fila de espera: 5511,1 ms.)
Esta linha aprende que o motivo do ANR é que o tempo limite do despacho de entrada expirou
06-16 16:16:28.590 1853 2073 E ActivityManager: Carga: 16,25 / 29,48 / 38,33
Esta linha conhece a carga da CPU . No sistema operacional Linux, você também pode obter a carga por um período de tempo inserindo o tempo de atividade.
tempo de atividade 20:09:54 até 71 dias, 10:48, 1 usuário, média de carga: 0,99, 0,78, 0,86
Então, o que significa carga? Os três números após Carga significam a carga média do sistema em 1 minuto, 5 minutos e 15 minutos, respectivamente . Quando a CPU está completamente ociosa, a carga média é 0; quando a carga de trabalho da CPU está saturada, a carga média é 1. A carga pode ser usada para determinar se a carga do sistema está muito pesada. Há uma metáfora vívida: imagine uma CPU como uma ponte. Há apenas uma faixa na ponte. Todos os veículos devem passar por essa faixa. A carga do sistema é 0, o que significa que não há um único carro na ponte. O sistema a carga é 0,5, o que significa que há carros em metade dos trechos da ponte, e a carga do sistema é 1,0, o que significa que há carros em todos os trechos da ponte, o que significa que a ponte está "cheia", e a carga do sistema é 2,0, o que significa que há muitos veículos e a ponte está cheia (100%) e há o dobro de veículos esperando para entrar na ponte. A capacidade de tráfego da ponte é a carga máxima de trabalho da CPU; os veículos na ponte são processos aguardando processamento pela CPU.
A regra é esta:
quando a carga do sistema é consistentemente superior a 0,7, você deve começar a investigar qual é o problema e evitar que a situação piore.
Quando a carga do sistema continuar maior que 1,0, você deverá encontrar uma solução para diminuir esse valor.
Quando a carga do sistema atinge 5.0, indica que seu sistema tem um problema sério.
Se a carga do sistema em apenas um minuto for superior a 1,0 e os outros dois períodos de tempo forem inferiores a 1,0, isso indica que é apenas um fenômeno temporário e que o problema não é sério.
Se a carga média do sistema for superior a 1,0 em 15 minutos (após ajustar o número de núcleos da CPU), isso indica que o problema persiste e não é um fenômeno temporário. Portanto, você deve observar principalmente a “carga do sistema de 15 minutos” como um indicador da operação normal do computador.
Nossos telefones celulares atuais têm uma arquitetura de CPU multi-core. Existem muitos oito núcleos, o que significa que o poder de processamento da CPU é multiplicado por 8. O tempo de execução de cada núcleo pode ser obtido no seguinte arquivo, /sys/devices/system / Leitura de cpu/cpu%d/cpufreq/stats/time_in_state, %d representa o núcleo da CPU. O arquivo registra o tempo de execução da CPU em cada frequência desde a inicialização até a leitura do arquivo, unidade: 10 mS.
Use adb shell cat /sys/devices/system/cpu/cpu1/cpufreq/stats/time_in_state para verificar a frequência
Use adb shell cat /sys/devices/system/cpu/cpu1/cpufreq/stats/time_in_state para visualizar o tempo de frequência 652800 1813593 1036800 46484 1401600 521974 1689600 2956667 1843200 83065 1958400 5 3516 2016000 251693
Para obter mais detalhes sobre a carga, consulte Compreendendo a carga do sistema Linux , mas não entre em muitos detalhes.
16/06 16:16:28.590 1853 2073 E ActivityManager: uso da CPU de 0 ms a 8058 ms depois: 16/06 16:16: 28.590 1853 2073 E ActivityManager: 58% 291/mediaserver: 51% usuário + 6,7% kernel/falhas: 2457 menor 4 maior 06-16 16:16:28.590 1853 2073 E ActivityManager: 27% 317/mm-qcamera-daemon: 21% usuário + 5,8% kernel/falhas: 15965 menor 06-16 16:16:28.590 1853 2073 E ActivityManager: 0,4% 288/debuggerd: 0% usuário + 0,3% kernel/falhas: 21615 menor 87 principal 06-16 16:16:28.590 1853 2073 E ActivityManager: 17% 27661/com.android.camera: 10% usuário + 6,8 % kernel / falhas: 2412 menores 34 principais .... 06-16 16:16:28.590 1853 2073 E ActivityManager: 96% TOTAL: 56% usuário + 29% kernel + 6,3% iowait + 4,1% softirq .....
Neste log, você pode obter o uso da CPU dos principais processos quando ocorre ANR. O usuário representa o espaço do usuário e o kernel representa o espaço do kernel. Geralmente, as regras a seguir se aplicam.
- Se a taxa de ocupação da CPU kswapd0 for alta, o sistema geral funcionará lentamente, causando vários ANRs. Encaminhe o problema para "Otimização de Memória" e peça para otimizá-lo.
- O alto uso da CPU logada também pode causar congelamentos do sistema e ANR, porque a operação de cada processo para gerar LOG é bloqueada e executada de forma extremamente lenta.
- Vold ocupa muita CPU e pode causar congelamentos do sistema e ANR. Investigue primeiro se você é responsável pelo armazenamento.
- O uso da CPU do qcom.sensor é muito alto, o que pode causar atraso. Investigue o sistema.
- O uso da CPU do próprio aplicativo é alto e há uma grande probabilidade de problemas no aplicativo
- O uso da CPU do sistema não é alto, mas o thread principal está aguardando um bloqueio e há uma grande probabilidade de problemas no aplicativo.
- A aplicação está no estado D e ocorre ANR. Se a última operação for refrigerar, a aplicação é congelada, o que normalmente é causado pela otimização do consumo de energia.
Ok, do log acima obtivemos as informações básicas do ANR. Para descobrir onde está o bloqueio, precisamos contar com o arquivo de rastreamento. Geralmente no diretório anr. Pesquise a pilha do thread principal neste arquivo de rastreamento, da seguinte forma:
----- pid 27661 em 16/06/2017 16:16:20 ----- Linha cmd: com.android.camera "main" prio=5 tid=1 Esperando | group="principal" sCount=1 dsCount=0 obj=0x75a4b5c8 self=0xb4cf6500 | sysTid=27661 nice=-10 cgrp=padrão sched=0/0 handle=0xb6f6cb34 | estado=S schedstat=( 11242036155 8689191757 38520 ) utm=895 stm=229 núcleo=0 HZ=100 | pilha=0xbe4ea000-0xbe4ec000 stackSize=8 MB | mantidos mutexes= em java.lang.Object.wait!(Método nativo) - aguardando <0x09e6a059> (um java.lang.Object) em java.lang.Thread.parkFor$(Thread.java:1220) - bloqueado <0x09e6a059 > (um java.lang.Object) em sun.misc.Unsafe.park(Unsafe.java:299) em java.util.concurrent.locks.LockSupport.park(LockSupport.java: em java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:810) em java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptably(AbstractQueuedSynchronizer.java:970) em java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSha vermelhoInterruptamente (AbstractQueuedSynchronizer.java:1278) em java.util.concurrent.CountDownLatch.await(CountDownLatch.java:203) em android.app.SharedPreferencesImpl$EditorImpl$1.run(SharedPreferencesImpl.java:366) em android.app.QueuedWork.waitToFinish (QueuedWork.java:88) em android.app.ActivityThread.handleStopActivity(ActivityThread.java:3605) em android.app.ActivityThread.access$1300(ActivityThread.java:153) em android.app.ActivityThread$H.handleMessage(ActivityThread.java:1399) em android.os.Handler.dispatchMessage(Handler.java:102) em android.os.Looper.loop(Looper.java:154) em android. app.ActivityThread.main(ActivityThread.java:5528) em java.lang.reflect.Method.invoke!(Método nativo) em com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:740) em com .android.internal.os.ZygoteInit.main(ZygoteInit.java:630)
Explique o significado de alguns campos
Campo |
significado |
tempo=1 |
Número do tópico |
sysTid=27661 |
O número do thread e o número do processo do thread principal são iguais |
Esperando |
Estado do thread, onde state também é o estado do thread, se state=D significa que a camada inferior está bloqueada. |
legal |
Quanto menor o valor agradável, maior será a prioridade. Por ser o thread principal, nice=-10 aqui, você pode ver que a prioridade é muito alta. |
schedstat |
Os três números entre colchetes são os tempos de execução, execução e troca em ordem. Tempo de execução: tempo de execução da CPU, unidade ns. Tempo executável: tempo de espera da fila RQ, em ns. Tempos de troca: o número de trocas de agendamento de CPU |
hum |
No momento em que o thread é executado no modo de usuário, a unidade é instantânea |
stm |
No momento em que o thread é executado no modo kernel, a unidade é instantânea |
contagem |
O número de vezes que este tópico foi suspenso |
dsCount |
O número de vezes que um thread foi suspenso pelo depurador. Quando um processo é depurado, sCount será redefinido para 0. Após a depuração, sCount aumentará dependendo se foi suspenso normalmente, mas dsCount não será redefinido para 0, então dsCount também pode ser usado. Usado para determinar se este thread foi depurado |
auto |
O endereço do próprio thread |
Vamos falar sobre o status do tópico
estado |
valor |
ilustrar |
THREAD_ZOMBIE |
0 |
TERMINADO |
THREAD_RUNNING |
1 |
RUNNABLE ou em execução agora |
THREAD_TIMED_WAIT |
2 |
TIMED_WAITING em Object.wait() |
THREAD_MONITOR |
3 |
BLOQUEADO em um monitor |
THREAD_INITIALIZING |
5 |
alocado ainda não está em execução |
THREAD_STARTING |
6 |
começou ainda não está na lista de tópicos |
THREAD_NATIVE |
7 |
off em um método nativo JNI |
THREAD_VMWAIT |
8 |
aguardando um recurso VM |
THREAD_SUSPENDED |
9 |
suspenso geralmente pelo GC ou depurador |
Então, como resolver este problema?Através da introdução básica acima e do arquivo de rastreamento, sabemos que o ponto bloqueado é
em java.util.concurrent.CountDownLatch.await(CountDownLatch.java:203) em android.app.SharedPreferencesImpl$EditorImpl$1.run(SharedPreferencesImpl.java:366) em android.app.QueuedWork.waitToFinish(QueuedWork.java:88) em android.app.ActivityThread.handleStopActivity(ActivityThread.java:3605) em android.app.ActivityThread.access$1300(ActivityThread.java:153)
Vejamos primeiro QueuedWork.waitToFinish
77 /** 78 * Termina ou aguarda a conclusão das operações assíncronas. 79 * (por exemplo, SharedPreferences$Editor#startCommit escreve) 80 * 81 * É chamado a partir do onPause() da classe base da Activity, após 82 * OnReceive do BroadcastReceiver, após o tratamento do comando Service, 83 * etc. (para que o trabalho assíncrono nunca seja perdido) 84 */ 85 public static void waitToFinish() { 86 Executável toFinish; //等待所有等待完成的任务完成 87 while ((toFinish = sPendingWorkFinishers.poll()) != null) { 88 toFinish.run(); 89} 90}
QueuedWork.waitToFinish será chamado após onPause de Activity ou onReceive de BroadcastReceiver para garantir que a execução da tarefa assíncrona seja concluída. Em waitToFinish, itere todas as tarefas aguardando para serem concluídas em sPendingWorkFinishers e aguarde sua conclusão. Vejamos SharedPreferencesImpl.apply.Este método colocará tarefas aguardando para serem gravadas no sistema de arquivos na fila de conclusão de espera do QueuedWork.
361 public void apply() { 362 final MemoryCommitResult mcr = commitToMemory(); 363 final Runnable awaitCommit = new Runnable() { 364 public void run() { 365 try { 366 mcr.writeedToDiskLatch.await(); 367 } catch (InterruptedException ignorado) { 368 } 369 } 370 }; 371 //Coloque tarefas aguardando para serem gravadas no sistema de arquivos na fila de espera do QueuedWork 372 QueuedWork.add(awaitCommit); 373 ... ... ... ... ... ... 388 }
Embora o próprio método apply possa retornar rapidamente, quando o onPause da Activity for chamado, ele aguardará a conclusão da tarefa de gravação no sistema de arquivos. Em outras palavras, embora o próprio apply não bloqueie o thread de chamada, ele transferirá o tempo de espera para o thread principal. Portanto, se a tarefa de gravação for executada lentamente e a operação sp de atividade, serviço e transmissão não for concluída no final do ciclo de vida, o thread principal será bloqueado e causará ANR. Neste ponto da análise, é óbvio que se trata de um problema de sistema e o App é impotente. Felizmente, esse problema foi amenizado nos telefones Xiaomi e a solução não será divulgada. De modo geral, as regras para observar vestígios são as seguintes:
- Quando ocorre um ANR, o processo correspondente não pode ser encontrado no rastreamento. Verifique se o Android Runtime está Desligado devido à falha do aplicativo. Se for Desligado, verifique o motivo do Desligamento neste momento.
- Ocorre um ANR em um aplicativo. Se o thread principal estiver executando getContentProvider, ele estará solicitando o ContentProvider de outro aplicativo. Neste momento, verifique o processo host do ContentProvider de destino para ver o que ele está fazendo.
- Se o thread principal executar operações de banco de dados ou solicitações de rede, deverá haver um problema com o próprio aplicativo.
- Se o thread principal aguardar bloqueios mantidos por outros threads e o thread de destino executar operações de banco de dados ou solicitações de rede, então há um problema com o próprio aplicativo.
Aqui começamos apenas com um caso para nos familiarizarmos com o processo básico de análise ANR. Vamos resumir a rotina acima aqui:
- Pegue o relatório de bug, pesquise ANR e verifique a hora e o processo de ocorrência
- Encontre o rastreamento do thread principal de acordo com o processo e encontre o local bloqueado
- Análise e solução com base no código-fonte.Claro
que através dessas duas etapas podemos localizar a causa do ANR, o que mostra que temos relativa sorte, mas na maioria das vezes não é assim.
Acima, analisamos um ANR causado por um problema no sistema. Aqui você pode pensar que meu aplicativo não funcionou, mas ocorreu um ANR. No futuro, posso culpar diretamente o sistema. Não, o problema específico ainda precisa ser analisado em detalhes., para duvidar do sistema, precisamos de evidências. De onde vem a evidência, ou do Log. Continue para a terceira seção, o plano de análise demorado do sistema.
3. Plano de análise demorado do sistema
O sistema realizou algumas operações de análise demoradas. Em alguns fabricantes de telefones celulares, existem outras melhorias no Log. Aqui estão algumas das mais comuns.
3.1、fichário_amostra
- A. Descrição da função: Monitore a situação demorada da transação do fichário do thread principal de cada processo. Quando o limite é excedido, as informações de chamada de destino correspondentes são emitidas. Ele é ativado em 1000 ms por padrão.
- B.log格式: 52004 binder_sample (descritor|3),(method_num|1|5),(time|1|3),(blocking_package|3),(sample_percent|1|6)
- Exemplo C.log:
2754 2754 I binder_sample: [android.app.IActivityManager,35,2900,android.process.media,5]
A partir do log acima, pode-se concluir que
1. Thread principal 2754;
2. Execute a interface android.app.IActivityManager
- O código do método correspondente =35 (ou seja, STOP_SERVICE_TRANSACTION),
- O tempo gasto é de 2900ms.
- O pacote onde este bloco está localizado é android.process.media, e o último parâmetro é a proporção da amostra (não tem muito valor)
3.2、dvm_lock_sample
- A. Descrição da função: Quando o tempo bloqueado por um thread aguardando bloqueio excede o limite, o status do bloqueio atual é exibido;
- B.log格式: 20003 dvm_lock_sample (process|3),(main|1|5),(thread|3),(time|1|3),(file|3),(line|1|5),( arquivo_proprietário|3),(linha_proprietária|1|5),(porcentagem_de_amostra|1|6)
- Exemplo C.log:
dvm_lock_sample: [system_server,1,Binder_9,1500,ActivityManagerService.java,6403,-,1448,0]
Isso significa que system_server: Binder_9, executado na linha 6403 de ActivityManagerService.java, estava aguardando o bloqueio do AMS, e o bloqueio é mantido pela linha 1448 do mesmo arquivo, fazendo com que o encadeamento Binder_9 seja bloqueado por 1500ms.
3.3、 Fichário sem pasta
- A. Descrição da função: Quando o conjunto de threads de processos como system_server é usado e não há threads ociosos, a comunicação do binder está em estado de fome.Se o estado de fome exceder um certo limite, as informações serão exibidas;
- B. Parâmetros de controle de nuvem: persist.sys.binder.starvation (valor padrão 16ms)
- Exemplo C.log:
1232 1232 "Conjunto de encadeamentos do binder (16 encadeamentos) com fome por 100 ms"
- Análise D.log: O conjunto de threads do processo system_server fica cheio por até 100 ms.
Geralmente, depois de obter essas informações, elas podem nos ajudar a determinar se a causa do problema é o sistema ou o aplicativo. Veja o caso 2 abaixo:
3.4. Caso 2: Crazy Binder Call leva ao ANR do aplicativo
Pesquisar ANR em
08-28 18:54:00.110 1000 1825 1848 E ActivityManager: ANR em com.jeejen.family (com.jeejen.family/com.jeejen.home.launcher.ShoppingActivity) 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: PID: 20576 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: Motivo: tempo limite de despacho de entrada expirou (com.jeejen.family/com.jeejen.home.launcher.WelcomeActivity, aguardando para enviar evento não-chave porque a janela tocada não concluiu o processamento de determinados eventos de entrada que foram entregues a ela há mais de 500,0 ms. Comprimento da fila de espera: 2. Idade do cabeçalho da fila de espera: 10064,4 ms.) 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: Pai : com.jeejen.family/com.jeejen.home.launcher.WelcomeActivity 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: Carga: 1,25 / 1,1 / 1,37 28/08 18:54:00.110 1000 1825 1848 E ActivityManager: uso da CPU de 5166ms a 0ms atrás (28/08/2018 18:53:51.270 a 28/08/2018 18:53:56.436): 28/08 18 : 54:00.110 1000 1825 1848 E ActivityManager: 7,7% 1825/system_server: 5,6% usuário + 2,1% kernel/falhas: 1329 minor 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 3,6% 20683/com.jeeje n.família :pushcenter_pushservice: 3% usuário + 0,5% kernel / falhas: 542 menores 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 2,7% 4114/cnss_diag: 1,9% usuário + 0,7% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 2,1% 422/kworker/u16:7: 0% usuário + 2,1% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 1,9% 20830/com.jeejen.family:store: 1,3 % usuário + 0,5% kernel/falhas: 199 menores 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 1,7% 20608/com.jeejen.family:pushcenter: 1,1% usuário + 0,5% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 1,5% 72 5 /[email protected]: 0,7% usuário + 0,7% kernel / falhas: 1 menor 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,9% 3538/com.android.systemui: 0,7% usuário + 0,1% kernel / falhas: 11 menores 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,5% 241/crtc_commit:111: 0% usuário + 0,5% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,5% 419/kworker/u16:4: 0% usuário + 0,5% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,5% 786/surfaceflinger: 0,5% usuário + 0% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,3% 185/IPCRTR_dsps_sme: 0% usuário + 0,3% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,3% 730/ android.hard ware.wifi @ 1.0-service: 0,1% usuário + 0,1% kernel / falhas: 28 menores 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,3% 820/dsps_IPCRTR: 0% usuário + 0,3% kernel 08-28 18:54 :00.110 1000 1825 1848 E ActivityManager: 0,3% 1147/msm_irqbalance: 0,1% usuário + 0,1% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,3% 4113/sugov:0: 0% usuário + 0. 3% de núcleo 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 10/rcuop/0: 0% usuário + 0,1% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 18/ksoftirqd/1 : 0% usuário + 0,1% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0% 34/ksoftirqd/3: 0% usuário + 0% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0% 53/rcuop/5 : 0% usuário + 0% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0% 61/rcuop/6: 0% usuário + 0% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager : 0,1% 242/crtc_event:111: 0% usuário + 0,1% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 538/ueventd: 0,1% usuário + 0% kernel 08-28 18:54: 00.110 1000 1825 1848 E ActivityManager: 0,1% 577/jbd2/sda22-8: 0% usuário + 0,1% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 591/logd: 0,1% usuário + 0% núcleo 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 719/[email protected]: 0,1% usuário + 0% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager : 0,1% 928/motor térmico: 0% usuário + 0,1% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 3490/cds_mc_thread: 0% usuário + 0,1% kernel 08-28 18:54: 00.110 1000 1825 1848 E ActivityManager: 0,1% 3491/cds_ol_rx_threa: 0% usuário + 0,1% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 3680/com.android.phone: 0% usuário + 0,1% kernel/falhas: 16 menores 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 4248/com.miui.daemon: 0,1% usuário + 0% kernel/falhas: 4 menores 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 4488/com.miui.powerkeeper: 0,1% usuário + 0% kernel / falhas: 10 menores 08-28 18:54:00.110 1000 1825 1848 E ActivityManager : 0,1% 5545/com.lbe.security.miui: 0% usuário + 0,1% kernel/falhas: 6 menores 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 6490/kworker/u17:2: 0% usuário + 0,1% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 7535/kworker/u16:15: 0% usuário + 0,1% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager : 0% 7723/kworker/3:5: 0% usuário + 0% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 15111/kworker/1:0: 0% usuário + 0,1% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 15138/kworker/3:0: 0% usuário + 0,1% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0% 19857/kworker /0:3: 0% usuário + 0% kernel 08-28 18:54:00.110 1000 1825 1848 E ActivityManager: 0,1% 20492/kworker/5:3: 0% usuário + 0,1% kernel 08-28 18:54: 00.110 1000 1825 1848 E ActivityManager: 3,8% TOTAL: 2% usuário + 1,1% kernel + 0% iowait + 0,3% irq + 0,1% softirq
De acordo com a rotina acima, tudo está relativamente normal. O horário da ocorrência é provavelmente 28/08 18:54:00.110. Estou olhando o rastreamento do thread principal.
----- pid 20576 em 28/08/2018 18:53:56 ----- Linha cmd: com.jeejen.family "main" prio=5 tid=1 Nativo | group="main" sCount=1 dsCount=0 sinalizadores=1 obj=0x77ffca18 self=0xecfce000 | sysTid=20576 nice=-10 cgrp=padrão sched=0/0 handle=0xf0bf2494 | estado = S schedstat = (628294395 402363898 957) utm = 42 stm = 20 núcleo = 4 HZ = 100 | pilha=0xff5fe000-0xff600000 stackSize=8MB | retidos mutexes= kernel: (não foi possível ler /proc/self/task/20576/stack) nativo: #00 pc 00053cfc /system/lib/libc.so (__ioctl+8) nativo: #01 pc 00021cd3 /system/lib /libc.so (ioctl+30) nativo: #02 pc 0003d3f5 /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+204) nativo: #03 pc 0003dde3 /system/lib/libbinder.so (android::IPCThreadState::waitForResponse(android::Parcel*, int*)+26) nativo: #04 pc 0003713d /system/lib/libbinder.so ( android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+36) nativo: #05 pc 000c3cf1 /system/lib/libandroid_runtime.so (android_os_BinderProxy_transact(_JNIEnv*, _jobject *, int, _jobject*, _jobject*, int)+200) em android.os.BinderProxy.transactNative(método nativo) em android.os.BinderProxy.transact(Binder.java:1127) em android.net.wifi.IWifiManager $Stub$Proxy.getConnectionInfo(IWifiManager.java:1441) em android.net.wifi.WifiManager.getConnectionInfo(WifiManager.java:1778) at org.chromium.net.NetworkChangeNotifierAutoDetect$WifiManagerDelegate.getWifiInfoLocked(NetworkChangeNotifierAutoDetect.java:28) at org.chromium.net.NetworkChangeNotifierAutoDetect$WifiManagerDelegate.getWifiSsid(NetworkChangeNotifierAutoDetect.java:22) - locked <0x0f4edae7> (a java.lang.Object ) em org.chromium.net.NetworkChangeNotifierAutoDetect.getCurrentNetworkState(NetworkChangeNotifierAutoDetect.java:67) em org.chromium.net.NetworkChangeNotifierAutoDetect.<init>(NetworkChangeNotifierAutoDetect.java:21) em org.chromium.net.NetworkChangeNotifier.setAutoDetectConnectivityStateInternal(NetworkChange Notificador. java:61)
Parece que a chamada do fichário está bloqueada e a interface de chamada é IWifiManager.getConnectionInfo(). Por ser uma chamada de fichário, verifique binder_sample.
08-28 18:54:01.384 10171 20576 20576 I binder_sample: [android.net.wifi.IWifiManager,24,16004,com.jeejen.family,100] 08-28 18:54:04.868 10171 20576 20576 I binder_ amostra: [ android.net.wifi.IWifiManager,24,3479,com.jeejen.family,100] 08-28 18:56:12.712 10171 21885 21885 I binder_sample: [android.net.wifi.IWifiManager,24,8963,com.jeejen .família,100]
Pode-se observar que às vezes próximo ao ANR, a chamada do binder usando a interface IWifiManager demora muito, então esse é um motivo do sistema? Então dê uma olhada no código de seu par Sysytem.
1763 /** 1764 * Consulte {@link android.net.wifi.WifiManager#getConnectionInfo()} 1765 * @return as informações de Wi-Fi, contidas em {@link WifiInfo}. 1766 */ 1767 @Override 1768 public WifiInfo getConnectionInfo() { 1769 aplicarAccessPermission(); 1770 mLog.trace("getConnectionInfo uid=%").c(Binder.getCallingUid()).flush(); 1771 /* 1772 * Certifique-se de que temos as informações mais recentes, enviando 1773 * uma solicitação de status ao suplicante. 1774 */ 1775 return mWifiStateMachine.syncRequestConnectionInfo(); 1776}
1521 WifiInfo público syncRequestConnectionInfo() { 1522 Resultado WifiInfo = new WifiInfo(mWifiInfo); 1523 resultado de retorno; 1524}
getConnectionInfo chama syncRequestConnectionInfo em wifiStateMachine diretamente por meio de wifiService. A implementação desta parte não será bloqueada. O Binder está cheio? Isso não é visto no rastreamento, então o que está acontecendo? Tentamos reproduzir esse problema, mas felizmente foi relativamente fácil de reproduzir.
09-04 18:24:29.182 D/WifiStateMachine( 1312): syncRequestConnectionInfo/in SSID: MIOffice-5G, BSSID: 70:3a:0e:2c:bb:f1, MAC: 80:ad:16:4c:0b: fe, estado do suplicante: CONCLUÍDO, RSSI: -44, velocidade do link: 400 Mbps, frequência: 5180 MHz, ID de rede: 0, dica medida: falso, pontuação: 60 09-04 18: 24: 29.182 D/WifiStateMachine (1312): syncRequestConnectionInfo /out SSID: MIOffice-5G, BSSID: 70:3a:0e:2c:bb:f1, MAC: 80:ad:16:4c:0b:fe, Estado do suplicante: COMPLETED, RSSI: -44, Velocidade do link: 400Mbps , Frequência: 5180 MHz, Net ID: 0, Dica medida: falso, pontuação: 60
Verificou-se que o thread principal estava gerando uma grande quantidade do log acima, e o desktop minimalista chamou essa interface 160 vezes em 1 minuto, fazendo com que o SystemServer não conseguisse responder ao aplicativo em tempo hábil, fazendo com que o próprio aplicativo ANR. Problemas como ANR causados por chamadas do Binder são muito comuns e existe o risco de ser bloqueado. Neste momento, você pode tentar executá-lo de forma assíncrona. Em segundo lugar, não faça um grande número de chamadas do Binder em um curto período de tempo . Este comportamento pode causar problemas no próprio App ou, na pior das hipóteses, o sistema pode travar e reiniciar com o Watchdog. .
3.5. Caso 3: O tempo limite da transmissão causa ANR do aplicativo
Vamos continuar com o Caso 3. De acordo com a rotina acima, primeiro verifique a hora em que ocorreu o ANR no log de eventos.
12-17 06: 02: 14.463 1566 1583 Eu sou_anr: [0,8769, com.android.updater, 952680005, transmissão de intenção { act = android.intent.action.BOOT_COMPLETED flg = 0x9000010 cmp = com.android.updater/ .BootCompletedReceiver (tem extras) }]
O horário em que o ANR ocorreu é am_anr. O ponto no tempo é 12-17 06:02:14.463. Continue examinando o registro.
12-17 06:02:00.370 1566 1583 W BroadcastQueue: Tempo limite da transmissão BroadcastRecord{21ef8c2 u0 android.intent.action.BOOT_COMPLETED} - receiver=android.os.BinderProxy@2a6c365, iniciado 60006ms atrás 12-17 06:02:00.370 1566 1583 W BroadcastQueue: Receptor durante o tempo limite: ResolveInfo{5a8283a com.android.updater/.BootCompletedReceiver m=0x108000} 12-17 06:02:00.370 1566 1583 I am_broadcast_discard_app: [0,35584194,android.intent. ação.BOOT_COMPLETED, 49,ResolveInfo{5a8283a com.android.updater/.BootCompletedReceiver m=0x108000}]
No entanto, descobrimos que o ANR ocorreu entre 12-17 06:02:00.370, indicando que o horário no log de eventos é um valor aproximado e pode haver um certo grau de atraso devido à escassez de recursos do sistema. Como é a transmissão android.intent.action.BOOT_COMPLETED que recebe o ANR, podemos seguir as pistas.
12-17 06:01:00.383 1566 3524 I ActivityManager: Iniciar proc 8769:com.android.updater/9802 para transmissão com.android.updater/.BootCompletedReceiver caller=null
O processo de transmissão foi iniciado às 12-17 06:01:00.383
12-17 06:01:36.721 8769 8769 D BootCompletedReceiver: onReceive android.intent.action.BOOT_COMPLETED 12-17 06:02:14.725 8769 8769 D UpdateService: onCreate
Às 12-17 06:01:36.721, o método onReceiver do cliente BootCompletedReceiver inicia o retorno de chamada, então onReceive inicia UpdateService e o tempo para chamar UpdateService.onCreate é 12-17 06:02:14.725. Com base na análise acima, há duas questões preliminares.
A transmissão começou às 12-17 06:01:00.383, o método onReceiver da transmissão iniciou o retorno de chamada às 12-17 06:01:36.721, e o horário ANR foi às 12-17 06:02:00.370, então por que isso iniciar 36 segundos depois? Acabei de receber a transmissão de inicialização concluída, o que é anormal por si só. Em segundo lugar, por que leva quase mais de um minuto para iniciar o UpdateService por meio da transmissão? Depois de analisar este ponto, os alunos do App acham que é impossível analisar mais a fundo, e 80% disso se deve ao sistema. A julgar pelas estatísticas da CPU, acredita-se que seja causado pelo uso excessivo de determinados programas, e o seguinte log é postado.
12-17 06:02:19.286 1566 1583 E ActivityManager: ANR em com.android.updater 12-17 06:02:19.286 1566 1583 E ActivityManager: PID: 8769 12-17 06:02:19.286 1566 1583 E ActivityManager: Motivo : Transmissão de Intent { act=android.intent.action.BOOT_COMPLETED flg=0x9000010 cmp=com.android.updater/.BootCompletedReceiver (tem extras) } 12-17 06:02:19.286 1566 1583 E ActivityManager: Carregar: 0,0/0,0 / 0,0 12-17 06: 02: 19.286 1566 1583 E ActivityManager: uso da CPU de 0 ms a 18.846 ms depois (2017-12-17 06: 02: 00.379 a 2017-12-17 06: 02: 19.224): 12-17 06 :02:19.286 1566 1583 E ActivityManager: 195% 6142/com.immomo.momo: 195% usuário + 0% kernel 12-17 06:02:19.286 1566 1583 E ActivityManager: 2,3% 8170/com.tencent.mm: 2,3 % usuário + 0% kernel/falhas: 448 menores 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,7% 1566/system_server: 0,4% usuário + 0,3% kernel/falhas: 150 menores 1 principais 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,4% 90 / kworker/u16:3: 0% usuário + 0,4% kernel 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,3% 4704/com.tencent.mm:push: 0,1% usuário + 0,2% kernel / falhas: 116 menores 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,3% 8769/com.android.updater: 0,2% usuário + 0,1% kernel / falhas: 1600 menor 2 principal 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,2% 4790/com.tencent.mm:patch: 0,2% usuário + 0% kernel/falhas: 748 menores 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,2% 329/mmc-cmdqd/0: 0% usuário + 0,2% de núcleo 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,2% 5429/com.tencent.mm:push: 0% usuário + 0,1% kernel / falhas: 17 menores 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,2% 5435/com.tencent.mm:patch: 0,2% usuário + 0% kernel/falhas: 82 menores 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,2% 8712/com.tencent.mm:exdevice: 0,1 % usuário + 0% kernel 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,1% 432/logd: 0,1% usuário + 0% kernel / falhas: 4 menores 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,1% 844/msm_irqbalance: 0% usuário + 0,1% kernel/falhas: 4 menores 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,1% 7580/kworker/u16:2: 0% usuário + 0,1% kernel 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,1% 7/rcu_preempt: 0% usuário + 0,1% kernel 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,1% 1240/zygote: 0% usuário + 0,1 % kernel/falhas: 84 menores 12-17 06:02:19.286 1566 1583 E ActivityManager: 0% 3216/com.xiaomi.simactivate.service: 0% usuário + 0% kernel/falhas: 5 menores 12-17 06:02 :19.286 1566 1583 E ActivityManager: 0,1% 8645/kworker/7:0: 0% usuário + 0,1% kernel 12-17 06:02:19.286 1566 1583 E ActivityManager: 0,1% 8730/kworker/4:2: 0% usuário + 0,1% kernel 12-17 06:02:19.286 1566 1583 E ActivityManager: 0% 45/rcuop/4: 0% usuário + 0% kernel
No entanto, a ocupação da CPU de 195% não é alta. Em multi-core, a ocupação máxima de cada núcleo é 100% (a ocupação de oito núcleos é 800% ). Em segundo lugar, Carga: 0,0 / 0,0 / 0,0. A carga não é ativo durante 15 minutos. É 0. Está parado? Parece que este Log não está totalmente correto. No entanto, nos telefones Xiaomi, o monitoramento ANR será fortalecido e o seguinte Log será gerado.
12-17 06:02:14.693 8769 8769 W MIUI-BLOCK-MONITOR: A mensagem {quando=-36s107ms what=113 obj=ReceiverData{intent=Intent { act=android.intent.action.BOOT_COMPLETED flg=0x9000010 cmp=com .android.updater/.BootCompletedReceiver (tem extras) } packageName=com.android.updater resultCode=0 resultData=null resultExtras=null} target=android.app.ActivityThread$H planTime=1513461660613 dispatchTime=1513461696720 finishTime=0 } levou 74080ms e levou 37.973 ms após o envio.
Além disso, registramos os pontos no tempo de cada status de cada Mensagem para facilitar nossa análise.
- quando: o tempo desde o momento em que a mensagem deve ser executada até o momento em que anr ocorre
- planTime: o momento em que o plano de mensagem é executado
- dispatchTime: o momento em que a mensagem é realmente executada
- finishTime: O ponto no tempo em que a mensagem é concluída.
Calcule o tempo de execução da mensagem como: -when-(dispatchTime-planTime)=0, então o que isso significa? Isso significa que a Mensagem 113 estava prestes a começar a ser executada, mas ocorreu um ANR antes de iniciar a execução. Ela aguardou 36 segundos na fila de mensagens do Looper do thread principal. Não há rastro do thread principal neste log e não tem efeito porque pode-se observar que esta mensagem ainda não foi executada? Então, o que você está fazendo durante esses 36 segundos? Existem mais registros abaixo.
12-17 06: 01: 29.334 8769 8769 W MIUI-BLOCK-MONITOR: A chamada do fichário levou 3.973 ms. 12-17 06:01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: java.lang.Throwable 12-17 06:01 :29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.os.AnrMonitor.checkBinderCallTime(AnrMonitor. java: 591) 12-17 06: 01: 29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.os.BinderProxy.transact (Binder.java: 623) 12-17 06: 01: 29.334 8769 8769 W MIUI-BLOCK -MONITOR: em android.content.pm.IPackageManager$Stub$Proxy.getApplicationInfo(IPackageManager.java:2658) 12-17 06:01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.app.ApplicationPackageManager.getApplicationInfoAsUser( ApplicationPackageManager.java:340) 12-17 06:01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.app.ApplicationPackageManager.getApplicationInfo(ApplicationPackageManager.java:333) 12-17 06:01: 29.334 8769 8769 W MIUI-BLOCK-MONITOR: em miui.core.ManifestParser.create (SourceFile: 64) 12-17 06: 01: 29.334 8769 8769 W MIUI-BLOCK-MONITOR: em miui.core.SdkManager.start (SourceFile: 186) 12-17 06: 01: 29.334 8769 8769 W MIUI-BLOCK-MONITOR: em java.lang.reflect.Method.invoke (Método Nativo) 12-17 06:01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: em miui.external.a.abx() 12-17 06:01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: em miui.external.a.attachBaseContext() 12-17 06:01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.app.Application .attach(Application.java:193) 12-17 06: 01: 29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.app.Instrumentation.newApplication (Instrumentation.java: 1009) 12-17 06: 01: 29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.app.Instrumentation.newApplication(Instrumentation.java:993) 12-17 06:01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.app.LoadedApk.makeApplication(LoadedApk.java:800) 12-17 06 :01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.app.ActivityThread.handleBindApplication(ActivityThread.java:5471) 12-17 06:01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.app. ActivityThread.-wrap2(ActivityThread.java) 12-17 06:01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.app.ActivityThread$H.handleMessage(ActivityThread.java:1584) 12-17 06: 01: 29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.os.Handler.dispatchMessage (Handler.java: 102) 12-17 06: 01: 29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.os.Looper.loop (Looper.java: 163) 12-17 06: 01: 29.334 8769 8769 W MIUI-BLOCK-MONITOR: em android.app.ActivityThread.main (ActivityThread.java: 6221) 12-17 06 :01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: em java.lang.reflect.Method.invoke (método nativo) 12-17 06:01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: em com.android.internal .os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) 12-17 06:01:29.334 8769 8769 W MIUI-BLOCK-MONITOR: em com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794 )
A operação bindApplication está sendo executada durante os 36 segundos. Neste caso, é mais provável que o status do sistema não seja otimista neste momento. Em segundo lugar, através da análise acima, também podemos ver que o onReceiver do BootCompletedReceiver é processado no thread principal, e iniciar o serviço também leva tempo. Depois de gastar muito tempo, também podemos considerar especificar o manipulador ao registrar o receptor e deixar o onReceiver rodar no thread filho (como fazer isso, você pode ver o código-fonte )
4. Rotinas de análise para problemas de ANR
- Pegue o relatório de bug, procure por ANR, verifique a hora e o processo de ocorrência e veja se há algum problema com a carga da CPU.
- Pesquise o rastreamento do thread principal de acordo com o processo e encontre o local bloqueado. Se for uma chamada do Binder, confirme ainda a situação do extremo oposto; se for uma operação demorada, modifique-a diretamente para assíncrona. Se você Se você suspeitar que a execução do sistema está lenta, você pode verificar binder_sample, dvm_lock e outras informações., Em segundo lugar, se há muitos gcs e se lmk mata processos com frequência, pode informar o status de integridade do sistema.
- Análise e solução baseada em código fonte
Este artigo registra apenas alguns casos e métodos de análise. A ideia norteadora é descobrir por que o thread principal foi bloqueado no passado. De um modo geral, é relativamente fácil de dominar. Ainda não abordou os princípios específicos, como o princípio de despejo do ANR, como o sistema determina o ANR, o que fazer com traços inválidos de ANR e outras questões mais aprofundadas. . Como os problemas de ANR às vezes são uma dor de cabeça, o rastreamento pode não ser a primeira cena do crime. Alguns fabricantes de telefones celulares reforçaram o monitoramento de ANRs, o que pode gerar mais informações e melhorar a eficiência da análise de problemas de ANR. Além disso, também pode ser vimos que os alunos que trabalham com questões de ANR no Room ficarão mais confortáveis devido à experiência na leitura de código-fonte no trabalho.