IT박스

Android-ANR은 어떻게 조사합니까?

itboxs 2020. 6. 17. 19:20
반응형

Android-ANR은 어떻게 조사합니까?


내 앱에서 ANR (응용 프로그램이 응답하지 않음)을 던진 위치를 찾는 방법이 있습니까? / data의 traces.txt 파일을 살펴본 결과 내 응용 프로그램에 대한 추적이 표시됩니다. 이것이 내가 추적에서 보는 것입니다.

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

문제가 어디에 있는지 어떻게 알 수 있습니까? 추적의 메소드는 모두 SDK 메소드입니다.

감사.


"메인"스레드에서 약간의 긴 작업이 수행 될 때 ANR이 발생합니다. 이것은 이벤트 루프 스레드이며, 사용중인 경우 Android는 애플리케이션에서 더 이상 GUI 이벤트를 처리 할 수 ​​없으므로 ANR 대화 상자를 발생시킵니다.

자, 당신이 게시 한 추적에서 주 스레드가 정상적으로 작동하는 것 같습니다. 문제가 없습니다. MessageQueue에서 유휴 상태가되어 다른 메시지가 들어 오기를 기다리고 있습니다. ANR이 스레드를 영구적으로 차단 한 것보다 더 긴 작업 일 가능성이 있으므로 작업이 완료된 후 이벤트 스레드가 복구되고 추적이 진행되었습니다. ANR 후.

영구 블록 (예를 들어 교착 상태를 획득하는 교착 상태) 인 경우 ANR이 발생하는 위치를 감지하는 것은 쉽지만 일시적인 지연 일 경우에는 더 어렵습니다. 먼저 코드를 살펴보고 취약한 지점과 장기 실행 작업을 찾으십시오. 예를 들어 이벤트 스레드 내에서 소켓, 잠금, 스레드 휴면 및 기타 차단 작업을 사용할 수 있습니다. 이 모든 것이 별도의 스레드에서 발생하는지 확인해야합니다. 문제가없는 것 같으면 DDMS를 사용하고 스레드보기를 활성화하십시오. 추적 결과와 유사한 애플리케이션의 모든 스레드가 표시됩니다. ANR을 재현하고 동시에 메인 스레드를 새로 고칩니다. ANR 시점에 무슨 일이 일어나고 있는지 정확하게 보여 주어야합니다.


API 레벨 9 이상에서 StrictMode사용할 수 있습니다 .

엄격 모드는 UI 작업이 수신되고 애니메이션이 발생하는 응용 프로그램의 메인 스레드에서 우발적 인 디스크 또는 네트워크 액세스를 포착하는 데 가장 일반적으로 사용됩니다. 응용 프로그램의 기본 스레드를 반응 적으로 유지 하면 ANR 대화 상자 가 사용자에게 표시되지 않습니다.

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

를 사용 penaltyLog()하면 응용 프로그램을 사용하여 위반이 발생할 때 adb logcat의 출력을 볼 수 있습니다.


어떤 작업이 UI 스레드를 보유하는지 궁금합니다. 추적 파일은 작업을 찾는 힌트를 제공합니다. 각 스레드의 상태를 조사해야합니다.

실 상태

  • 실행 중-애플리케이션 코드 실행
  • 수면-Thread.sleep ()
  • 모니터-모니터 잠금 획득 대기
  • wait-Object.wait ()에서
  • native-네이티브 코드 실행
  • vmwait-VM 자원 대기
  • 좀비-실이 죽어 가고있다
  • init-스레드가 초기화 중입니다 (이것을 보지 않아야합니다)
  • 시작-스레드가 시작됩니다 (이것도 보지 않아야합니다)

SUSPENDED, MONITOR 상태에 중점을 둡니다. 모니터 상태는 어떤 스레드를 조사했는지를 나타내며 스레드의 SUSPENDED 상태는 교착 상태의 주요 원인 일 수 있습니다.

기본 조사 단계

  1. "잠금 대기 중"찾기
    • 모니터 상태 "바인더 스레드 # 15"를 찾을 수 있습니다. prio = 5 tid = 75 MONITOR
    • "잠금 대기"를 찾으면 운이 좋다
    • 예 : threadid = 74가 보유한 <0xblahblah> (com.foo.A) 잠금 대기 중
  2. "tid = 74"는 이제 작업을 보유하고 있음을 알 수 있습니다. tid = 74로 가십시오
  3. tid = 74 아마도 일시 중단 된 상태입니다! 주된 이유를 찾으십시오!

추적에 항상 "잠금 대기 중"이 포함되는 것은 아닙니다. 이 경우 주된 이유를 찾기가 어렵습니다.


나는 지난 몇 개월 동안 안드로이드를 배웠으므로 전문가와는 거리가 멀지 만 ANR에 대한 문서에 정말 실망했습니다.

대부분의 조언은 코드를 맹목적으로 살펴봄으로써 코드를 피하거나 수정하는 데 도움이되는 것 같습니다.하지만 추적을 분석 할 때 아무것도 찾을 수 없습니다.

ANR 로그에서 실제로 찾아야 할 세 가지가 있습니다.

1) 교착 상태 : 스레드가 WAIT 상태 인 경우 세부 정보를 통해 누가 "heldby ="인지 확인할 수 있습니다. 대부분 자체적으로 유지되지만 다른 스레드에 의해 유지되는 경우 위험 신호일 수 있습니다. 그 실을보고 그것이 무엇을 가지고 있는지보십시오. 루프가 발견 될 수 있는데, 이는 무언가 잘못되었다는 명백한 신호입니다. 이것은 매우 드문 일이지만 그것이 일어날 때 악몽이기 때문에 첫 번째 요점입니다.

2) 메인 스레드 대기 : 메인 스레드가 WAIT 상태 인 경우 다른 스레드에 의해 고정되어 있는지 확인하십시오. UI 스레드가 백그라운드 스레드에 의해 유지되어서는 안되기 때문에 이런 일이 발생하지 않아야합니다.

이 두 시나리오 모두 코드를 크게 재 작업해야한다는 것을 의미합니다.

3) 메인 스레드에서의 과도한 작업 : 이것이 ANR의 가장 일반적인 원인이지만 때로는 찾아서 수정하기 어려운 것 중 하나입니다. 주요 스레드 세부 사항을보십시오. 스택 추적을 아래로 스크롤하여 앱에서 인식하는 클래스가 표시 될 때까지 스크롤합니다. 추적에서 메소드를보고이 위치에서 네트워크 호출, db 호출 등을 작성하는지 확인하십시오.

Finally, and I apologize for shamelessly plugging my own code, you can use the python log analyzer I wrote at https://github.com/HarshEvilGeek/Android-Log-Analyzer This will go through your log files, open ANR files, find deadlocks, find waiting main threads, find uncaught exceptions in your agent logs and print it all out on the screen in a relatively easy to read manner. Read the ReadMe file (which I'm about to add) to learn how to use it. It's helped me a ton in the last week!


Whenever you're analyzing timing issues, debugging often does not help, as freezing the app at a breakpoint will make the problem go away.

Your best bet is to insert lots of logging calls (Log.XXX()) into the app's different threads and callbacks and see where the delay is at. If you need a stacktrace, create a new Exception (just instantiate one) and log it.


What Triggers ANR?

Generally, the system displays an ANR if an application cannot respond to user input.

In any situation in which your app performs a potentially lengthy operation, you should not perform the work on the UI thread, but instead create a worker thread and do most of the work there. This keeps the UI thread (which drives the user interface event loop) running and prevents the system from concluding that your code has frozen.

How to Avoid ANRs

Android applications normally run entirely on a single thread by default the "UI thread" or "main thread"). This means anything your application is doing in the UI thread that takes a long time to complete can trigger the ANR dialog because your application is not giving itself a chance to handle the input event or intent broadcasts.

Therefore, any method that runs in the UI thread should do as little work as possible on that thread. In particular, activities should do as little as possible to set up in key life-cycle methods such as onCreate() and onResume(). Potentially long running operations such as network or database operations, or computationally expensive calculations such as resizing bitmaps should be done in a worker thread (or in the case of databases operations, via an asynchronous request).

Code: Worker thread with the AsyncTask class

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: Execute Worker thread

To execute this worker thread, simply create an instance and call execute():

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

Source

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


my issue with ANR , after much work i found out that a thread was calling a resource that did not exist in the layout, instead of returning an exception , i got ANR ...


You need to look for "waiting to lock" in /data/anr/traces.txt file

enter image description here

for more details: Engineer for High Performance with Tools from Android & Play (Google I/O '17)


Basic on @Horyun Lee answer, I wrote a small python script to help to investigate ANR from traces.txt.

The ANRs will output as graphics by graphviz if you have installed grapvhviz on your system.

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

A png will output like below if there are ANRs detected in file traces.txt. It's more intuitive.

enter image description here

The sample traces.txt file used above was get from here.


Consider using the ANR-Watchdog library to accurately track and capture ANR stack traces in a high level of detail. You can then send them to your crash reporting library. I recommend using setReportMainThreadOnly() in this scenario. You can either make the app throw a non-fatal exception of the freeze point, or make the app force quit when the ANR happens.

Note that the standard ANR reports sent to your Google Play Developer console are often not accurate enough to pinpoint the exact problem. That's why a third-party library is needed.

참고URL : https://stackoverflow.com/questions/704311/android-how-do-i-investigate-an-anr

반응형