Cómo encontrar la conversación que no responde

En este documento, se muestra cómo identificar el subproceso que no responde en un volcado de pila de ANR. El subproceso que no responde varía según el tipo de ANR, como se muestra en la siguiente tabla.

Tipo de ANR Subproceso que no responde
Envío de entradas Subproceso principal
Venta no enfocada del envío de entradas Subproceso principal. Por lo general, un subproceso bloqueado no causa este tipo de ANR.
Receptor de emisión (síncrono) Subproceso que ejecuta onReceive(). Es el subproceso principal, a menos que se especifique con Context.registerReceiver un controlador personalizado en un subproceso que no sea el principal.
Receptor de emisión (asíncrono) Verifica el código para ver qué subproceso o conjunto de subprocesos es responsable de procesar la transmisión después de llamar a goAsync.
Tiempo de espera del servicio de ejecución Subproceso principal
Inicio del servicio en primer plano Subproceso principal
El proveedor de contenido no responde Puede deberse a una de estas opciones:
  • Subproceso de Binder si el error de ANR se debe a una consulta lenta al proveedor de contenido
  • Subproceso principal si el error de ANR se debe a un inicio prolongado de la app
No hay respuesta a onStartJob ni onStopJob Subproceso principal

En ocasiones, el subproceso no responde debido a una causa raíz en otro subproceso o proceso. Es posible que el subproceso no responda debido a que se espera lo siguiente:

  • Un bloqueo que mantiene otro subproceso
  • Una llamada a Binder lenta a un proceso diferente

Causas comunes de subprocesos no responsivos

A continuación, se incluyen las causas comunes de los subprocesos que no responden.

Llamada a Binder lenta

Si bien la mayoría de las llamadas a Binder son rápidas, la cola larga puede ser muy lenta. Es más probable que esto suceda si el dispositivo está cargado o el subproceso de respuesta de Binder es lento, como en la contención de bloqueo, muchas llamadas entrantes a Binder o un tiempo de espera de la capa de abstracción de hardware (HAL).

Para resolver este problema, mueve las llamadas síncronas de Binder a subprocesos en segundo plano siempre que sea posible. Si la llamada debe producirse en el subproceso principal, averigua por qué es lenta. La mejor manera de hacerlo es desde los registros de Perfetto.

Busca BinderProxy.transactNative o Binderproxy.transact en las pilas. Eso significa que se está realizando una llamada a Binder. Luego de estas dos líneas, puedes ver la API de Binder a la que se llama. En el siguiente ejemplo, la llamada es a IAccessibilityManager.addClient.

main tid=123

...
android.os.BinderProxy.transactNative (Native method)
android.os.BinderProxy.transact (BinderProxy.java:568)
android.view.accessibility.IAccessibilityManager$Stub$Proxy.addClient (IAccessibilityManager.java:599)
...

Muchas llamadas consecutivas a Binder

Realizar muchas llamadas consecutivas a Binder en un bucle cerrado puede bloquear un subproceso durante un período prolongado.

Una E/S de bloqueo

Nunca ejecutes E/S de bloqueo en el subproceso principal, ya que es un antipatrón.

Contención de bloqueo

Si se bloquea un subproceso cuando se adquiere un bloqueo, se puede producir un error de ANR.

En el siguiente ejemplo, se muestra que el subproceso principal se bloquea cuando se intenta obtener un bloqueo:

main (tid=1) Blocked

Waiting for com.example.android.apps.foo.BarCache (0x07d657b7) held by
ptz-rcs-28-EDITOR_REMOTE_VIDEO_DOWNLOAD
[...]
at android.app.ActivityThread.handleStopActivity(ActivityThread.java:5412)
[...]

El subproceso de bloqueo realiza una solicitud HTTP para descargar un video:

ptz-rcs-28-EDITOR_REMOTE_VIDEO_DOWNLOAD (tid=110) Waiting

at jdk.internal.misc.Unsafe.park(Native method:0)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:715)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1047)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:230)
at com.example.android.apps.foo.HttpRequest.execute(HttpRequest:136)
at com.example.android.apps.foo$Task$VideoLoadTask.downloadVideoToFile(RequestExecutor:711)
[...]

Fotograma costoso

Renderizar demasiados elementos en un solo fotograma puede generar que el subproceso principal no responda durante la ejecución del fotograma, como en los siguientes casos:

  • Representar muchos elementos innecesarios fuera de la pantalla
  • Usar un algoritmo ineficiente, como O(n^2), cuando se renderizan muchos elementos de IU

Bloqueo de otro componente

Si otro componente, como un receptor de emisión, bloquea el subproceso principal durante más de cinco segundos, podría generar errores de ANR de despacho de entrada y bloqueos graves.

Evita realizar trabajos pesados en el subproceso principal de los componentes de la app. Ejecuta los receptores de emisión en un subproceso diferente siempre que sea posible.