This document shows how to identify the unresponsive thread in an ANR stack dump. The unresponsive thread varies by type of ANR, as shown in the following table.
|ANR type||Unresponsive thread|
|Input dispatch||Main thread|
|Input dispatch no focused window||Main thread. This type of ANR isn't usually caused by a blocked thread.|
|Broadcast receiver (synchronous)||Thread running
|Broadcast receiver (asynchronous)||Check the code to see which thread or thread pool is responsible for
doing the work to process the broadcast after
|Executing service timeout||Main thread|
|Foreground service start||Main thread|
|Content provider not responding||Either:
|No response to
Sometimes the thread is unresponsive due to a root cause in a different thread or process. The thread can be unresponsive due to waiting on the following:
- A lock held by a different thread.
- A slow binder call to a different process.
Common causes of unresponsive threads
The following are common causes of unresponsive threads.
Slow binder call
Although most binder calls are quick, the long tail can be very slow. This is more likely to happen if the device is loaded or the binder reply thread is slow, such as from lock contention, many incoming binder calls, or hardware abstraction layer (HAL) timeout.
You can solve this by moving synchronous binder calls to background threads wherever possible. If the call must happen on the main thread, find out why the call is slow. The best way to do this is from Perfetto traces.
Binderproxy.transact in the stacks.
This means a binder call is taking place. Following these two lines, you can see
the binder API that is called. In the following example, the call is to
main tid=123 ... android.os.BinderProxy.transactNative (Native method) android.os.BinderProxy.transact (BinderProxy.java:568) android.view.accessibility.IAccessibilityManager$Stub$Proxy.addClient (IAccessibilityManager.java:599) ...
Many consecutive binder calls
Performing many consecutive binder calls in a tight loop can block a thread for a long period.
A blocking I/O
Never perform blocking I/O on the main thread. This is an antipattern.
If a thread is blocked when acquiring a lock, it can result in an ANR.
The following example shows the main thread is blocked when trying to acquire a lock:
main (tid=1) Blocked Waiting for com.example.android.apps.foo.BarCache (0x07d657b7) held by ptz-rcs-28-EDITOR_REMOTE_VIDEO_DOWNLOAD [...] at android.app.ActivityThread.handleStopActivity(ActivityThread.java:5412) [...]
The blocking thread is making a HTTP request to download a video:
ptz-rcs-28-EDITOR_REMOTE_VIDEO_DOWNLOAD (tid=110) Waiting at jdk.internal.misc.Unsafe.park(Native method:0) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:715) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1047) at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:230) at com.example.android.apps.foo.HttpRequest.execute(HttpRequest:136) at com.example.android.apps.foo$Task$VideoLoadTask.downloadVideoToFile(RequestExecutor:711) [...]
Rendering too many things in a single frame can cause the main thread to be unresponsive for the duration of the frame, such as the following:
- Rendering many unnecessary off-screen items.
- Using an inefficient algorithm, such as
O(n^2), when rendering many UI elements.
Blocked by other component
If another component, such as a broadcast receiver, blocks the main thread for more than five seconds, it can cause input dispatch ANRs and serious jank.
Avoid doing any heavy work on the main thread in app components. Run broadcast receivers on a different thread wherever possible.