Android – wie untersuche ich eine ANR?

Lesezeit: 11 Minuten

Android – wie untersuche ich eine ANR
lostInTransit

Gibt es eine Möglichkeit herauszufinden, wo meine App einen ANR (Application Not Responding) ausgegeben hat? Ich habe mir die Datei traces.txt in /data angesehen und sehe einen Trace für meine Anwendung. Das sehe ich im Trace.

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 <0x1cd570> (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 -----

Wie kann ich herausfinden, wo das Problem liegt? Die Methoden im Trace sind alle SDK-Methoden.

  • Ich habe einen Bericht dieser Art, der auch bei passiert android.os.MessageQueue.nativePollOnce(Native Method). Kann ich es bedenkenlos ignorieren?

    – rts

    20. Juni 2012 um 12:00 Uhr

Ein ANR tritt auf, wenn im “Haupt”-Thread eine lange Operation stattfindet. Dies ist der Thread der Ereignisschleife, und wenn er beschäftigt ist, kann Android keine weiteren GUI-Ereignisse in der Anwendung verarbeiten und wirft daher einen ANR-Dialog aus.

Nun, in der von Ihnen geposteten Ablaufverfolgung scheint der Hauptthread gut zu funktionieren, es gibt kein Problem. Es befindet sich im Leerlauf in der MessageQueue und wartet auf das Eintreffen einer weiteren Nachricht. In Ihrem Fall war die ANR wahrscheinlich eine längere Operation und nicht etwas, das den Thread dauerhaft blockierte, sodass der Ereignis-Thread nach Abschluss der Operation wiederhergestellt wurde und Ihre Ablaufverfolgung durchlief nach ANR.

Es ist einfach zu erkennen, wo ANRs auftreten, wenn es sich um eine dauerhafte Blockierung handelt (z. B. ein Deadlock, der einige Sperren erwirbt), aber schwieriger, wenn es sich nur um eine vorübergehende Verzögerung handelt. Gehen Sie zuerst Ihren Code durch und suchen Sie nach Schwachstellen und lang andauernden Vorgängen. Beispiele können die Verwendung von Sockets, Sperren, Thread-Ruhezuständen und anderen Blockierungsvorgängen innerhalb des Ereignis-Threads umfassen. Sie sollten sicherstellen, dass dies alles in separaten Threads geschieht. Wenn nichts das Problem zu sein scheint, verwenden Sie DDMS und aktivieren Sie die Thread-Ansicht. Dies zeigt alle Threads in Ihrer Anwendung ähnlich der Ablaufverfolgung, die Sie haben. Reproduzieren Sie die ANR und aktualisieren Sie gleichzeitig den Hauptthread. Das sollte Ihnen genau zeigen, was zur Zeit des ANR vor sich ging

  • Das einzige Problem ist “ANR reproduzieren” 🙂 . Könnten Sie bitte erklären, wie der Hauptthread dieser Stack-Trace-Show “im Leerlauf” ist, das wäre großartig.

    – Blundell

    30. März 2011 um 11:53 Uhr


  • Der Stack-Trace zeigt, dass sich der Haupt-Thread im Looper (der Nachrichtenschleifenimplementierung) befindet und eine zeitgesteuerte Wartezeit durch Object.wait durchführt. Dies bedeutet, dass die Nachrichtenschleife derzeit keine Nachrichten zu versenden hat und auf den Eingang neuer Nachrichten wartet. Ein ANR tritt auf, wenn das System erkennt, dass eine Nachrichtenschleife zu viel Zeit mit der Verarbeitung einer Nachricht und nicht mit der Verarbeitung anderer Nachrichten in der Schleife verbringt Warteschlange. Wenn die Schleife auf Nachrichten wartet, geschieht dies offensichtlich nicht.

    – bald

    31. März 2011 um 18:25 Uhr

  • @Soonil Hallo, wissen Sie, was der Rest der Abschnitte bedeutet, wie z. Außerdem enthält es Informationen wie VMWAIT, RUNNABLE, NATIVE

    – minhaz

    27. Februar 2012 um 19:39 Uhr


  • Meine App ist NDK-basiert, ich sehe das gleiche ANR. Auch der Hauptfaden ist in Ordnung. Ich habe DDMS ausprobiert und meinen Worker-Thread aktualisiert, wenn er einfriert. Leider bekomme ich nur eine einzige Zeile NativeStart::run. Ist die DDMS-Threadansicht überhaupt in der Lage, native NDK-Threads zu inspizieren? Außerdem: StrictMode hat nichts gefunden.

    – Bram

    20. Dezember 2012 um 21:28 Uhr

  • Sehen ellioth.blogspot.com/2012/08/… für eine gute Erklärung der Ausgabe.

    – bald

    11. Mai 2013 um 18:36 Uhr

Android – wie untersuche ich eine ANR
Dheeraj Vepakomma

Sie können aktivieren Strikter Modus in API-Level 9 und höher.

StrictMode wird am häufigsten verwendet, um versehentliche Festplatten- oder Netzwerkzugriffe im Hauptthread der Anwendung abzufangen, wo UI-Vorgänge empfangen und Animationen stattfinden. Indem Sie den Haupt-Thread Ihrer Anwendung reaktionsfähig halten, tun Sie das auch ANR-Dialoge verhindern Benutzern nicht angezeigt werden.

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

verwenden penaltyLog() Sie können die Ausgabe von adb logcat beobachten, während Sie Ihre Anwendung verwenden, um die Verstöße zu sehen, während sie auftreten.

  • StrictMode kann nicht in einen Typ aufgelöst werden. Muss ich vorher etwas importieren? Das Drücken von STRG+UMSCHALT+O hilft nicht.

    – kuchi

    24. Januar 2012 um 4:41 Uhr

  • Kleiner Tipp – verwenden Sie if (BuildConfig.DEBUG) … um die Aufnahme in die Produktion zu verhindern

    – Amir Uwal

    14. November 2013 um 14:12 Uhr

  • @uval was meinst du mit “um die Aufnahme in die Produktion zu verhindern” ?!!

    – Muhammed Refaat

    1. April 2015 um 13:49 Uhr

  • @MuhammedRefaat es verhindert keine ANR. Es stürzt die App sofort statt nach 5 Sekunden ab. Wenn Sie beispielsweise im Hauptthread auf die Datenbank zugreifen und es 2 Sekunden dauert, erhalten Sie kein ANR, aber StrictMode stürzt die App ab. StrictMode ist ausschließlich für Ihre Debugging-Phase, nicht für die Produktion.

    – Amir Uwal

    2. April 2015 um 11:31 Uhr


  • @MuhammedRefaat hat meine Antwort auf Ihre Frage hinzugefügt.

    – Amir Uwal

    4. April 2015 um 9:37 Uhr

Sie fragen sich, welche Aufgabe einen UI-Thread enthält. Trace-Datei gibt Ihnen einen Hinweis, um die Aufgabe zu finden. Sie müssen den Status jedes Threads untersuchen

Zustand des Threads

  • running – Ausführen von Anwendungscode
  • schlafend – genannt Thread.sleep()
  • monitor – wartet darauf, eine Monitorsperre zu erwerben
  • warte – in Object.wait()
  • native – Ausführen von nativem Code
  • vmwait – Warten auf eine VM-Ressource
  • Zombie – Thread ist im Begriff zu sterben
  • init – Thread wird initialisiert (Sie sollten dies nicht sehen)
  • Starting – Thread beginnt gleich (sollten Sie auch nicht sehen)

Konzentrieren Sie sich auf den Zustand SUSPENDED, MONITOR. Der Überwachungsstatus gibt an, welcher Thread untersucht wird, und der Status SUSPENDED des Threads ist wahrscheinlich der Hauptgrund für Deadlocks.

Grundlegende Untersuchungsschritte

  1. Finden Sie “Warten auf Sperre”
    • Sie können den Monitorstatus finden “Binder Thread #15” prio=5 tid=75 MONITOR
    • Sie haben Glück, wenn Sie “waiting to lock” finden
    • Beispiel: Warten auf Sperren von <0xblahblah> (ein com.foo.A), das von threadid=74 gehalten wird
  2. Sie können feststellen, dass “tid=74” jetzt eine Aufgabe enthält. Gehen Sie also zu tid=74
  3. tid=74 möglicherweise SUSPENDIERTER Zustand! Hauptgrund finden!

Trace enthält nicht immer “waiting to lock”. In diesem Fall ist es schwierig, den Hauptgrund zu finden.

  • Schöne Erklärung. Jetzt ist es für mich einfacher, ANR-Protokolle zu verstehen. Aber ich habe immer noch ein Problem zu verstehen, weil ich in Schritt 1 die Thread-ID leicht finden kann, aber wenn ich in Schritt 2 versuche, dorthin zu gehen, wo sie ist, um den Status zu überprüfen, kann ich sie nicht finden . Irgendeine Idee, wie es weitergeht?

    – THZ

    23. November 2018 um 14:09 Uhr

  • Ich habe - waiting to lock an unknown object Innerhalb "HeapTaskDaemon" daemon prio=5 tid=8 Blocked . Was bedeutet kann jemand helfen?

    – Hilal

    10. Dezember 2019 um 13:44 Uhr


Ich habe in den letzten Monaten Android gelernt, bin also weit davon entfernt, ein Experte zu sein, aber ich war wirklich enttäuscht von der Dokumentation zu ANRs.

Die meisten Ratschläge scheinen darauf ausgerichtet zu sein, sie zu vermeiden oder zu beheben, indem Sie Ihren Code blind durchsehen, was großartig ist, aber ich konnte nichts zur Analyse der Ablaufverfolgung finden.

Es gibt drei Dinge, auf die Sie bei ANR-Protokollen wirklich achten müssen.

1) Deadlocks: Wenn sich ein Thread im WAIT-Zustand befindet, können Sie die Details durchsehen, um herauszufinden, von wem er „gehalten“ wird. Meistens wird es von selbst gehalten, aber wenn es von einem anderen Faden gehalten wird, ist das wahrscheinlich ein Gefahrenzeichen. Sehen Sie sich diesen Thread an und sehen Sie, was er hält. Möglicherweise finden Sie eine Schleife, die ein klares Zeichen dafür ist, dass etwas schief gelaufen ist. Das ist ziemlich selten, aber es ist der erste Punkt, denn wenn es passiert, ist es ein Albtraum

2) Haupt-Thread wartet: Wenn sich Ihr Haupt-Thread im WAIT-Zustand befindet, überprüfen Sie, ob er von einem anderen Thread gehalten wird. Dies sollte nicht passieren, da Ihr UI-Thread nicht von einem Hintergrundthread gehalten werden sollte.

Beide Szenarien bedeuten, dass Sie Ihren Code erheblich überarbeiten müssen.

3) Schwerwiegende Operationen im Hauptthread: Dies ist die häufigste Ursache für ANRs, aber manchmal eine der schwieriger zu findenden und zu behebenden. Sehen Sie sich die Details des Hauptthreads an. Scrollen Sie im Stack-Trace nach unten, bis Sie Klassen sehen, die Sie erkennen (aus Ihrer App). Sehen Sie sich die Methoden im Trace an und finden Sie heraus, ob Sie an diesen Stellen Netzwerkaufrufe, DB-Aufrufe usw. tätigen.

Schließlich, und ich entschuldige mich dafür, dass ich meinen eigenen Code schamlos eingefügt habe, können Sie den Python-Protokollanalysator verwenden, bei dem ich geschrieben habe https://github.com/HarshEvilGeek/Android-Log-Analyzer Dies durchsucht Ihre Protokolldateien, öffnet ANR-Dateien, findet Deadlocks, findet wartende Haupt-Threads, findet nicht erfasste Ausnahmen in Ihren Agentenprotokollen und druckt alles relativ leicht lesbar auf dem Bildschirm aus. Lesen Sie die ReadMe-Datei (die ich gleich hinzufügen werde), um zu erfahren, wie Sie sie verwenden. Es hat mir in der letzten Woche sehr geholfen!

Wann immer Sie Timing-Probleme analysieren, hilft das Debuggen oft nicht, da das Einfrieren der App an einem Haltepunkt das Problem verschwinden lässt.

Am besten fügen Sie viele Protokollierungsaufrufe (Log.XXX()) in die verschiedenen Threads und Rückrufe der App ein und sehen, wo die Verzögerung liegt. Wenn Sie einen Stacktrace benötigen, erstellen Sie eine neue Ausnahme (instanziieren Sie einfach eine) und protokollieren Sie sie.

  • Vielen Dank für den Hinweis zum Erstellen einer neuen Ausnahme, wenn Sie einen Stacktrace benötigen. Das ist sehr hilfreich beim Debuggen 🙂

    – kuchi

    24. Januar 2012 um 4:43 Uhr

1646258592 54 Android – wie untersuche ich eine ANR
Jack

Was löst ANR aus?

Im Allgemeinen zeigt das System eine ANR an, wenn eine Anwendung nicht auf Benutzereingaben reagieren kann.

In jeder Situation, in der Ihre App einen potenziell langwierigen Vorgang ausführt, sollten Sie die Arbeit nicht im UI-Thread ausführen, sondern stattdessen einen Worker-Thread erstellen und dort den größten Teil der Arbeit erledigen. Dies hält den UI-Thread (der die Ereignisschleife der Benutzeroberfläche steuert) am Laufen und verhindert, dass das System zu dem Schluss kommt, dass Ihr Code eingefroren ist.

Wie man ANRs vermeidet

Android-Anwendungen werden normalerweise vollständig auf einem einzigen Thread ausgeführt, standardmäßig dem „UI-Thread“ oder „Haupt-Thread“). Dies bedeutet, dass alles, was Ihre Anwendung im UI-Thread tut, was lange dauert, den ANR-Dialog auslösen kann, da Ihre Anwendung sich selbst keine Chance gibt, das Eingabeereignis oder die Intent-Broadcasts zu verarbeiten.

Daher sollte jede Methode, die im UI-Thread ausgeführt wird, in diesem Thread so wenig Arbeit wie möglich leisten. Insbesondere sollten Aktivitäten so wenig wie möglich in wichtigen Lebenszyklusmethoden wie onCreate() und onResume() eingerichtet werden. Potenziell lang andauernde Operationen wie Netzwerk- oder Datenbankoperationen oder rechenintensive Berechnungen wie die Größenänderung von Bitmaps sollten in einem Worker-Thread (oder im Fall von Datenbankoperationen über eine asynchrone Anforderung) durchgeführt werden.

Code: Worker-Thread mit der AsyncTask-Klasse

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
    // 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");
    }
}

Code: Worker-Thread ausführen

Um diesen Worker-Thread auszuführen, erstellen Sie einfach eine Instanz und rufen Sie execute() auf:

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

Quelle

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

  • Vielen Dank für den Hinweis zum Erstellen einer neuen Ausnahme, wenn Sie einen Stacktrace benötigen. Das ist sehr hilfreich beim Debuggen 🙂

    – kuchi

    24. Januar 2012 um 4:43 Uhr

Sie müssen nach “waiting to lock” suchen /data/anr/traces.txt Datei

Geben Sie hier die Bildbeschreibung ein

für mehr Details: Engineer for High Performance mit Tools von Android & Play (Google I/O ’17)

916580cookie-checkAndroid – wie untersuche ich eine ANR?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy