Nicht reagierenden Thread suchen

In diesem Dokument wird gezeigt, wie Sie den nicht reagierenden Thread in einem ANR-Stack-Dump identifizieren. Der nicht reagierende Thread variiert je nach ANR-Typ, wie in der folgenden Tabelle gezeigt.

ANR-Typ Thread reagiert nicht
Eingabeweiterleitung Hauptthread
Eingabeweiterleitung, kein fokussiertes Fenster Hauptthread. Diese Art von ANR-Fehler wird normalerweise nicht durch blockierte Threads verursacht.
Broadcast-Empfänger (synchron) Thread wird ausgeführt: onReceive(). Dies ist der Hauptthread, sofern kein benutzerdefinierter Handler für einen Nicht-Hauptthread mit Context.registerReceiver angegeben wird.
Broadcast-Receiver (asynchron) Prüfen Sie den Code, um festzustellen, welcher Thread oder Thread-Pool für die Verarbeitung des Broadcasts verantwortlich ist, nachdem goAsync aufgerufen wurde.
Zeitlimit für Dienst wird ausgeführt Hauptthread
Dienst im Vordergrund starten Hauptthread
Contentanbieter antwortet nicht Sie haben folgende Möglichkeiten:
  • Binder-Thread, wenn ANR durch eine langsame Contentanbieter-Abfrage verursacht wird.
  • Hauptthread, wenn ANR durch einen langen App-Start verursacht wird.
Keine Antwort auf onStartJob oder onStopJob Hauptthread

Manchmal reagiert der Thread aufgrund einer Ursache in einem anderen Thread oder Prozess nicht. Der Thread reagiert möglicherweise nicht, weil auf Folgendes gewartet wurde:

  • Eine Sperre für einen anderen Thread.
  • Ein langsamer Binder-Aufruf an einen anderen Prozess.

Häufige Ursachen für nicht reagierende Threads

Häufige Ursachen für nicht reagierende Threads:

Langsamer Binder-Aufruf

Obwohl die meisten Binder-Aufrufe schnell sind, kann der Longtail sehr langsam sein. Dies ist wahrscheinlicher, wenn das Gerät geladen wird oder der Binder-Antwort-Thread langsam ist, z. B. aufgrund von Sperrenkonflikten, vielen eingehenden Binder-Aufrufen oder einem Zeitlimit für die Hardwareabstraction Layer (HAL).

Sie können dies lösen, indem Sie nach Möglichkeit synchrone Binder-Aufrufe in Hintergrundthreads verschieben. Wenn der Aufruf im Hauptthread erfolgen muss, finden Sie heraus, warum der Aufruf langsam ist. Dazu verwenden Sie am besten Perfetto-Traces.

Suchen Sie in den Stapeln nach BinderProxy.transactNative oder Binderproxy.transact. Das bedeutet, dass ein Binder-Aufruf stattfindet. Nach diesen beiden Zeilen sehen Sie die aufgerufene Binder API. Im folgenden Beispiel wird IAccessibilityManager.addClient aufgerufen.

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

Viele aufeinanderfolgende Binder-Aufrufe

Viele aufeinanderfolgende Binderaufrufe in einer engen Schleife können einen Thread für einen langen Zeitraum blockieren.

Eine blockierende E/A

Blockieren Sie nie E/A-Vorgänge im Hauptthread. Dies ist ein Antimuster.

Konflikt durch Sperre

Wenn ein Thread blockiert wird, wenn eine Sperre eingerichtet wird, kann dies zu einem ANR-Fehler führen.

Das folgende Beispiel zeigt, dass der Hauptthread beim Versuch, eine Sperre abzurufen, blockiert wird:

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

Der blockierende Thread sendet eine HTTP-Anfrage zum Herunterladen eines Videos:

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

Teurer Frame

Wenn zu viele Elemente in einem einzelnen Frame gerendert werden, kann der Hauptthread während der Dauer des Frames nicht mehr reagieren. Beispiel:

  • Es werden viele unnötige Elemente außerhalb des Bildschirms gerendert.
  • Verwendung eines ineffizienten Algorithmus wie O(n^2) zum Rendern vieler UI-Elemente.

Von anderer Komponente blockiert

Wenn eine andere Komponente, z. B. ein Broadcast-Empfänger, den Hauptthread mehr als fünf Sekunden lang blockiert, kann dies zu ANR-Fehlern bei der Eingabe und einer erheblichen Verzögerung führen.

Vermeiden Sie aufwendige Arbeiten am Hauptthread in Anwendungskomponenten. Führen Sie Broadcast-Empfänger nach Möglichkeit in einem anderen Thread aus.