Android: ¿cómo investigo un ANR?

¿Hay alguna manera de averiguar dónde mi aplicación arrojó un ANR (aplicación no responde). Eché un vistazo al archivo traces.txt en / data y veo un rastro para mi aplicación. Esto es lo que veo en el rastro.

DALVIK THREADS: "main" prio=5 tid=3 TIMED_WAIT | group="main" sCount=1 dsCount=0 s=0 obj=0x400143a8 | sysTid=691 nice=0 sched=0/0 handle=-1091117924 at java.lang.Object.wait(Native Method) - waiting on  (a android.os.MessageQueue) at java.lang.Object.wait(Object.java:195) at android.os.MessageQueue.next(MessageQueue.java:144) at android.os.Looper.loop(Looper.java:110) at android.app.ActivityThread.main(ActivityThread.java:3742) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497) at dalvik.system.NativeStart.main(Native Method) "Binder Thread #3" prio=5 tid=15 NATIVE | group="main" sCount=1 dsCount=0 s=0 obj=0x434e7758 | sysTid=734 nice=0 sched=0/0 handle=1733632 at dalvik.system.NativeStart.run(Native Method) "Binder Thread #2" prio=5 tid=13 NATIVE | group="main" sCount=1 dsCount=0 s=0 obj=0x433af808 | sysTid=696 nice=0 sched=0/0 handle=1369840 at dalvik.system.NativeStart.run(Native Method) "Binder Thread #1" prio=5 tid=11 NATIVE | group="main" sCount=1 dsCount=0 s=0 obj=0x433aca10 | sysTid=695 nice=0 sched=0/0 handle=1367448 at dalvik.system.NativeStart.run(Native Method) "JDWP" daemon prio=5 tid=9 VMWAIT | group="system" sCount=1 dsCount=0 s=0 obj=0x433ac2a0 | sysTid=694 nice=0 sched=0/0 handle=1367136 at dalvik.system.NativeStart.run(Native Method) "Signal Catcher" daemon prio=5 tid=7 RUNNABLE | group="system" sCount=0 dsCount=0 s=0 obj=0x433ac1e8 | sysTid=693 nice=0 sched=0/0 handle=1366712 at dalvik.system.NativeStart.run(Native Method) "HeapWorker" daemon prio=5 tid=5 VMWAIT | group="system" sCount=1 dsCount=0 s=0 obj=0x4253ef88 | sysTid=692 nice=0 sched=0/0 handle=1366472 at dalvik.system.NativeStart.run(Native Method) ----- end 691 ----- 

¿Cómo puedo averiguar dónde está el problema? Los métodos en la traza son todos los métodos SDK.

Gracias.

Un ANR ocurre cuando una operación larga tiene lugar en el hilo “principal”. Este es el hilo de bucle de evento, y si está ocupado, Android no puede procesar ningún otro evento GUI en la aplicación y, por lo tanto, arroja un cuadro de diálogo ANR.

Ahora, en el seguimiento que publicó, el hilo principal parece estar bien, no hay problema. Está inactivo en MessageQueue, esperando a que aparezca otro mensaje. En su caso, el ANR probablemente fue una operación más larga, en lugar de algo que bloqueó el hilo permanentemente, por lo que el hilo del evento se recuperó después de que la operación finalizó y después del ANR.

Detectar dónde ocurren los ANR es fácil si se trata de un locking permanente (por ejemplo, un punto muerto que adquiere algunos lockings), pero más difícil si solo se trata de un retraso temporal. Primero, repase su código y busque lugares vunerables y operaciones de larga duración. Los ejemplos pueden incluir el uso de sockets, lockings, secuencias de hilos y otras operaciones de locking desde el hilo del evento. Debes asegurarte de que todo esto suceda en hilos separados. Si nada parece ser el problema, use DDMS y habilite la vista de subprocesos. Esto muestra todos los hilos en su aplicación similar a la traza que tiene. Reproduzca el ANR y actualice el hilo principal al mismo tiempo. Eso debería mostrarle exactamente qué está sucediendo en el momento de la ANR

Puede habilitar StrictMode en API nivel 9 y superior.

StrictMode se usa con mayor frecuencia para detectar acceso accidental a disco o red en el hilo principal de la aplicación, donde se reciben operaciones de IU y se realizan animaciones. Al mantener la respuesta del hilo principal de su aplicación, también evita que los diálogos ANR se muestren a los usuarios.

 public void onCreate() { StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectAll() .penaltyLog() .penaltyDeath() .build()); super.onCreate(); } 

Usando penaltyLog() puede ver el resultado de adb logcat mientras usa su aplicación para ver las violaciones a medida que ocurren.

Te estás preguntando qué tarea tiene un subproceso de interfaz de usuario. El archivo de seguimiento le da una pista para encontrar la tarea. necesitas investigar un estado de cada hilo

Estado del hilo

  • corriendo – ejecutando el código de la aplicación
  • durmiendo – llamado Thread.sleep ()
  • monitor: esperando adquirir un locking de monitor
  • espera – en Object.wait ()
  • nativo – ejecutando código nativo
  • vmwait – esperando en un recurso VM
  • zombie – thread está en proceso de morir
  • init – thread se está inicializando (no debería ver esto)
  • start – thread está a punto de comenzar (no debería ver esto tampoco)

Enfoque en estado SUSPENDIDO, MONITOR. El estado del monitor indica qué hilo se está investigando y el estado SUSPENDIDO del hilo es probablemente el motivo principal del punto muerto.

Pasos básicos de investigación

  1. Encuentra “esperando para bloquear”
    • puede encontrar el estado del monitor “Binder Thread # 15” prio = 5 tid = 75 MONITOR
    • tienes suerte si encuentras “esperando para bloquear”
    • ejemplo: esperando para bloquear <0xblahblah> (a com.foo.A) en manos de threadid = 74
  2. Puede observar que “tid = 74” contiene una tarea ahora. Así que vaya a tid = 74
  3. tid = 74 ¡estado quizás SUSPENDIDO! ¡encuentra la razón principal!

trace no siempre contiene “esperando para bloquear”. en este caso, es difícil encontrar la razón principal.

He estado aprendiendo sobre Android durante los últimos meses, así que estoy lejos de ser un experto, pero me ha decepcionado mucho la documentación sobre ANR.

La mayoría de los consejos parecen estar orientados a evitarlos o corregirlos mirando ciegamente a través de su código, lo cual es genial, pero no pude encontrar nada en el análisis de la traza.

Hay tres cosas que realmente debe buscar con los registros de ANR.

1) Interlockings: cuando un hilo está en el estado de ESPERA, puede consultar los detalles para encontrar quién está “retenido =”. La mayoría de las veces, se llevará a cabo por sí mismo, pero si está retenido por otro hilo, es probable que sea una señal de peligro. Ve a mirar ese hilo y mira en qué está contenido. Es posible que encuentre un bucle, que es una clara señal de que algo salió mal. Esto es bastante raro, pero es el primer punto porque cuando sucede, es una pesadilla

2) Espera del hilo principal: si su hilo principal está en el estado de ESPERA, compruebe si está retenido por otro hilo. Esto no debería suceder, porque el hilo de UI no debería estar retenido por un hilo de fondo.

Ambos escenarios, significa que debe volver a trabajar su código de manera significativa.

3) Operaciones pesadas en el hilo principal: esta es la causa más común de ANR, pero a veces es una de las más difíciles de encontrar y corregir. Mira los detalles del hilo principal. Desplácese hacia abajo en el seguimiento de la stack y hasta que vea las clases que reconoce (desde su aplicación). Observe los métodos en el rastreo y descubra si está haciendo llamadas de red, llamadas de DNS, etc. en estos lugares.

Finalmente, y me disculpo por haber insertado sin vergüenza mi propio código, puede usar el analizador de registros de Python que escribí en https://github.com/HarshEvilGeek/Android-Log-Analyzer. Esto irá a través de sus archivos de registro, abrirá archivos ANR, encontrará interlockings, encuentre los hilos principales en espera, encuentre excepciones no detectadas en los registros de su agente e imprímalo todo en la pantalla de una manera relativamente fácil de leer. Lea el archivo ReadMe (que estoy a punto de agregar) para aprender a usarlo. ¡Me ha ayudado muchísimo la semana pasada!

Cada vez que está analizando problemas de sincronización, la depuración a menudo no ayuda, ya que congelar la aplicación en un punto de interrupción hará que el problema desaparezca.

Su mejor opción es insertar muchas llamadas de registro (Log.XXX ()) en los diferentes subprocesos y devoluciones de llamadas de la aplicación y ver dónde está la demora. Si necesita un stacktrace, cree una nueva excepción (solo crea una instancia) y conéctela.

¿Qué desencadena ANR?

En general, el sistema muestra un ANR si una aplicación no puede responder a la entrada del usuario.

En cualquier situación en la que su aplicación realice una operación potencialmente larga, no debe realizar el trabajo en el hilo de la interfaz de usuario, sino crear un hilo de trabajo y hacer la mayor parte del trabajo allí. Esto mantiene el hilo de la interfaz de usuario (que controla el bucle de eventos de la interfaz de usuario) y evita que el sistema concluya que el código se ha congelado.

Cómo evitar ANR

Las aplicaciones de Android normalmente se ejecutan completamente en un solo subproceso de forma predeterminada el “subproceso de interfaz de usuario” o “subproceso principal”). Esto significa que cualquier cosa que su aplicación esté haciendo en el subproceso UI que lleve mucho tiempo completar puede desencadenar el diálogo ANR porque su aplicación no se está dando la oportunidad de manejar el evento de entrada o las transmisiones por intención.

Por lo tanto, cualquier método que se ejecute en el subproceso de UI debe hacer el menor trabajo posible en ese subproceso. En particular, las actividades deberían hacer lo menos posible para configurar los métodos clave del ciclo de vida, como onCreate () y onResume (). Las operaciones potencialmente largas como las operaciones de red o de base de datos, o los cálculos computacionalmente costosos como cambiar el tamaño de mapas de bits se deben hacer en un hilo de trabajo (o en el caso de operaciones de bases de datos, a través de una solicitud asincrónica).

Código: hilo de trabajo con la clase AsyncTask

 private class DownloadFilesTask extends AsyncTask { // Do the long-running work in here protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); // Escape early if cancel() is called if (isCancelled()) break; } return totalSize; } // This is called each time you call publishProgress() protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } // This is called when doInBackground() is finished protected void onPostExecute(Long result) { showNotification("Downloaded " + result + " bytes"); } } 

Código: Ejecutar hilo de trabajo

Para ejecutar este hilo de trabajo, simplemente crea una instancia y ejecuta execute ():

 new DownloadFilesTask().execute(url1, url2, url3); 

Fuente

http://developer.android.com/training/articles/perf-anr.html

mi problema con ANR, después de mucho trabajo descubrí que un hilo estaba llamando a un recurso que no existía en el diseño, en lugar de devolver una excepción, obtuve ANR …

Debe buscar “esperando bloquear” en el archivo /data/anr/traces.txt

enter image description here

para más detalles: Ingeniero de Alto Rendimiento con Herramientas de Android & Play (Google I / O ’17)

Básico sobre la respuesta de @Horyun Lee, escribí un pequeño script de python para ayudar a investigar ANR desde traces.txt .

Los ANR se mostrarán como gráficos por graphviz si ha instalado grapvhviz en su sistema.

 $ ./anr.py --format png ./traces.txt 

Un png dará como resultado a continuación si hay ANR detectados en el archivo traces.txt . Es mas intuitivo

enter image description here

El archivo de ejemplo de traces.txt utilizado anteriormente se obtuvo de aquí .

Considere usar la biblioteca ANR-Watchdog para rastrear con precisión y capturar rastros de stack ANR con un alto nivel de detalle. Luego puede enviarlos a su biblioteca de informes de fallas. Recomiendo usar setReportMainThreadOnly() en este escenario. Puede hacer que la aplicación arroje una excepción no fatal del punto de congelación, o hacer que la fuerza de la aplicación se cierre cuando ocurre el ANR.

Tenga en cuenta que los informes ANR estándar que se envían a su consola de Google Play Developer a menudo no son lo suficientemente precisos como para identificar el problema exacto. Es por eso que se necesita una biblioteca de terceros.

Intereting Posts