ANR이란 무엇인가?
Application Not Responding의 약자이다. 단어 그대로, 어플리케이션이 응답하지 않는 경우 안드로이드 시스템에서 보여주는 에러이다. 메인 스레드(일명, UI 스레드)가 일정시간 동안 잡혀 있으면 발생한다.
언제 ANR이 발생하는가?
안드로이드 운영체제는 홈페이지 정리가 매우 잘 되어 있다. ANR의 경우는 여기에 정리되어 있는데,
- 터치를 통한 사용자 입력이 5초 내에 처리되지 않았을 때
- 브로드캐스트가 10초 내에 처리되지 않았을 때
가 나와있다. 하지만 여기에 나오지 않은 경우가 하나 더 있다.
- 서비스가 20초 내로 처리되지 않을 때
안드로이드는 UI가 없는 컴포넌트인 브로드캐스트 리시버와 서비스도 메인 스레드에서 돌아가기 때문에 당연히 서비스에서도 시간 소모성 작업을 하는 경우 ANR이 발생할 수 있다.
왜 ANR이 발생하는가?
위의 ANR이 발생하는 조건을 보면 알겠지만, 앱이 무한 루프에 빠지거나 OOM(Out Of Memory)가 나야 ANR이 발생하는 것이 아니다. 시간이 좀 걸리는 처리를 해도 ANR이 충분히 발생할 수 있다. 그래서, 나처럼 자바프로그래밍에서 안드로이드로 온 사람에게는 한참동안 이해가 안될 수도 있다.
ANR이 필요한가?
ANR이 필요한 이유는 무엇인가? 내 생각에 이 부분을 이해하기 위해서는 사용자가 어떤 경우 문제가 있다고 느끼는가에 대한 것을 먼저 생각해야한다. 지금 대부분의 어플리케이션에서 사용하고 있는 프로그레스바를 생각하면 쉽다. 사용자에게 ‘움직이고 있다.’라는 사인을 주면 사용자는 기다린다. 하지만, 일명 먹통이 되면 사용자는 문제가 있다고 판단하여 전원을 끈다던가 다른 자신이 할 수 있는 해결책을 시도하는 것이다. 모바일 OS는 화면이 작아, 대부분(테블릿은 화면이 크고, 안드로이드에서 지원하는 프레그먼트는 한 화면에 여러개의 액티비티를 동작하게 할 수도 있다.)은 전체 화면을 차지한다. 이 때 화면이 정지한다면 정상적으로 동작하고 있음에도 문제가 있다고 느낄 수 있는 것이다.
그럼 어떻게 ANR을 관리해야 할까?
안드로이드 개발자 사이트를 참조해야할 질문이다. 여기에 잘 정리되어 있다. 간단히 요약하면,
- 시간이 오래걸리는 작업은 스레드를 통해 처리하도록 권장한다.
- 사용자에게는 프로그레스바 등을 이용해 진행 과정을 안내해 기다리도록 한다.
- 이를 위해, 안드로이드에서 상속받아 사용할 수 있는 다양한 방법을 제공하고 있다.
dumpstate에서 ANR의 원인을 분석하고 싶다면?
SYSTEM LOG에서 ActivityManager가 ANR 메시지를 표시하지 않는지 살펴보자. “ANR in”으로 검색하면 된다.
12-31 11:28:40.489 3574 3627 E ActivityManager: ANR in com.androd.calendar (com.android.calendar/.MainActivity) ... 12-31 11:28:40.489 3574 3627 E ActivityManager: Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago. Wait queue length: 58. Wait queue head age: 20502.0ms.) ... 12-31 11:28:40.489 3574 3627 E ActivityManager: CPU usage from 4928ms to 328ms ago: ...
문제가 발생한 곳의 위치가 표시되고, 이유와 함께 CPU 사용량도 표시된다.
SYSTEM LOG에서 “SIG: 9″를 검색해 보자. 이는 시스템에서 ANR을 발생시키는 프로세스를 종료하기 위해 SIGNAL_KILL을 호출되면서 남기는 로그일 수 있다. 그 부분의 전후 로그를 살펴보자. ANR이라고 판단한 이유가 로그로 남아있을 수 있다.
EVENT LOG에서 “am_anr” 태그로 검색해 보자. anr이 발생한 어플리케이션 정보를 얻을 수 있다.
12-31 11:28:40.489 3574 3627 I am_anr : [0,3669,com.android.calendar,952647237,Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago. Wait queue length: 58. Wait queue head age: 20502.0ms.)]
문제가 발생한 패키지 명과 PID, 이유가 표시된다.
DUMP OF SERVICE… 의 VM TRACES AT LAST ANR 부분에도 살펴보자. 문제가 없는 경우라면 다음 처럼 아무 내용이 없다.
... WINDOW MANAGER LAST ANR (dumpsys window lastanr) <no ANR has occurred since boot> ...
하지만, ANR이 발생한 경우에는 아래와 같이 앱 정보부터 시작하여 실행 당시의 콜스택이 남아있다.
------ VM TRACES AT LAST ANR (/data/anr/traces.txt: 2017-01-22 01:48:03) ------ ----- pid 16287 at 2017-01-22 01:47:25 ----- Cmd line: com.facebook.orca ...
콜 스택을 확인할 때에는 “main” 스레드부터 찾자. 글의 초반에 설명했듯이 ANR의 원인이 메인 스레드(일명 UI 스레드)이 오랫동안 바쁜 경우이므로 “main” 스레드 정보를 먼저 확인해야 한다. 특히, TIMED_WAIT나 MONITOR 에 있는지 확인하자.
그 밖에
ANR이 Activity Manager나 Window Manager 같은 곳에서 발생한 경우는 “어플리케이션이 응답이 없습니다. 기다리시겠습니까?”와 같은 메시지가 표시되지 않을 수 있다.
참조