Android - how do I investigate an ANR?
You can enable StrictMode in API level 9 and above.
StrictMode is most commonly used to catch accidental disk or network access on the application's main thread, where UI operations are received and animations take place. By keeping your application's main thread responsive, you also prevent ANR dialogs from being shown to users.
public void onCreate() {
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.penaltyDeath()
.build());
super.onCreate();
}
using
penaltyLog()
you can watch the output of adb logcat while you use your application to see the violations as they happen.
An ANR happens when some long operation takes place in the "main" thread. This is the event loop thread, and if it is busy, Android cannot process any further GUI events in the application, and thus throws up an ANR dialog.
Now, in the trace you posted, the main thread seems to be doing fine, there is no problem. It is idling in the MessageQueue, waiting for another message to come in. In your case the ANR was likely a longer operation, rather than something that blocked the thread permanently, so the event thread recovered after the operation finished, and your trace went through after the ANR.
Detecting where ANRs happen is easy if it is a permanent block (deadlock acquiring some locks for instance), but harder if it's just a temporary delay. First, go over your code and look for vunerable spots and long running operations. Examples may include using sockets, locks, thread sleeps, and other blocking operations from within the event thread. You should make sure these all happen in separate threads. If nothing seems the problem, use DDMS and enable the thread view. This shows all the threads in your application similar to the trace you have. Reproduce the ANR, and refresh the main thread at the same time. That should show you precisely whats going on at the time of the ANR
You are wondering which task hold a UI Thread. Trace file gives you a hint to find the task. you need investigate a state of each thread
State of thread
- running - executing application code
- sleeping - called Thread.sleep()
- monitor - waiting to acquire a monitor lock
- wait - in Object.wait()
- native - executing native code
- vmwait - waiting on a VM resource
- zombie - thread is in the process of dying
- init - thread is initializing (you shouldn't see this)
- starting - thread is about to start (you shouldn't see this either)
Focus on SUSPENDED, MONITOR state. Monitor state indicates which thread is investigated and SUSPENDED state of the thread is probably main reason for deadlock.
Basic investigate steps
- Find "waiting to lock"
- you can find monitor state "Binder Thread #15" prio=5 tid=75 MONITOR
- you are lucky if find "waiting to lock"
- example : waiting to lock <0xblahblah> (a com.foo.A) held by threadid=74
- You can notice that "tid=74" hold a task now. So go to tid=74
- tid=74 maybe SUSPENDED state! find main reason!
trace does not always contain "waiting to lock". in this case it is hard to find main reason.