Se il thread dell'interfaccia utente di un'app per Android viene bloccato per troppo tempo, il sistema invia un errore ANR (L'applicazione non risponde). In questa pagina vengono descritti i diversi tipi di errori ANR, come diagnosticarli e i suggerimenti per correggerli. Tutti gli intervalli di tempo di timeout predefiniti elencati sono per dispositivi AOSP e Pixel; questi tempi possono variare in base all'OEM.
Tieni presente che quando determini la causa degli errori ANR, è utile distinguere tra problemi del sistema e delle app.
Quando il sistema è in uno stato non valido, i seguenti problemi possono causare errori ANR:
- I problemi temporanei nel server di sistema causano in genere chiamate a Binder veloci lente.
- I problemi relativi al server di sistema e all'elevato carico del dispositivo causano la mancata pianificazione dei thread di app.
Se disponibile, un buon modo per distinguere tra problemi di sistema e di app è usare tracce Perfetto:
- Per verificare se il thread principale dell'app è pianificato, controlla la traccia dello stato del thread in Perfetto per capire se è in esecuzione o eseguibile.
- Cerca nei thread
system_server
eventuali problemi come la contesa del blocco. - Per le chiamate a Binder lente, osserva il thread di risposta, se presente, per capire perché è lento.
Timeout invio input
Gli errori ANR di invio degli input si verificano quando il thread principale dell'app non risponde in tempo a un evento di input, ad esempio uno scorrimento o la pressione di un tasto. Poiché l'app è in primo piano quando si verificano timeout per l'invio dell'input, sono quasi sempre visibili all'utente ed è molto importante mitigarli.
Periodo di timeout predefinito: 5 secondi.
Gli errori ANR di invio degli input sono di solito causati da problemi nel thread principale. Se il thread principale è stato bloccato in attesa di acquisire un blocco, può essere coinvolto anche il thread di un organizzatore.
Per evitare errori ANR di invio degli input, segui queste best practice:
- Non eseguire operazioni di blocco o a lunga esecuzione sul thread principale. Potresti usare
StrictMode
per rilevare le attività accidentali sul thread principale. - Riduci al minimo la contesa del blocco tra il thread principale e altri thread.
- Riduci al minimo il lavoro non UI sul thread principale, ad esempio durante la gestione di broadcast o servizi in esecuzione.
Cause comuni
Di seguito sono riportate alcune cause comuni e correzioni suggerite per gli errori ANR di invio dell'input.
Motivo | Che cosa succede | Correzioni suggerite |
---|---|---|
Chiamata a Binder lenta | Il thread principale esegue una chiamata a binder sincrona lunga. | Sposta la chiamata fuori dal thread principale o prova a ottimizzare la chiamata, se sei il proprietario dell'API. |
Numerose chiamate a Binder consecutive | Il thread principale esegue molte chiamate a binder sincroni consecutive. | Non eseguire chiamate a Binder in un ciclo chiuso. |
Blocco I/O | Il thread principale effettua il blocco delle chiamate I/O, ad esempio l'accesso al database o alla rete. | Sposta tutti gli IO di blocco dal thread principale. |
Conflitto blocco | Il thread principale è bloccato in attesa di acquisizione di un blocco. | Riduci i conflitti del blocco tra il thread principale e gli altri thread. Ottimizza il codice lento nell'altro thread. |
Frame costoso | Rendering eccessivo in un singolo frame, con conseguente jank grave. | Lavora meno piegando il frame. Non usare algoritmi2. Utilizza componenti efficienti per attività come lo scorrimento o il paging, ad esempio la libreria di Paging Jetpack. |
Bloccata da un altro componente | Un altro componente, ad esempio un ricevitore della trasmissione, è in esecuzione e blocca il thread principale. | Sposta il più possibile il lavoro non UI dal thread principale. Esegui ricevitori di broadcast su un thread diverso. |
Blocco della GPU | Il blocco della GPU è un problema di sistema o hardware che causa il blocco del rendering e, di conseguenza, un errore ANR di invio dell'input. | Purtroppo, di solito non ci sono correzioni sul lato app. Se possibile, contatta il team hardware per risolvere i problemi. |
Come eseguire il debug
Inizia il debug controllando la firma del cluster ANR in Google Play Console o Firebase Crashlytics. Il cluster in genere contiene i primi frame che si sospetta abbiano causato l'errore ANR.
Il seguente diagramma di flusso mostra come determinare la causa di un errore ANR di invio timeout di input.
Play vitals può rilevare ed eseguire il debug di alcune di queste cause comuni degli errori ANR. Ad esempio, se vitals rileva che si è verificato un errore ANR a causa di una contesa del blocco, può riassumere il problema e la correzione consigliata nella sezione Approfondimenti sugli errori ANR.
Nessuna finestra attiva
Mentre eventi come il tocco vengono inviati direttamente alla finestra pertinente in base agli hit test, eventi come i tasti necessitano di un target. Questo target è indicato come finestra mirata. È presente una sola finestra attiva per display e solitamente è la finestra con cui l'utente sta attualmente interagendo. Se non è possibile trovare una finestra attiva, l'input genera un errore ANR di finestra non attiva. Un errore ANR senza finestra attiva è un tipo di errore ANR di invio di input.
Periodo di timeout predefinito: 5 secondi.
Cause comuni
Gli errori ANR senza finestra attiva di solito sono causati da uno dei seguenti problemi:
- L'app sta lavorando troppo ed è troppo lenta per disegnare il primo fotogramma.
- La finestra principale non è attivabile. Se una finestra viene contrassegnata con
FLAG_NOT_FOCUSABLE
, l'utente non può inviarti eventi chiave o pulsante.
Kotlin
override fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) window.addFlags(WindowManager.LayoutParams.FLAG_FLAG_NOT_FOCUSABLE) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); }
Timeout del ricevitore della trasmissione
L'errore ANR di un ricevitore si verifica quando un ricevitore non gestisce la trasmissione in tempo. Per i ricevitori sincroni, o che non chiamano
goAync()
, un timeout indica che onReceive()
non è stato completato
in tempo. Per i ricevitori asincroni, o che chiamano goAsync()
, un timeout significa che PendingResult.finish()
non è stato chiamato in tempo.
Gli errori ANR del ricevitore della trasmissione si verificano spesso in questi thread:
- Thread principale, se il problema è l'avvio lento dell'app.
- Ricevitore di trasmissione in esecuzione Thread, se il problema è un codice
onReceive()
lento. - Trasmetti thread worker, se il problema è un codice di trasmissione
goAsync()
lento.
Per evitare errori ANR di ricevitori trasmessi, segui queste best practice:
- Assicurati che l'avvio dell'app sia rapido, poiché viene conteggiato nel timeout ANR se l'app viene avviata a gestire la trasmissione.
- Se utilizzi
goAsync()
, assicurati chePendingResult.finish()
venga chiamato rapidamente. Questo è soggetto allo stesso timeout ANR dei ricevitori di trasmissione sincroni. - Se viene utilizzato
goAsync()
, assicurati che i thread worker non siano condivisi con altre operazioni a lunga esecuzione o di blocco. - Valuta la possibilità di utilizzare
registerReceiver()
per eseguire ricevitori di broadcast in un thread non principale, per evitare di bloccare il codice UI in esecuzione nel thread principale.
Periodi di timeout
I periodi di timeout della ricezione della trasmissione dipendono dal fatto che sia impostato o meno il flag dell'intent in primo piano e dalla versione della piattaforma.
Tipo di intent | Android 13 e versioni precedenti | Android 14 e versioni successive |
---|---|---|
Intento di priorità in primo piano ( |
10 secondi |
10-20 secondi, a seconda che il processo sia o meno esaurito |
Intento priorità sfondo ( |
60 secondi |
60-120 secondi, a seconda che il processo sia o meno esaurito |
Per determinare se il flag FLAG_RECEIVER_FOREGROUND
è impostato, cerca "flg=" nell'oggetto ANR e verifica la presenza di 0x10000000
. Se questo bit è impostato, l'intent ha impostato FLAG_RECEIVER_FOREGROUND
e quindi il timeout è più breve.
Esempio di soggetto ANR con timeout di trasmissione breve (10-20 secondi):
Broadcast of Intent { act=android.inent.action.SCREEN_ON flg=0x50200010 }
Esempio di soggetto ANR con timeout di trasmissione lungo (60-120 secondi):
Broadcast of Intent { act=android.intent.action.TIME_SET flg=0x25200010 }
Come vengono misurati i tempi di trasmissione
La misurazione della durata della trasmissione inizia quando la trasmissione viene inviata da
system_server
all'app e termina quando l'app termina l'elaborazione
della trasmissione. Se il processo dell'app non era già in esecuzione, deve essere eseguito anche un avvio a freddo entro il periodo di timeout ANR. Di conseguenza, un avvio lento dell'app può causare errori ANR del destinatario della trasmissione.
La figura seguente illustra la sequenza temporale ANR del ricevitore della trasmissione in linea con alcuni processi dell'app.
La misurazione del timeout ANR termina quando il ricevitore termina l'elaborazione della trasmissione: quando esattamente questo accade dipende dal fatto che si tratti di un ricevitore sincrono o asincrono.
- Per i ricevitori sincroni, la misurazione si interrompe quando ritorna
onReceive()
. - Per i ricevitori asincroni, la misurazione si interrompe quando viene chiamato
PendingResult.finish()
.
Cause comuni
Di seguito sono riportate alcune cause comuni e correzioni suggerite per gli errori ANR del ricevitore broadcast.
Motivo | Si applica a | Che cosa è successo | Correzione suggerita |
---|---|---|---|
Avvio dell'app lento | Tutti i destinatari | L'avvio a freddo dell'app ha richiesto troppo tempo. | Ottimizza l'avvio lento dell'app. |
onReceive() non pianificato | Tutti i destinatari | Il thread del ricevitore della trasmissione era impegnato in un altro lavoro e non è stato possibile avviare il metodo onReceive() . | Non eseguire attività a lunga esecuzione sul thread del destinatario (o sposta il destinatario nel thread dedicato). |
Dispositivo onReceive() lento | Tutti i ricevitori, ma principalmente quelli sincroni | Il metodo onReceive() è stato avviato, ma è stato bloccato o è lento, quindi non è stato completato in tempo. | Ottimizza il codice del ricevitore lento. |
Attività ricevitore asincrone non pianificate | goAsync()
ricevitori | Il metodo onReceive() ha tentato di eseguire il lavoro su un pool di thread di worker bloccato, pertanto il lavoro non è mai iniziato. |
Ottimizza le chiamate lente o di blocco oppure utilizza thread diversi per i worker di broadcast rispetto ad altre attività a lunga esecuzione. |
Worker lenti o bloccati | goAsync() ricevitori |
Si è verificata un'operazione lenta o di blocco da qualche parte nel pool di thread di worker durante l'elaborazione della trasmissione. Di conseguenza, PendingResult.finish
non è stato chiamato in tempo. | Ottimizza il codice del ricevitore async lento. |
Hai dimenticato di chiamare il numero PendingResult.finish |
goAsync() ricevitori |
Chiamata a finish() mancante nel percorso del codice. |
Assicurati che finish() sia sempre chiamato. |
Come eseguire il debug
In base alla firma del cluster e al report ANR, puoi individuare il thread su cui viene eseguito il destinatario e poi il codice specifico mancante o in esecuzione lenta.
Il seguente diagramma di flusso mostra come determinare la causa di un errore ANR di un ricevitore di broadcast.
Trovare il codice del destinatario
Google Play Console mostra la classe del destinatario e l'intent di trasmissione nella firma ANR. Cerca quanto segue:
cmp=<receiver class>
act=<broadcast_intent>
Ecco un esempio di firma ANR del ricevitore della trasmissione:
com.example.app.MyClass.myMethod
Broadcast of Intent { act=android.accounts.LOGIN_ACCOUNTS_CHANGED
cmp=com.example.app/com.example.app.MyAccountReceiver }
Trovare il thread che esegue il metodo onRicevi()
Se utilizzi Context.registerReceiver
per specificare un gestore personalizzato, è il thread che esegue questo gestore. Altrimenti, si tratta del thread principale.
Esempio: attività ricevitore asincrone non pianificate
Questa sezione illustra un esempio di come eseguire il debug di un errore ANR di un ricevitore di broadcast.
Supponiamo che la firma ANR abbia il seguente aspetto:
com.example.app.MyClass.myMethod
Broadcast of Intent {
act=android.accounts.LOG_ACCOUNTS_CHANGED cmp=com.example.app/com.example.app.MyReceiver }
In base alla firma, sembra che l'intent di broadcast sia android.accounts.LOG_ACCOUNTS_CHANGED
e la classe del ricevitore sia com.example.app.MyReceiver
.
Dal codice del ricevitore, puoi determinare che il pool di thread "BG Thread
[0,1,2,3]" è il lavoro principale per l'elaborazione di questa trasmissione. Se esamini i dump dello stack, puoi vedere che tutti e quattro i thread di background (BG) hanno lo stesso pattern: eseguono una chiamata di blocco, getDataSync
. Poiché tutti i thread di BG erano occupati, non è stato possibile
elaborare la trasmissione in tempo, il che ha causato un errore ANR.
BG Thread #0 (tid=26) Waiting
at jdk.internal.misc.Unsafe.park(Native method:0)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture:563)
at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture:68)
at com.example.app.getDataSync(<MyClass>:152)
...
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at com.google.android.libraries.concurrent.AndroidExecutorsModule.lambda$withStrictMode$5(AndroidExecutorsModule:451)
at com.google.android.libraries.concurrent.AndroidExecutorsModule$$ExternalSyntheticLambda8.run(AndroidExecutorsModule:1)
at java.lang.Thread.run(Thread.java:1012)
at com.google.android.libraries.concurrent.ManagedPriorityThread.run(ManagedPriorityThread:34)
There are several approaches to fix the issue:
- Find out why
getDataSync
is slow and optimize. - Don't run
getDataSync
on all four BG threads. - More generally, ensure that the BG thread pool isn't saturated with long-running operations.
- Use a dedicated thread pool for
goAsync
worker tasks. - Use an unbounded thread pool instead of the bounded BG thread pool
Example: slow app startup
A slow app startup can cause several types of ANRs, especially broadcast
receiver and execute service ANRs. The cause of an
ANR is likely slow app startup if you see ActivityThread.handleBindApplication
in the main thread stacks.
Execute service timeout
An execute service ANR happens when the app's main thread doesn't start a
service in time. Specifically, a service doesn't finish executing
onCreate()
and onStartCommand()
or onBind()
within the
timeout period.
Default timeout period: 20 seconds for foreground service; 200 seconds for
background service. The ANR timeout period includes the app cold start, if
necessary, and calls to onCreate(), onBind()
, or onStartCommand()
.
To avoid execute service ANRs, follow these general best practices:
- Make sure that app startup is fast, since it's counted in the ANR timeout if the app is started to run the service component.
- Make sure that the service's
onCreate()
,onStartCommand()
, andonBind()
methods are fast. - Avoid running any slow or blocking operations on the main thread from other components; these operations can prevent a service from starting quickly.
Common causes
The following table lists common causes of execute service ANRs and suggested fixes.
Cause | What | Suggested fix |
---|---|---|
Slow app startup | The app takes too long to perform a cold start. | Optimize slow app start. |
Slow onCreate(), onStartCommand (), or
onBind() |
The service component's onCreate(),
onStartCommand (), or onBind() method takes too long to
execute on the main thread. |
Optimize slow code. Move slow operations off the critical path where possible. |
Not scheduled (main thread blocked before onStart() ) |
The app's main thread is blocked by another component before the service can be started. | Move other component's work off the main thread. Optimize other component's blocking code. |
How to debug
From the cluster signature and ANR report in Google Play Console or Firebase Crashlytics, you can often determine the cause of the ANR based on what the main thread is doing.
The following flow chart describes how to debug an execute service ANR.
If you've determined that the execute service ANR is actionable, follow these steps to help resolve the issue:
Find the service component class in the ANR signature. In Google Play Console, the service component class is shown in the ANR signature. In the following example ANR details, it's
com.example.app/MyService
.com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly Executing service com.example.app/com.example.app.MyService
Determine whether the slow or block operation is part of app startup, the service component, or elsewhere by checking for the following important function call(s) in the main threads.
Function call(s) in main thread stacks What it means android.app.ActivityThread.handleBindApplication
App was starting up, so the ANR was caused by slow app start. <ServiceClass>.onCreate()
[...]
android.app.ActivityThread.handleCreateService
Service was being created, so the ANR was likely caused by slow onCreate()
code.<ServiceClass>.onBind()
[...]
android.app.ActivityThread.handleBindService
Service was being bound, so the ANR was likely caused by slow onBind()
code.<ServiceClass>.onStartCommand()
[...]
android.app.ActivityThread.handleServiceArgs
Service was being started, so the ANR was likely caused by slow onStartCommand()
code.For example, if the
onStartCommand()
method in theMyService
class is slow, the main threads will look like this:at com.example.app.MyService.onStartCommand(FooService.java:25) at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4820) at android.app.ActivityThread.-$$Nest$mhandleServiceArgs(unavailable:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2289) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:205) at android.os.Looper.loop(Looper.java:294) at android.app.ActivityThread.main(ActivityThread.java:8176) at java.lang.reflect.Method.invoke(Native method:0)
Se non riesci a visualizzare nessuna delle chiamate di funzione importanti, ci sono un paio di altre possibilità:
- Il servizio è in esecuzione o in fase di arresto, il che significa che gli stack sono stati acquisiti troppo tardi. In questo caso, puoi ignorare l'ANR come falso positivo.
- È in esecuzione un altro componente dell'app, ad esempio un ricevitore. In questo caso, è probabile che il thread principale sia bloccato in questo componente, impedendo l'avvio del servizio.
Se vedi una chiamata di funzione chiave e puoi determinare dove si verifica in generale l'errore ANR, controlla il resto degli stack dei thread principali per trovare l'operazione lenta e ottimizzala oppure spostala fuori dal percorso critico.
- Assicurati che l'avvio dell'app sia rapido, poiché viene conteggiato nel timeout ANR se l'app viene avviata a eseguire il fornitore di contenuti.
- Assicurati che le query dei fornitori di contenuti siano veloci.
- Non eseguire molte chiamate di Binder di blocco simultanee che possono bloccare tutti i thread di Binder dell'app.
- Dubbi dello stack tardivo: Il thread è stato recuperato durante il breve periodo tra l'attivazione dell'ANR e gli stack di cui viene eseguito il dump. La latenza in Pixel su Android 13 è di circa 100 ms, ma può superare 1 secondo. La latenza nei Pixel su Android 14 è solitamente inferiore a 10 ms.
- Attribuzione errata del thread. Il thread utilizzato per creare la firma ANR non era quello effettivo che non risponde che ha causato l'errore ANR. In questo caso, prova a determinare se l'errore ANR è uno dei seguenti tipi:
- Problema a livello di sistema. Il processo non è stato pianificato a causa di un carico elevato o di un problema del server di sistema.
- Prendere lo stack richiede troppo tempo e si verifica un timeout.
- Il processo è morto o è stato interrotto prima che le pile venissero prese.
Per ulteriori informazioni sui servizi, consulta le seguenti pagine:
Il fornitore di contenuti non risponde
Un errore ANR del fornitore di contenuti si verifica quando un fornitore di contenuti remoto impiega più tempo del periodo di timeout per rispondere a una query e viene interrotto.
Periodo di timeout predefinito: specificato dal fornitore di contenuti utilizzando ContentProviderClient.setDetectNotResponding
. Il periodo di timeout ANR include il tempo totale per l'esecuzione di una query del fornitore di contenuti remoto, incluso l'avvio a freddo dell'app remota, se non era già in esecuzione.
Per evitare errori ANR dei fornitori di contenuti, segui queste best practice:
Cause comuni
La seguente tabella elenca le cause comuni degli errori ANR dei fornitori di contenuti e le correzioni suggerite.
Motivo | Che cosa succede | Segnale | Correzione suggerita |
---|---|---|---|
Query lenta sul fornitore di contenuti | Il fornitore di contenuti impiega troppo tempo per essere eseguito o è bloccato. | Il frame android.content.ContentProvider$Transport.query si trova nel thread di Binder. |
Query Ottimizza il fornitore di contenuti. Scopri cosa blocca il thread di binder. |
Avvio dell'app lento | L'avvio dell'app del fornitore di contenuti richiede troppo tempo. | Il frame ActivityThread.handleBindApplication si trova nel
thread principale. |
Ottimizza l'avvio dell'app. |
Esaurimento dei thread di Binder: tutti i fili di Binder sono occupati | Tutti i thread di Binder sono occupati a gestire altre richieste sincrone, pertanto non è possibile eseguire la chiamata a Binder del fornitore di contenuti. | L'app non viene avviata, tutti i thread di Binder sono occupati e il fornitore di contenuti non è in esecuzione. | Riduci il carico sui fili di raccoglitore. Ciò significa che puoi effettuare meno chiamate a Binder in uscita sincrone o svolgere meno lavoro durante la gestione delle chiamate in arrivo. |
Come eseguire il debug
Per eseguire il debug di un errore ANR del fornitore di contenuti utilizzando la firma del cluster e il report ANR in Google Play Console o Firebase Crashlytics, controlla cosa stanno facendo i thread principali e i thread del binder.
Il seguente diagramma di flusso descrive come eseguire il debug di un errore ANR del fornitore di contenuti:
Il seguente snippet di codice mostra l'aspetto del thread di Binder quando è bloccato a causa di una query del fornitore di contenuti lenta. In questo caso, la query del fornitore di contenuti è in attesa del blocco all'apertura di un database.
binder:11300_2 (tid=13) Blocked
Waiting for osm (0x01ab5df9) held by at com.google.common.base.Suppliers$NonSerializableMemoizingSupplier.get(Suppliers:182)
at com.example.app.MyClass.blockingGetOpenDatabase(FooClass:171)
[...]
at com.example.app.MyContentProvider.query(MyContentProvider.java:915)
at android.content.ContentProvider$Transport.query(ContentProvider.java:292)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:107)
at android.os.Binder.execTransactInternal(Binder.java:1339)
at android.os.Binder.execTransact(Binder.java:1275)
Lo snippet di codice riportato di seguito mostra l'aspetto del thread principale quando è bloccato a causa di un avvio lento dell'app. In questo caso, l'avvio dell'app è lento a causa della contesa dei blocchi durante l'inizializzazione del pugnale.
main (tid=1) Blocked
[...]
at dagger.internal.DoubleCheck.get(DoubleCheck:51)
- locked 0x0e33cd2c (a qsn)at dagger.internal.SetFactory.get(SetFactory:126)
at com.myapp.Bar_Factory.get(Bar_Factory:38)
[...]
at com.example.app.MyApplication.onCreate(DocsApplication:203)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1316)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6991)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(unavailable:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2235)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8170)
at java.lang.reflect.Method.invoke(Native method:0)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Risposta del job lenta
Un errore ANR di risposta del job lento si verifica quando l'app impiega troppo tempo per rispondere a JobService.onStartJob()
o JobService.onStopJob()
oppure impiega troppo tempo per fornire una notifica utilizzando JobService.setNotification()
. Questo suggerisce che
il thread principale dell'app è bloccato a compiere un'altra azione.
Se si tratta di un problema con JobService.onStartJob()
o JobService.onStopJob()
,
controlla cosa sta succedendo nel thread principale. Se si tratta di un problema con JobService.setNotification()
, assicurati di chiamare il più rapidamente possibile.
Non lavorare molto prima di aver ricevuto la notifica.
ANR dei misteri
A volte non è chiaro il motivo per cui si sta verificando un errore ANR oppure non ci sono informazioni sufficienti per eseguirne il debug nella firma del cluster e nel report ANR. In questi casi, ci sono ancora alcuni passaggi che puoi seguire per determinare se l'errore ANR è attuabile.
Coda messaggi inattiva o nativePollOnce
Se vedi il frame android.os.MessageQueue.nativePollOnce
negli stack, spesso indica che il thread sospetto che non risponde era in realtà inattivo e in attesa di messaggi looper. In Google Play Console, i dettagli ANR
sono simili ai seguenti:
Native method - android.os.MessageQueue.nativePollOnce
Executing service com.example.app/com.example.app.MyService
Ad esempio, se il thread principale è inattivo, gli stack avranno il seguente aspetto:
"main" tid=1 NativeMain threadIdle
#00 pc 0x00000000000d8b38 /apex/com.android.runtime/lib64/bionic/libc.so (__epoll_pwait+8)
#01 pc 0x0000000000019d88 /system/lib64/libutils.so (android::Looper::pollInner(int)+184)
#02 pc 0x0000000000019c68 /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
#03 pc 0x000000000011409c /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
at android.os.MessageQueue.nativePollOnce (Native method)
at android.os.MessageQueue.next (MessageQueue.java:339) at android.os.Looper.loop (Looper.java:208)
at android.app.ActivityThread.main (ActivityThread.java:8192)
at java.lang.reflect.Method.invoke (Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:626)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1015)
Esistono diversi motivi per cui il thread sospetto che non risponde può essere inattivo:
Nessuno stack frame
Alcuni report ANR non includono gli stack con l'errore ANR, il che significa che il dumping dello stack non è riuscito durante la generazione del report ANR. Ci sono un paio di possibili motivi per la mancanza di stack frame:
[...]
--- CriticalEventLog ---
capacity: 20
timestamp_ms: 1666030897753
window_ms: 300000
libdebuggerd_client: failed to read status response from tombstoned: timeout reached?
----- Waiting Channels: pid 7068 at 2022-10-18 02:21:37.<US_SOCIAL_SECURITY_NUMBER>+0800 -----
[...]
Non è possibile eseguire azioni sugli errori ANR senza stack frame dalla firma del cluster o dal report ANR. Per eseguire il debug, esamina altri cluster per l'app. Se un problema è abbastanza grande, di solito avrà un proprio cluster in cui sono presenti gli stack frame. Un'altra opzione è dare un'occhiata a Tracce perfetti.
Problemi noti
Mantenere un timer nel processo della tua app al fine di terminare la gestione della trasmissione prima dell'attivazione di un ANR potrebbe non funzionare correttamente a causa della modalità asincrona di monitoraggio degli errori ANR da parte del sistema.