webentwicklung-frage-antwort-db.com.de

Android - Wie untersuche ich einen ANR?

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

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.

Vielen Dank.

136
lostInTransit

Eine ANR tritt auf, wenn im "main" -Thread eine lange Operation ausgeführt wird. Dies ist der Ereignisschleifenthread. Wenn er ausgelastet ist, kann Android keine weiteren GUI-Ereignisse in der Anwendung verarbeiten und gibt daher ein ANR-Dialogfeld aus.

Nun, in der von Ihnen geposteten Spur scheint der Haupt-Thread gut zu laufen, es gibt kein Problem. In MessageQueue ist es im Leerlauf und wartet darauf, dass eine weitere Nachricht eingeht. In Ihrem Fall war der ANR wahrscheinlich ein längerer Vorgang als ein Vorgang, der den Thread dauerhaft blockierte. Der Ereignisthread wurde nach Abschluss des Vorgangs wiederhergestellt und die Ablaufverfolgung durchlaufen nach dem ANR.

Das Erkennen von ANRs ist einfach, wenn es sich um eine permanente Blockierung handelt (Deadlock, die zum Beispiel Sperren abruft), aber schwieriger, wenn es sich nur um eine vorübergehende Verzögerung handelt. Gehen Sie zunächst Ihren Code durch, und suchen Sie nach geeigneten Stellen und lang andauernden Vorgängen. Beispiele können die Verwendung von Sockets, Sperren, Thread-Sleeps und anderen Blockierungsvorgängen innerhalb des Ereignisthreads umfassen. Sie sollten sicherstellen, dass dies alles in separaten Threads geschieht. Wenn das Problem nicht angezeigt wird, verwenden Sie DDMS und aktivieren Sie die Threadansicht. Dies zeigt alle Threads in Ihrer Anwendung, die der von Ihnen verwendeten Ablaufverfolgung ähnlich sind. Reproduzieren Sie den ANR und aktualisieren Sie gleichzeitig den Haupt-Thread. Das sollte Ihnen genau zeigen, was zur Zeit des ANR los ist

114
sooniln

Sie können StrictMode in API-Ebene 9 und höher aktivieren.

StrictMode wird am häufigsten verwendet, um versehentliche Festplatten oder Netzwerke abzufangen Zugriff auf den Haupt-Thread der Anwendung, wobei UI-Vorgänge .__ sind. empfangene und animationen finden statt. Durch Beibehalten des Hauptthreads Ihrer Anwendung In Reaktion darauf können Sie auch verhindern, dass ANR-Dialogfelder Benutzern angezeigt werden.

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

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

92
Dheeraj V.S.

Sie fragen sich, welche Aufgabe einen UI-Thread enthält. Die Trace-Datei enthält einen Hinweis zum Auffinden der Aufgabe. Sie müssen einen Zustand jedes Threads untersuchen 

Zustand des Gewindes

  • laufen - Ausführen von Anwendungscode
  • schlafen - genannt Thread.sleep () 
  • monitor - Warten auf eine Monitorsperre
  • warten - in Object.wait () 
  • native - Ausführen von nativem Code 
  • vmwait - Wartet auf eine Ressource VM 
  • zombie - Thread ist im Sterben 
  • init - thread wird initialisiert (das solltest du nicht sehen) 
  • start - Thread steht kurz vor dem Start (das sollte man auch nicht sehen) 

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

Grundlegende Untersuchungsschritte

  1. Suchen Sie nach "Warten auf Sperren"
    • der Monitorstatus "Binder Thread # 15" wird angezeigt. prio = 5 tid = 75 MONITOR
    • sie haben Glück, wenn Sie "warten, um zu sperren"
    • beispiel: Warten auf das Sperren von <0xblahblah> (a com.foo.A), das von threadid = 74 gehalten wird
  2. Sie können feststellen, dass "tid = 74" jetzt eine Aufgabe enthält. Also gehe zu tid = 74
  3. tid = 74 möglicherweise SUSPENDED state! Hauptgrund finden!

die Ablaufverfolgung enthält nicht immer "Warten auf Sperren". In diesem Fall ist der Hauptgrund schwer zu finden.

64
Horyun Lee

Ich habe in den letzten Monaten Android gelernt, also bin ich kein Experte, aber die Dokumentation zu ANRs hat mich wirklich enttäuscht.

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

Es gibt drei Dinge, nach denen Sie mit ANR-Protokollen wirklich suchen müssen.

1) Deadlocks: Wenn sich ein Thread im Status WAIT befindet, können Sie die Details durchsehen, um herauszufinden, wer es ist "holdby =". Die meiste Zeit wird es von alleine gehalten, aber wenn es von einem anderen Thread gehalten wird, ist dies wahrscheinlich ein Gefahrenzeichen. Schau dir den Thread an und schau, was er hält. Möglicherweise finden Sie eine Schleife, die ein deutliches Zeichen dafür ist, dass etwas schiefgelaufen ist. Das ist ziemlich selten, aber es ist der erste Punkt, denn wenn es passiert, ist es ein Albtraum

2) Main Thread Waiting: Wenn sich Ihr Haupt-Thread im Status WAIT befindet, prüfen Sie, ob er von einem anderen Thread gehalten wird. Dies sollte nicht passieren, da Ihr UI-Thread nicht von einem Hintergrund-Thread gehalten werden sollte.

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

3) Schwere Operationen am Haupt-Thread: Dies ist die häufigste Ursache für ANRs, aber manchmal eine der schwieriger zu finden und zu beheben. Schauen Sie sich die wichtigsten Thread-Details an. Scrollen Sie im Stack-Trace nach unten und bis Sie Klassen sehen, die Sie (von Ihrer App) kennen. Sehen Sie sich die Methoden in der Ablaufverfolgung an und finden Sie heraus, ob Sie an diesen Stellen Netzwerkanrufe, Datenbankanrufe usw. tätigen.

Zum Schluss, und ich entschuldige mich für das schamlose Einstecken meines eigenen Codes, können Sie den Python Log Analyzer verwenden, den ich unter https://github.com/HarshEvilGeek/Android-Log-Analyzer geschrieben habe. Dadurch werden Ihre Protokolldateien geöffnet ANR-Dateien, Deadlocks finden, wartende Haupt-Threads finden, nicht erfasste Ausnahmen in Ihren Agentenprotokollen finden und alles relativ lesbar auf dem Bildschirm ausdrucken. Lesen Sie die Readme-Datei (die ich gerade hinzufügen möchte), um zu erfahren, wie Sie sie verwenden. Es hat mir in der letzten Woche eine Menge geholfen!

Bei der Analyse von Timing-Problemen hilft das Debuggen oft nicht, da das Anhalten der App an einem Haltepunkt das Problem beseitigt.

Am besten fügen Sie viele Logging-Aufrufe (Log.XXX ()) in die verschiedenen Threads und Callbacks der App ein und sehen, wo sich die Verzögerung befindet. Wenn Sie ein Stacktrace benötigen, erstellen Sie eine neue Exception (instanziieren Sie eine) und protokollieren Sie sie.

4
Ulrich

Was löst ANR aus?

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

In jeder Situation, in der Ihre App einen möglicherweise langwierigen Vorgang ausführt, sollten Sie die Arbeit nicht an dem Benutzeroberflächenthread ausführen, sondern stattdessen einen Arbeitsthread erstellen und die meisten Aufgaben dort erledigen. Dadurch bleibt der UI-Thread (der die Benutzeroberflächen-Ereignisschleife steuert) aktiv, und das System kann nicht zu dem Schluss kommen, dass Ihr Code eingefroren ist. 

ANRs vermeiden

Android-Anwendungen laufen normalerweise vollständig in einem einzigen Thread (standardmäßig "UI-Thread" oder "Haupt-Thread"). Dies bedeutet, dass alles, was Ihre Anwendung im UI-Thread durchführt, dessen Ausführung sehr lange dauert, das ANR-Dialogfeld auslösen kann, da Ihre Anwendung sich selbst keine Möglichkeit gibt, das Eingabeereignis oder die beabsichtigten Broadcasts zu verarbeiten.

Daher sollte jede im UI-Thread ausgeführte Methode in diesem Thread so wenig wie möglich arbeiten. Insbesondere sollten Aktivitäten so wenig wie möglich zum Einrichten in wichtigen Lebenszyklusmethoden wie onCreate () und onResume () beitragen. Möglicherweise lange ausgeführte Operationen wie Netzwerk- oder Datenbankoperationen oder rechenintensive Berechnungen wie das Ändern der Größe von Bitmaps sollten in einem Arbeitsthread (oder bei Datenbankoperationen über eine asynchrone Anforderung) ausgeführt werden.

Code: Arbeitsthread 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

3
Jack

Sie müssen in der Datei /data/anr/traces.txt nach "Warten auf Sperren" suchen

 enter image description here

für weitere Details: Ingenieur für Höchstleistung mit Tools von Android & Play (Google I/O '17)

1
phnmnn

nach meiner langen Arbeit fand ich heraus, dass ein Thread eine Ressource aufrief, die im Layout nicht vorhanden war. Statt eine Ausnahme zurückzugeben, bekam ich ANR ... 

1
yaniv

Verwenden Sie die Bibliothek ANR-Watchdog , um ANR-Stack-Traces mit hoher Detailgenauigkeit zu verfolgen und zu erfassen. Sie können sie dann an Ihre Absturzberichterstellungsbibliothek senden. Ich empfehle in diesem Szenario die Verwendung von setReportMainThreadOnly(). Sie können entweder die App eine nicht schwerwiegende Ausnahme des Einfrierpunkts auslösen lassen oder die Anwendung erzwingen, wenn der ANR auftritt.

Beachten Sie, dass die ANR-Standardberichte, die an Ihre Google Play Developer Console gesendet werden, häufig nicht genau genug sind, um das genaue Problem zu ermitteln. Deshalb ist eine Bibliothek eines Drittanbieters erforderlich.

0
Mr-IDE

Grundlegend auf der Antwort von @Horyun Lee, habe ich ein kleines Python script geschrieben, um ANR aus traces.txt herauszufinden.

Die ANRs werden von graphviz als Grafik ausgegeben, wenn Sie grapvhviz auf Ihrem System installiert haben.

$ ./anr.py --format png ./traces.txt

Ein png wird wie folgt ausgegeben, wenn in der Datei traces.txt ANRs gefunden werden. Es ist intuitiver.

 enter image description here

Die oben verwendete traces.txt-Datei stammt von here .

0
alijandro