Trovare il thread che non risponde

Questo documento mostra come identificare il thread che non risponde in un dump dello stack ANR. Il thread che non risponde varia in base al tipo di ANR, come mostrato nella seguente tabella.

Tipo di ANR Il thread non risponde
Invio input Thread principale
Invio di input senza finestra attiva Thread principale. Questo tipo di errore ANR di solito non è causato da un thread bloccato.
Ricevitore broadcast (sincrono) Thread in esecuzione onReceive(). Questo è il thread principale, a meno che non venga specificato un gestore personalizzato su un thread non principale utilizzando Context.registerReceiver.
Ricevitore trasmissione (asincrona) Controlla il codice per vedere quale pool di thread o thread è responsabile dell'elaborazione della trasmissione dopo la chiamata a goAsync.
Esecuzione del timeout del servizio in corso... Thread principale
Avvio del servizio in primo piano Thread principale
Il fornitore di contenuti non risponde Una di queste soglie:
  • Thread di associazione se l'errore ANR è causato da una query relativa a un fornitore di contenuti lento.
  • Thread principale se l'errore ANR è causato da un avvio lungo dell'app.
Nessuna risposta per onStartJob o onStopJob Thread principale

A volte il thread non risponde a causa di una causa principale in un altro thread o processo. Il thread potrebbe non rispondere a causa dell'attesa di quanto segue:

  • Un blocco mantenuto da un thread diverso.
  • Una chiamata a Bider lenta a un processo diverso.

Cause comuni dei thread che non rispondono

Di seguito sono riportate le cause più comuni dei thread che non rispondono.

Chiamata a Binder lenta

Anche se la maggior parte delle chiamate a Binder sono rapide, la long tail può essere molto lenta. Ciò è più probabile che si verifichi se il dispositivo viene caricato o il thread di risposta di Binder è lento, ad esempio in caso di contesa dei blocchi, molte chiamate a Binder in entrata o timeout dell'hardware (HAL).

Per risolvere il problema, sposta le chiamate di binder sincroni in thread in background, ove possibile. Se la chiamata deve avvenire nel thread principale, scopri perché è lenta. Il modo migliore per farlo è usare le tracce di Perfetto.

Cerca BinderProxy.transactNative o Binderproxy.transact negli stack. Questo significa che è in corso una chiamata a Binder. Seguendo queste due righe, puoi vedere l'API Binder che viene chiamata. Nell'esempio seguente, la chiamata è 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)
...

Numerose chiamate a Binder consecutive

L'esecuzione di molte chiamate a binder consecutive in un ciclo chiuso può bloccare un thread per un lungo periodo di tempo.

Un blocco I/O

Non eseguire mai il blocco dell'I/O sul thread principale. Si tratta di un anti-pattern.

Conflitto blocco

Se un thread viene bloccato durante l'acquisizione di un blocco, può causare un errore ANR.

L'esempio seguente mostra che il thread principale è bloccato quando si tenta di acquisire un blocco:

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)
[...]

Il thread di blocco sta inviando una richiesta HTTP per scaricare 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)
[...]

Frame costoso

Il rendering di troppi elementi in un singolo frame può far sì che il thread principale non risponda per la durata del frame, ad esempio:

  • Eseguire il rendering di molti elementi fuori schermo non necessari.
  • Utilizzo di un algoritmo inefficiente, come O(n^2), durante il rendering di molti elementi dell'interfaccia utente.

Bloccata da un altro componente

Se un altro componente, ad esempio un ricevitore di broadcast, blocca il thread principale per più di cinque secondi, potrebbe causare errori ANR nell'invio dell'input e gravi jank.

Evita di lavorare in modo eccessivo sul thread principale nei componenti dell'app. Se possibile, esegui i ricevitori di broadcast su un thread diverso.