CN

Android ANR Series 3 - ANR Case Studies

Word count: 6.6kReading time: 41 min
2025/02/08
loading

This is the third article in the Android App ANR series, focusing on real-world ANR cases. The series includes:

  1. Android App ANR Series 1: Understanding Android ANR Design Philosophy
  2. Android App ANR Series 2: ANR Analysis Workflow and Key Logs
  3. Android App ANR Series 3: ANR Case Studies

Version note (reviewed October 2026): These historical cases include logs from 2020. The exact ROM/app versions and complete traces are unavailable. Rendering mechanisms are checked against android-10.0.0_r47; updates use android-15.0.0_r1 and current documentation. These source baselines do not identify the original devices’ builds. Some spacing, line endings, and timestamps are incomplete; missing values are not reconstructed.

Identify type and impact with Android Vitals or field monitoring, then align bugreports, EventLog, main/system logs, and Perfetto covering the timeout window. Direct /data/anr access requires permissions. API 30+ ApplicationExitInfo contains historical exits; traces may be missing, and exit time is not ANR start time. See part two.

The abridged 2015 quotation below is retained as historical context. Attribution to an app does not establish an app-side cause, and ANRs are not confined to the main thread. Low incidence alone does not justify ignoring a problem. Each case below distinguishes observed waits from causes that still need evidence.

ANR (Application Not Responding) is a simple definition that covers many Android system design philosophies.

First, ANR belongs to the application scope. This differs from SNR (System Not Responding), which reflects issues in the system process (system_server). SNR is managed by the Watchdog mechanism, while ANR is managed by the message handling mechanism at the system layer through message scheduling and timeout handling.

Second, the ANR mechanism is primarily implemented in the system layer. All ANR-related messages are scheduled by system_server and dispatched to the application process. The system uses various timeout limits to track message processing. If an app fails to respond within these limits, the system collects diagnostics (CPU/IO usage, thread stacks) and reports that the process is not responding.

Third, ANR is essentially a performance issue. The mechanism limits the app’s main thread, requiring it to handle common operations (starting services, processing broadcasts, input) within fixed timeframes. Time-consuming operations in the main thread (heavy calculations, heavy I/O, complex layouts) reduce responsiveness.

Finally, some ANR issues are very difficult to analyze. System-level issues like Linux kernel bugs, memory fragmentation, or hardware failures can cause message scheduling failures that are hard to reproduce and diagnose.

– From duanqz

Common Causes of ANR

For ANRs, the approach is bold hypotheses, careful checks. Pick an unusual event, suppose it caused the problem, and read the surrounding logs to test that idea. If the evidence does not support it, try another lead.

The lists below identify places to investigate. An operation is not itself an ANR: connect it to the timed-out contract. Slow Activity lifecycle work can block input and other progress; there is no single independent ANR timer for every Activity callback.

Issues Within the Current Process

  1. Deadlocks.
  2. Main thread calls thread.join(), sleep(), wait(), or waits for a thread lock.
  3. Main thread waits at nSyncAndDrawFrame for a RenderThread synchronization point.
  4. Time-consuming operations on the main thread, such as complex layouts, massive for loops, IO, etc.
  5. Main thread is blocked by a sub-thread’s synchronized lock.
  6. Main thread times out waiting for a sub-thread.
  7. Slow Activity lifecycle work delays input or the first frame.
  8. Main thread Service lifecycle method execution timeout.
  9. BroadcastReceiver.onReceive() does not return promptly, or goAsync() work does not finish its PendingResult in time.
  10. RenderThread is time-consuming.
  11. Time-consuming network access.
  12. Application reads and writes a large amount of data.
  13. Database operations.
  14. Hardware operations (such as Camera).
  15. A Binder service process’s thread pool is saturated, queuing a critical synchronous request; this is not a universal limit on Binder objects.
  16. A worker fails without completing a business-level wait condition. Ordinary Thread.join() returns when the target terminates; termination itself does not imply an indefinite join.
  17. Dump memory operations.
  18. SharedPreferences loading/writes or pending persistence work at lifecycle transitions delay a critical thread.

Issues in Remote Processes or the System

  1. Binder communication with SystemServer, and SystemServer execution is time-consuming.
    1. The method itself takes a long time to execute causing timeout.
    2. Too much lock contention in SystemServer, resulting in lock wait timeout.
  2. Timeout waiting for other processes to return, such as getting data from other processes’ ContentProvider.
  3. Window state confusion leading to Input dispatch timeout.
  4. A ContentProvider process death may fail dependent calls or affect client survival, depending on the dependency type. Process death and ANR are distinct outcomes.
  5. System-wide low memory.
  6. System-wide high CPU usage.
  7. System-wide high IO usage.
  8. SurfaceFlinger timeout.
  9. Bug in system freezing function.
  10. A system_server Watchdog timeout is a separate system-failure detector. It may coincide with app ANRs without being the same event.
  11. The device triggers thermal control frequency limitation.

ANR Case Studies

ANR Case: Toutiao - Deadlock

The reported steps were to repeatedly pull Toutiao out of the sidebar into split-screen mode. After several attempts, the app reported an ANR and its split-screen area briefly went black and stopped responding. It recovered after 4–5 seconds.

The historical heading is retained, but the excerpt establishes a main-thread wait on a LogReaper lock during exception handling, not a proven deadlock.

1
2
3
4
5
6
7
8
9
10
11
12
"main"prio=5tid=1Blocked
| group="main"sCount=1dsCount=0obj=0x74f9bbe8self=0xe7084400
| sysTid=28210nice=0cgrp=defaultsched=0/0handle=0xe9dcd534
| state=S schedstat=(13454428309928953492) utm=121stm=13core=3HZ=100
| stack=0xff3b6000-0xff3b8000stackSize=8MB
| held mutexes=
at com.ss.android.common.applog.LogReaper.insertCrashLog(SourceFile:98)
- waiting to lock <0x0d3fbd00> (a com.ss.android.common.applog.LogReaper) held by thread34
at com.ss.android.common.applog.AppLog.uncaughtException(SourceFile:1408
at u.aly.n.uncaughtException(SourceFile:34)
at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1068)
at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1063)

Waited-on lock:

1
waiting to lock <0x0d3fbd00> (a com.ss.android.common.applog.LogReaper) held by thread34

held by thread 34 is an ART tid. Find tid=34 in the same dump, not Linux TID 34; its Linux TID here is 28274.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"LogReaper"prio=5tid=34TimedWaiting
| group="main"sCount=1dsCount=0obj=0x12fcaba0self=0xcb226e00
| sysTid=28274nice=0cgrp=defaultsched=0/0handle=0xc9f9b920
| state=S schedstat=(77341565269270880) utm=7stm=0core=5HZ=100
| stack=0xc9e99000-0xc9e9b000stackSize=1038KB
| held mutexes=
at java.lang.Object.wait!(Native method)
- waiting on <0x00fc7065> (a java.util.concurrent.atomic.AtomicInteger)
at java.lang.Object.wait(Object.java:407)
at com.ss.android.action.b.d.a(SourceFile:216)
at com.ss.android.newmedia.b.onLogSessionBatchEvent(SourceFile:468)
at com.ss.android.common.applog.DBHelper.batchSession(SourceFile:616)
- locked <0x0d4ff1c4> (a com.ss.android.common.applog.DBHelper)
at com.ss.android.common.applog.LogReaper.switchSession(SourceFile:175)
at com.ss.android.common.applog.LogReaper.switchSession(SourceFile:153)
at com.ss.android.common.applog.LogReaper.processItem(SourceFile:122)
- locked <0x0d3fbd00> (a com.ss.android.common.applog.LogReaper)
at com.ss.android.common.applog.LogReaper.run(SourceFile:632)

Next wait:

1
waiting on <0x00fc7065> (a java.util.concurrent.atomic.AtomicInteger)

LogReaper holds 0x0d3fbd00 and a DBHelper monitor while calling Object.wait() on 0x00fc7065. Object.wait releases the waited-on object’s monitor, not other monitors already held. The object being an AtomicInteger does not make this a lock-free atomic operation.

Find who changes and signals the condition, whether that path needs the main thread or either held lock, and whether the timed wait can expire. A cycle or unfinishable condition is still needed to diagnose deadlock or a logical hang. The uncaughtException frames also require investigating the original exception; a blocked crash handler is not necessarily the initial fault. The reported recovery after 4–5 seconds does not prove a persistent deadlock.

ANR Case: ANR caused by Freezing

Start with the am_anr timestamp and reason. This older input dispatcher reports unfinished previously delivered input preventing further delivery. It is not NoFocusedWindow, nor proof that an app callback was actively executing.

1
05-0100:51:39.594 1449 5234I am_anr  : [0,2169,com.xxx.weather2,820526660,Input dispatching timed out (Waiting to send key event because the focused window has not finished processing all of the input events that were previously delivered to it.  Outbound queue length: 0.  Wait queue length: 1.)]

Then inspect the CPU report:

1
2
3
4
5
6
7
8
9
05-0100:51:53.974 1449 5234E ActivityManager: ANR in com.xxx.weather2 (com.xxx.weather2/com.xxx.weather.xxxMainActivity)
05-0100:51:53.974 1449 5234E ActivityManager: PID:2169
05-0100:51:53.974 1449 5234E ActivityManager: Reason:Input dispatching timed out (Waiting to send key event because the focused window has not finished processing all of the input events that were previously delivered to it. Outbound queue length: 0. Wait queue length: 1.)
05-01 00:51:53.974 1449 5234 E ActivityManager: Parent: com.xxx.weather2/com.xxx.weather.xxxMainActivity
05-01 00:51:53.974 1449 5234 E ActivityManager: Load: 29.89 / 31.82 / 32.27
05-01 00:51:53.974 1449 5234 E ActivityManager: CPU usage from 4583ms to 12043ms later (2020-05-01 00:51:44.177 to 2020-05-01 00:51:51.637):
05-01 00:51:53.974 1449 5234 E ActivityManager: 18% 1449/system_server: 9.1% user + 9.3% kernel / faults: 7819 minor 1 major
05-01 00:51:53.974 1449 5234 E ActivityManager: 10% 720/surfaceflinger: 6.2% user + 4.4% kernel / faults: 734 minor 26 major
05-01 00:51:53.974 1449 5234 E ActivityManager: 10% 651/android.hardware.audio@5.0-service-mediatek: 9.5% user + 0.8% kernel / faults: 1 minor 4 major

The CPU interval, 00:51:44.177–51.637, is after the 00:51:39.594 am_anr. Only three processes are listed, while Load is around 30. This cannot establish an idle system or exclude system pressure. Inspect pre-timeout scheduling, I/O/memory pressure, and freezer state.

The unfreeze reason: Signal line after the ANR gives us a lead: if the app was being unfrozen then, could an earlier freeze explain why it had not responded to input? Searching backward finds the freeze at 00:51:04.000. Put the timestamps together before deciding whether that hypothesis holds:

Time What the excerpt records
00:51:04.000 Vendor Hans logs freeze for UID 10182 / weather2, reason LcdOff
00:51:04.471–04.477 Input policy logs BACK DOWN before queueing/dispatch; this is not proof of app processing
00:51:34.478 Policy logs BACK UP about 30 seconds later, with a different downTime; do not reconstruct a normal paired press
00:51:39.484 / 39.594 Input dispatch timeout / am_anr
00:51:40.868–40.870 Signal Catcher reacts, Hans logs unfreeze reason: Signal, and the app drops/cancels events and reports a long input duration

Explanatory annotations below are corrected; log values are retained.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Hans records a freeze operation, reason: LcdOff
05-01 00:51:03.994 1449 2187 I xxxHansManager : freeze uid: 10245 package: com.tencent.mm reason: LcdOff
05-01 00:51:03.994 1449 2187 D xxxListManagerImpl: com.tencent.mm in autoStart list!
05-01 00:51:03.998 1449 2187 I xxxHansManager : freeze uid: 10246 package: com.xunmeng.pinduoduo reason: LcdOff
05-01 00:51:03.998 1449 2187 D xxxListManagerImpl: com.xunmeng.pinduoduo in autoStart list!
05-01 00:51:04.000 1449 2187 I xxxHansManager : freeze uid: 10182 package: com.xxx.weather2 reason: LcdOff
05-01 00:51:04.002 645 30914 I netd : firewallSetUidRule(4, 10182, 2) <0.09ms>
05-01 00:51:04.005 1449 2187 I xxxHansManager : freeze uid: 10187 package: com.heytap.yoli reason: LcdOff
05-01 00:51:04.005 1449 2187 D xxxListManagerImpl: com.heytap.yoli in autoStart list!
05-01 00:51:04.005 1449 2187 I xxxHansManager : isHansImportantCase uid: 10196 pkg: cn.kuwo.player reason: audiofocus
05-01 00:51:04.007 1449 2187 I xxxHansManager : freeze uid: 10234 package: com.tencent.mobileqq reason: LcdOff
05-01 00:51:04.008 1449 2187 D xxxListManagerImpl: com.tencent.mobileqq in autoStart list!
05-01 00:51:04.014 1449 2187 I xxxHansManager : freeze uid: 10235 package: com.tencent.qqlive reason: LcdOff

// System policy observes BACK DOWN before queueing/dispatch to the target window
05-01 00:51:04.471 1449 9842 D xxxPhoneWindowManager: interceptKeyBeforeQueueing:KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x8, repeatCount=0, eventTime=38812125, downTime=38812125, deviceId=-1, source=0x101, displayId=0 }
05-01 00:51:04.471 1449 9842 I sysui_multi_action: [757,803,799,key_back_down,802,1]
05-01 00:51:04.477 1449 1620 D xxxPhoneWindowManager: interceptKeyBeforeDispatching key: win=Window{1b36ae8 u0 com.xxx.weather2/com.xxx.weather.xxxMainActivity} event = KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x8, repeatCount=0, eventTime=38812125, downTime=38812125, deviceId=-1, source=0x101, displayId=0 }
05-01 00:51:04.477 1449 1620 D xxxPhoneWindowManager: interceptKeyBeforeDispatching newEvent keyCode = 4

// System policy observes BACK UP before dispatch to the target window
05-01 00:51:34.478 1449 1620 D xxxPhoneWindowManager: interceptKeyBeforeDispatching key: win=Window{1b36ae8 u0 com.xxx.weather2/com.xxx.weather.xxxMainActivity} event = KeyEvent { action=ACTION_UP, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x8, repeatCount=0, eventTime=38842126, downTime=38842126, deviceId=-1, source=0x101, displayId=0 }
05-01 00:51:34.478 1449 1620 D xxxPhoneWindowManager: interceptKeyBeforeDispatching newEvent keyCode = 4

// About 5 seconds later: previously delivered input remains unfinished
05-01 00:51:39.484 1449 1620 I WindowManager: Input event dispatching timed out sending to com.xxx.weather2/com.xxx.weather.xxxMainActivity. Reason: Waiting to send key event because the focused window has not finished processing all of the input events that were previously delivered to it. Outbound queue length: 0. Wait queue length: 1.
05-01 00:51:39.484 2256 5518 I QUALITY-TOTAL: exp: anr
05-01 00:51:39.594 1449 5234 I am_anr : [0,2169,com.xxx.weather2,820526660,Input dispatching timed out (Waiting to send key event because the focused window has not finished processing all of the input events that were previously delivered to it. Outbound queue length: 0. Wait queue length: 1.)]
05-01 00:51:39.593 1449 1620 D ActivityManager: ANR post Runnable for ProcessRecord{ae0c833 2169:com.xxx.weather2/u0a182} to deal with anr happend at 38847248@#@2169
05-01 00:51:39.593 1449 1620 D ActivityManager: ANR caller(2) = com.android.server.am.ActivityManagerService$LocalService.inputDispatchingTimedOut:19872 com.android.server.wm.ActivityRecord.keyDispatchingTimedOut:2641 com.android.server.wm.AppWindowToken.keyDispatchingTimedOut:2007 com.android.server.wm.InputManagerCallback.notifyANR:111 com.android.server.input.InputManagerService.notifyANR:1822 <bottom of call stack> <bottom of call stack> <bottom of call stack>

// Signal Catcher reacts; this incomplete line gives neither signal number nor sender
05-01 00:51:40.868 2169 2202 I oloros.weather: Thread[7,tid=2202,WaitingInMainSignalCatcherLoop,Thread*=0xd9878400,peer=0x138c0250,"Signal Catcher"]: reacting to signal

// Hans logs an unfreeze with reason Signal; vendor implementation is needed for causality
05-01 00:51:40.869 1449 9811 I xxxHansManager : unfreeze uid: 10182 package: com.xxx.weather2 reason: Signal
05-01 00:51:40.869 2169 2202 I oloros.weather:
05-01 00:51:40.869 2169 2169 W ViewRootImpl[xxxMainActivity]: Dropping event due to no window focus: KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x8, repeatCount=0, eventTime=38812125, downTime=38812125, deviceId=-1, source=0x101, displayId=0 }, hasFocus:true, mStopped:true, mPausedForTransition:false
05-01 00:51:40.869 2169 2169 W ViewRootImpl[xxxMainActivity]: Cancelling event due to no window focus: KeyEvent { action=ACTION_UP, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x28, repeatCount=0, eventTime=38847249, downTime=38812125, deviceId=-1, source=0x101, displayId=0 }, hasFocus:true, mStopped:true, mPausedForTransition:false

// InputDispatcher reports 36391.9 ms for the last input event, not CPU runtime
05-01 00:51:40.869 1449 1620 I InputDispatcher: Window '1b36ae8 com.xxx.weather2/com.xxx.weather.xxxMainActivity (server)' spent 36391.9ms processing the last input event: KeyEvent
05-01 00:51:40.869 2169 2169 V ViewRootImpl[xxxMainActivity]: Sending input event to IME: KeyEvent { action=ACTION_UP, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x28, repeatCount=0, eventTime=38847249, downTime=38812125, deviceId=-1, source=0x101, displayId=0 }
05-01 00:51:40.870 2169 2169 I Choreographer: Skipped 2212 frames! The application may be doing too much work on its main thread.

The sequence supports investigating input remaining unfinished during freezing and progressing around unfreeze. Actual freezer state, complete input IDs, and vendor unfreeze logic are still missing. Nearby logs alone do not close the causal chain. ANR stack collection commonly uses SIGQUIT (3), but this incomplete Signal Catcher line omits the number; millisecond log order across threads is not execution causality.

36391.9 ms is the dispatcher’s duration. Wall-clock 04.471→40.869 is about 36398 ms, so these are not identical timing boundaries; 04.477 is closer, but monotonic event timing is still needed. Skipped 2212 frames does not prove continuous CPU work. Escalate with these limits to the freezer/input owners rather than generalizing this 2020 Hans sequence to modern AOSP freezing.

ANR Case: Broadcast Timeout causing ANR

In this case, the user was migrating data. The receiver had started a worker thread, yet an ANR still occurred. At first, I missed the issue because I thought moving the slow work to a worker would let the broadcast finish. Then I noticed the call to goAsync(). The full broadcast reason, worker stack, and finish timing are missing. These two lines only show a database-upgrade window gaining focus; they do not establish the broadcast timeout cause.

1
2
04-0717:03:17.174435 1448 1476V WindowManager: Lookingforfocus: Window{efa2a4f u0 正在升级数据库,数据量较大,请耐心等待}, flags=25296898, canReceive=true1
04-0717:03:17.174459 1448 1476V WindowManager: findFocusedWindow: Foundnewfocus @ Window{efa2a4f u0 正在升级数据库,数据量较大,请耐心等待}2

Mechanically, goAsync() keeps the current broadcast active after onReceive() returns. It is not restricted to ordered broadcasts and does not restart the deadline or allow unlimited time. Starting an untracked thread alone does not guarantee process survival. Investigate late/missing PendingResult completion and worker queue delay, rather than automatically calling this a slow onReceive() body.

The older comment’s “10 seconds/30 seconds or more” wording and JobIntentService reference are historical guidance. Current diagnosis distinguishes version and FLAG_RECEIVER_FOREGROUND: common limits are 10/60 seconds through Android 13, and 10–20/60–120 seconds from Android 14 depending on CPU starvation, with OEM variations. Startup/scheduling and asynchronous work consume the budget too. See broadcast ANR diagnosis.

This shortened goAsync() logic shows the transfer of mPendingResult. It corrects the old transcription and omits Android 15 tracing:

1
2
3
4
5
public final PendingResult goAsync() {
PendingResult result = mPendingResult;
mPendingResult = null;
return result;
}

In Android 15 BroadcastReceiver, finish() may wait for component QueuedWork before notifying the system; the call itself is not proof of immediate server-side completion.

Complete the app-side cleanup paths as below. This retains the original initialized mAsyncHandler and business method onReceiveAsync. The Handler must use an app-managed worker Looper that stays alive through completion, not the main Looper. This snippet demonstrates broadcast cleanup, not a migration implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
public void onReceive(final Context context, final Intent intent) {
final PendingResult result = goAsync();
boolean posted = false;
try {
posted = mAsyncHandler.post(() -> {
try {
onReceiveAsync(context, intent);
} finally {
result.finish();
}
});
} finally {
if (!posted) {
result.finish();
}
}
if (!posted) {
android.util.Log.e("MigrationReceiver", "Worker did not accept the task");
}
}

finally covers business exceptions and posting failure, but cannot interrupt long work or prevent queue timeout. Successful post() only means enqueueing. A rejected task is not a successful migration; handle failure/retry explicitly. For lengthy migration, keep the receiver’s durable handoff short and use an appropriate mechanism such as WorkManager. Finishing early and continuing an unmanaged thread does not solve its lifecycle problem.

ANR Case: Launcher - Input ANR

The am_anr reason identifies an input dispatch timeout with previously delivered input still unfinished, rather than NoFocusedWindow:

1
19:44:56.815  2515 25056 I am_anr  : [0,3365,com.xxx.launcher,819478085,Input dispatching timed out (Waiting to send key event because the focused window has not finished processing all of the input events that were previously delivered to it.  Outbound queue length: 0.  Wait queue length: 9.)]

The CPU report is written at 19:45:07.753 and samples roughly 10.9 seconds from around the ANR onward. Load: 0.02/0.01/0.0 cannot exclude a specific scheduling, lock, or driver wait; logd 97% is not 97% of total device capacity. This incomplete sample neither proves a logic bug nor rules out system pressure. Follow the wait chain instead.

1
2
3
4
5
6
7
8
9
10
11
12
1-0119:45:07.753 251525056E ActivityManager: ANR in com.xxx.launcher (com.xxx.launcher/.Launcher)
19:45:07.753 251525056E ActivityManager: PID:3365
19:45:07.753 251525056E ActivityManager: Reason: Input dispatching timed out (Waiting to send key event because the focused window hasnotfinished processing all of the input events that were previously delivered to it. Outbound queue length:0. Wait queue length:9.)
19:45:07.753 251525056E ActivityManager: Parent: com.xxx.launcher/.Launcher
19:45:07.753 251525056E ActivityManager: Load:0.02/0.01/0.0
19:45:07.753 251525056E ActivityManager: CPU usage from0ms to10936ms later (2020- 19:44:56.751to2020- 19:45:07.688):
19:45:07.753 251525056E ActivityManager: 97%546/logd:97% user +0.2% kernel / faults:12minor
19:45:07.753 251525056E ActivityManager: 25%956/surfaceflinger:11% user +13% kernel / faults:151minor17major
19:45:07.753 251525056E ActivityManager: 1.4%1664/media.codec:0.9% user +0.5% kernel / faults:28729minor4major
19:45:07.753 251525056E ActivityManager: 7.5%2515/system_server:2.9% user +4.6% kernel / faults:1818minor8major
19:45:07.753 251525056E ActivityManager: 3.2%3365/com.xxx.launcher:2.1% user +1% kernel / faults:3535minor29major
19:45:07.753 251525056E ActivityManager: 2%3620/com.xxx.persist.system:1.2% user +0.7% kernel / faults:870minor

First inspect the main thread:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
"main"prio=5tid=1Native
| group="main"sCount=1dsCount=0flags=1obj=0x72a50cd0self=0x6f7ae10800
| sysTid=3365nice=-10cgrp=defaultsched=0/0handle=0x700123bed8
| state=S schedstat=(37451337214473599138010494263) utm=26967stm=10484core=0HZ=100
|stack=0x7fc0270000-0x7fc0272000stackSize=8192KB
| held mutexes=
kernel: (couldn't read /proc/self/task/3365/stack)
native: #00pc0000000000071a8c /apex/com.android.runtime/lib64/bionic/libc.so (syscall+28)
native: #01pc0000000000075710 /apex/com.android.runtime/lib64/bionic/libc.so (__futex_wait_ex(voidvolatile*,bool,int,bool, timespecconst*)+140)
native: #02pc00000000000d9744 /apex/com.android.runtime/lib64/bionic/libc.so (pthread_cond_wait+60)
native: #03pc00000000002bf5e8 /system/lib64/libhwui.so (android::uirenderer::renderthread::DrawFrameTask::postAndWait()+168)
native: #04pc00000000002bf510 /system/lib64/libhwui.so (android::uirenderer::renderthread::DrawFrameTask::drawFrame()+44)12
at android.graphics.HardwareRenderer.nSyncAndDrawFrame(Native method)
at android.graphics.HardwareRenderer.syncAndDrawFrame(HardwareRenderer.java:422)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:671)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:3983)
- locked <0x030694da> (a java.lang.Object)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3782)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3085)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1994)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8201)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1085)
at android.view.Choreographer.doCallbacks(Choreographer.java:908)
at android.view.Choreographer.doFrame(Choreographer.java:835)
at android.view.Choreographer$FrameHandler.handleMessage(Choreographer.java:1013)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:238)
at android.app.ActivityThread.main(ActivityThread.java:7798)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)

The main thread waits on a condition variable in DrawFrameTask::postAndWait(). Next inspect that process’s RenderThread:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
"RenderThread"daemon prio=7tid=25Native
| group="main"sCount=1dsCount=0flags=1obj=0x13100b00self=0x6f0c698c00
| sysTid=3616nice=-10cgrp=defaultsched=0/0handle=0x6f072e0d50
| state=S schedstat=(35808915205059629728352628704) utm=29226stm=6582core=3HZ=100
|stack=0x6f071ea000-0x6f071ec000stackSize=991KB
| held mutexes=
kernel: (couldn't read /proc/self/task/3616/stack)
native: #00pc00000000000c49f4 /apex/com.android.runtime/lib64/bionic/libc.so (__ioctl+4)
native: #01pc000000000007d518 /apex/com.android.runtime/lib64/bionic/libc.so (ioctl+132)
native: #02pc0000000000059e58 /system/lib64/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+244)
native: #03pc000000000005ad94 /system/lib64/libbinder.so (android::IPCThreadState::waitForResponse(android::Parcel*,int*)+60
native: #04pc000000000005ab38 /system/lib64/libbinder.so (android::IPCThreadState::transact(int,unsignedint, android::Parcelconst&, android::Parcel*,unsignedint)+180)
native: #05pc000000000004f000 /system/lib64/libbinder.so (android::BpBinder::transact(unsignedint, android::Parcelconst&, android::Parcel*,unsignedint)+228)
native: #06pc000000000007fef8 /system/lib64/libgui.so (android::BpGraphicBufferProducer::dequeueBuffer(int*, android::sp<android::Fence>*,unsignedint,unsignedint,int,unsignedlong,unsignedlong*, android::FrameEventHistoryDelta*)+224)
native: #07pc00000000000b9880 /system/lib64/libgui.so (android::Surface::dequeueBuffer(ANativeWindowBuffer**,int*)+392)
native: #08pc0000000000380540 /system/lib64/libhwui.so (android::uirenderer::renderthread::ReliableSurface::hook_dequeueBuffer(ANativeWindow*, ANativeWindowBuffer**,int*)+104)
native: #09pc000000000000989c /vendor/lib64/egl/eglSubDriverAndroid.so (???)
native: #10pc0000000000009388 /vendor/lib64/egl/eglSubDriverAndroid.so (???)
native: #11pc000000000022cd2c /vendor/lib64/egl/libGLESv2_adreno.so (???)
native: #12pc0000000000212b8c /vendor/lib64/egl/libGLESv2_adreno.so (???)
native: #13pc0000000000020838 /system/lib64/libEGL.so (android::eglQuerySurfaceImpl(void*,void*,int,int*)+248)
native: #14pc00000000002c6794 /system/lib64/libhwui.so (android::uirenderer::renderthread::EglManager::beginFrame(void*)+224)
native: #15pc00000000002d414c /system/lib64/libhwui.so (android::uirenderer::renderthread::CanvasContext::draw()+236)
native: #16pc00000000002d34e8 /system/lib64/libhwui.so (_ZNSt3__110__function6__funcIZN7android10uirenderer12renderthread13DrawFrameTask11postAndWaitEvE3$_0NS_9allocatorIS6_EEFvvEEclEv$c303f2d2360db58ed70a2d0ac7ed911b+380)
native: #17pc00000000002de044 /system/lib64/libhwui.so (android::uirenderer::WorkQueue::process()+228)
native: #18pc00000000002ddd24 /system/lib64/libhwui.so (android::uirenderer::renderthread::RenderThread::threadLoop()+576)
native: #19pc0000000000013654 /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+328)
native: #20pc00000000000da200 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+36)
native: #21pc00000000000769d4 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64)

RenderThread is waiting for a synchronous Binder reply to BpGraphicBufferProducer::dequeueBuffer(). This connects the main thread’s rendering wait to a buffer request, but the two stacks alone do not identify it as the previous frame.

Android 10 DrawFrameTask can unblock the UI thread before or after drawing, depending on canUnblockUiThread; earlier RenderThread work can also delay synchronization. Use frame IDs and a trace rather than assuming the UI always unblocks before dequeue.

The following Binder data is the original teaching example, not a captured transaction from this incident. It shows Launcher PID 3365 / TID 3616 calling PID 956 / TID 1357. The comment’s 1356 typo is corrected to match both illustrative transaction lines.

1
2
3
4
5
6
7
// 956 is SurfaceFlinger, here is the incoming binder information of SurfaceFlinger
proc956:
incoming transaction28350131:0000000000000000from3365:3616to956:1357code2flags10pri0:110r1 node28346208size112:0data0000000000000000

// 3365 is Launcher, 3365:3616 => 956:1357 means from Launcher (3365) rendering thread (3616) to SurfaceFlinger (956) Binder: 956_4 (1357)
proc3365:
outgoing transaction28350131:0000000000000000from3365:3616to956:1357code2flags10pri0:110r1

The separately listed Binder:956_4 stack shows that thread waiting inside dequeueBuffer. Without the incident’s transaction mapping, it does not prove that this was the RenderThread’s server thread:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"Binder:956_4"sysTid=1357
#00pc0000000000071a8c /apex/com.android.runtime/lib64/bionic/libc.so (syscall+28) (BuildId:340eb42dd36c6541aec54c306eb4d0ee)
#01pc0000000000075710 /apex/com.android.runtime/lib64/bionic/libc.so (__futex_wait_ex(voidvolatile*,bool,int,bool, timespecconst*)+140) (BuildId:340eb42dd36c6541aec54c306eb4d0ee)
#02pc00000000000d97e8 /apex/com.android.runtime/lib64/bionic/libc.so (pthread_cond_timedwait+120) (BuildId:340eb42dd36c6541aec54c306eb4d0ee)
#03pc0000000000072df0 /system/lib64/libc++.so (_ZNSt3__118condition_variable15__do_timed_waitERNS_11unique_lockINS_5mutexEEENS_6chrono10time_pointINS5_12system_clockENS5_8durationIxNS_5ratioILl1ELl1000000000EEEEEEE+108) (BuildId:5aad1075509f6e517eb78db32da8fbf6)
#04pc000000000006f9d8 /system/lib64/libgui.so (android::BufferQueueProducer::waitForFreeSlotThenRelock(android::BufferQueueProducer::FreeSlotCaller, std::__1::unique_lock<std::__1::mutex>&,int*)const+788) (BuildId: e017958f19275814d1f2d55ce8b10bfa)
#05pc000000000006fd8c /system/lib64/libgui.so (android::BufferQueueProducer::dequeueBuffer(int*, android::sp<android::Fence>*,unsignedint,unsignedint,int,unsignedlong,unsignedlong*, android::FrameEventHistoryDelta*)+776) (BuildId: e017958f19275814d1f2d55ce8b10bfa)
#06pc000000000007f0a8 /system/lib64/libgui.so (android::BnGraphicBufferProducer::onTransact(unsignedint, android::Parcelconst&, android::Parcel*,unsignedint)+3580) (BuildId: e017958f19275814d1f2d55ce8b10bfa)
#07pc000000000004d67c /system/lib64/libbinder.so (android::BBinder::transact(unsignedint, android::Parcelconst&, android::Parcel*,unsignedint)+136) (BuildId: bb7ca5d12323a310f26473506cf070ed)
#08pc000000000005a55c /system/lib64/libbinder.so (android::IPCThreadState::executeCommand(int)+1008) (BuildId: bb7ca5d12323a310f26473506cf070ed)
#09pc000000000005a0b8 /system/lib64/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+156) (BuildId: bb7ca5d12323a310f26473506cf070ed)
#10pc000000000005a898 /system/lib64/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+220) (BuildId: bb7ca5d12323a310f26473506cf070ed)
#11pc000000000008093c /system/lib64/libbinder.so (android::PoolThread::threadLoop()+24) (BuildId: bb7ca5d12323a310f26473506cf070ed)
#12pc0000000000013654 /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+328) (BuildId:594f10db565bb0b9cf0223c7a1990ce5)
#13pc00000000000da200 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+36) (BuildId:340eb42dd36c6541aec54c306eb4d0ee)
#14pc00000000000769d4 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId:340eb42dd36c6541aec54c306eb4d0ee)

This thread is in waitForFreeSlotThenRelock(). In Android 10 BufferQueueProducer, no available slot or too many outstanding queued buffers can lead to waiting; allocation policy, blocking mode, and dequeue timeout also matter. BufferQueueCore derives limits from acquired/dequeued counts and mode. A layer does not universally have three or four permanently fixed buffers.

The later logs provide additional clues; their explanatory annotations are corrected:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Consumer acquired-count limit reached; this is not the total buffer count
19:44:42.371 956 956 E BufferQueueConsumer: [com.xxx.launcher/com.xxx.launcher.Launcher#0] acquireBuffer: max acquired buffer count reached: 2 (max 1)
19:44:42.371 956 956 E BufferLayerConsumer: [com.xxx.launcher/com.xxx.launcher.Launcher#0] updateTexImage: acquire failed: Function not implemented (-38)

// Prompt is dequeueBuffer failed
19:45:45.127 3365 3616 W OpenGLRenderer: dequeueBuffer failed, error = -110; switching to fallback

19:45:45.138 3365 3616 I OpenGLRenderer: Davey! duration=4015ms; Flags=0, IntendedVsync=21148991192817, Vsync=21148991192817, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=21148991206202, AnimationStart=21148991249587, PerformTraversalsStart=21148991252765, DrawStart=21148991798858, SyncQueued=21148991974796, SyncStart=21152137782451, IssueDrawCommandsStart=21152138724534, SwapBuffers=21156150646824, FrameCompleted=21156152280366, DequeueBufferDuration=0, QueueBufferDuration=0,

// MessageQueue information identifies which Message blocks
19:45:45.142 3365 3365 E ANR_LOG : >>> msg's executing time is too long
19:45:45.142 3365 3365 E ANR_LOG : Blocked msg = { when=-4s2ms what=0 target=android.view.Choreographer$FrameHandler callback=android.view.Choreographer$FrameDisplayEventReceiver } , cost = 4002 ms
19:45:45.142 3365 3365 E ANR_LOG : >>>Current msg List is:
19:45:45.142 3365 3365 E ANR_LOG : Current msg <1> = { when=-4s5ms what=13 target=android.view.ViewRootImpl$ViewRootHandler }
19:45:45.142 3365 3365 E ANR_LOG : Current msg <2> = { when=-4s1ms what=0 target=android.view.ViewRootImpl$ViewRootHandler callback=com.android.launcher3.util.ViewOnDrawExecutor }
19:45:45.143 3365 3365 E ANR_LOG : Current msg <3> = { when=-4s1ms what=0 target=android.view.ViewRootImpl$ViewRootHandler callback=android.widget.Editor$1 }
19:45:45.143 3365 3365 E ANR_LOG : Current msg <4> = { when=-3s23ms what=0 target=android.view.ViewRootImpl$ViewRootHandler callback=android.widget.ViewFlipper$2 }
19:45:45.143 3365 3365 E ANR_LOG : Current msg <5> = { when=-1s502ms what=6 target=android.view.inputmethod.InputMethodManager$H arg1=74627 obj=android.view.inputmethod.InputMethodManager$PendingEvent@561bec9 }
19:45:45.143 3365 3365 E ANR_LOG : Current msg <6> = { when=+14s859ms what=0 target=android.os.Handler callback=xxxUIEngineProguard.i.b$b }
19:45:45.143 3365 3365 E ANR_LOG : Current msg <7> = { when=+24d20h30m18s414ms what=0 target=android.view.ViewRootImpl$ViewRootHandler callback=android.widget.ViewFlipper$2 }
19:45:45.143 3365 3365 E ANR_LOG : >>>CURRENT MSG DUMP OVER<<<

acquireBuffer: ... 2 (max 1) reports two buffers already acquired by the consumer and a configured limit of one. The Android 10 consumer permits one extra temporarily and returns INVALID_OPERATION at this boundary. Function not implemented (-38) is the error-code text, not proof that acquireBuffer is wholly unimplemented. The later -110 indicates a dequeue timeout without identifying who failed to release a buffer.

Keep the times separate: acquire failure is at 19:44:42.371, ANR at 19:44:56.815, and dequeue failure plus the 4002 ms message at 19:45:45. Nor does Davey duration=4015ms equal the roughly 7161 ms between IntendedVsync and FrameCompleted in the excerpt. Without vendor timing code, retain the fields rather than merging them into one proven frame. Zero buffer-duration fields do not invalidate the observed wait stack.

Ask the graphics owners to correlate buffer acquisition/release, consumer state, fences, and composition progress; this evidence does not assign the root cause directly to SurfaceFlinger. Re-identify dependencies on modern builds: Android 15 ViewRootImpl creates BLASTBufferQueue, whose implementation creates a client-side queue and submits buffers through SurfaceControl transactions. The old cross-process dequeue path is not a universal rule.

Anomalous Log Examples

Main Thread Database Operation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
"main" prio=5 tid=1 Native
held mutexes=
kernel: (couldn't read /proc/self/task/11003/stack)
native: #00 pc 000492a4 /system/lib/libc.so (nanosleep+12)
native: #01 pc 0002dc21 /system/lib/libc.so (usleep+52)
native: #02 pc 00009cab /system/lib/libsqlite.so (???)
native: #03 pc 00011119 /system/lib/libsqlite.so (???)
native: #04 pc 00016455 /system/lib/libsqlite.so (???)
native: #16 pc 0000fa29 /system/lib/libsqlite.so (???)
native: #17 pc 0000fad7 /system/lib/libsqlite.so (sqlite3_prepare16_v2+14)
native: #18 pc 0007f671 /system/lib/libandroid_runtime.so (???)
native: #19 pc 002b4721 /system/framework/arm/boot-framework.oat (Java_android_database_sqlite_SQLiteConnection_nativePrepareStatement__JLjava_lang_String_2+116)
at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:294)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:808)
locked <0x0db193bf> (a java.lang.Object)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:793)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:690)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:299)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
locked <0x045a4a8c> (a com.xxxx.video.common.data.DataBaseHelper)
at com.xxxx.video.common.data.DataBaseORM.<init>(DataBaseORM.java:46)
at com.xxxx.video.common.data.DataBaseORM.getInstance(DataBaseORM.java:53)
locked <0x017095d5> (a java.lang.Class<com.xxxx.video.common.data.DataBaseORM>)

This stack establishes main-thread database opening/journal-mode configuration through getWritableDatabase(), while holding Java monitors. It does not identify a slow business query. Native usleep/nanosleep may involve SQLite lock-retry behavior, but unresolved ??? frames do not identify the busy handler or owning connection. SQLite busy timeout supports sleep-and-retry on lock contention; that does not make every SQLite sleep the same cause.

Correlate database open, initialization/migration, transactions, and connection ownership. Move blocking opening/migration work off the main thread without making the UI synchronously wait for it. Increasing busy timeout lengthens waiting; it does not remove the ANR risk. Do not change WAL mode from this stack alone. Without an ANR reason and duration, this is a risky snapshot, not proof of a separate ANR.

Large Binder Payloads

1
2
3
4
5
07-2104:43:21.573 1000 148812756E Binder  : Unreasonably large binder replybuffer: on android.content.pm.BaseParceledListSlice$1@770c74f calling1size388568(data:1,32,7274595)
07-2104:43:21.573 1000 148812756E Binder : android.util.Log$TerribleFailure: Unreasonably large binder replybuffer: on android.content.pm.BaseParceledListSlice$1@770c74f calling1size388568(data:1,32,7274595)
07-2104:43:21.607 1000 1488 2951E Binder : Unreasonably large binder replybuffer: on android.content.pm.BaseParceledListSlice$1@770c74f calling1size211848(data:1,23,7274595)
07-2104:43:21.607 1000 1488 2951E Binder : android.util.Log$TerribleFailure: Unreasonably large binder replybuffer: on android.content.pm.BaseParceledListSlice$1@770c74f calling1size211848(data:1,23,7274595)
07-2104:43:21.662 1000 1488 6258E Binder : Unreasonably large binder replybuffer: on android.content.pm.BaseParceledListSlice$1@770c74f calling1size259300(data:1,33,7274595)

These lines report large Binder replies. Values such as size388568 are Parcel data bytes, not transaction counts or durations. They do not by themselves prove transaction failure, process death, or ANR.

Version matters: AOSP Android 10 Binder.checkParcel uses an 800 * 1024 byte threshold behind the default-disabled CHECK_PARCEL_SIZE; Android 15 retains this check. The listed values are smaller, so this historical device output cannot be attributed directly to that default implementation. Inspect its device-branch logging policy.

The TransactionTooLargeException documentation describes a process buffer shared by in-flight transactions, currently documented as 1 MB—not 1 MB reserved for each call. Reduce/page responses, use an appropriate file-descriptor or shared-data channel for large data, and account for concurrency. Its relevance to an ANR still requires timing evidence.

Binder Communication Failure

1
2
3
4
07-2106:04:35.580<6>[32837.690321] binder:1698:2362transaction failed29189/-3,size100-0line3042
07-2106:04:35.594<6>[32837.704042] binder:1765:4071transaction failed29189/-3,size76-0line3042
07-2106:04:35.899<6>[32838.009132] binder:1765:4067transaction failed29189/-3,size224-8line3042
07-2106:04:36.018<6>[32838.128903] binder:1765:2397transaction failed29189/-22,size348-0line2916

Decode the device kernel’s format before attributing transaction failed to memory exhaustion. Using Linux v4.14 binder.c as a reference, 1698:2362 is the issuing PID:TID, 29189/-3 is the protocol return code/additional error, size100-0 gives data and offsets bytes, and line3042 locates a kernel error path. Source line numbers are not portable across builds.

In that UAPI, 29189 (0x7205) is BR_DEAD_REPLY, not BR_FAILED_REPLY; the errno definitions map -3 to ESRCH and -22 to EINVAL. This does not identify the device as v4.14. In particular, verify the final line’s return-code/error combination against its kernel and earlier driver logs.

Inspect target-process death, Binder node/mapping state, and the failing branch; then correlate client exceptions, retries, and waits. A transaction may fail promptly without causing ANR. These lines do not justify increasing the Binder thread pool or blaming oversized payloads.

ANR Related Information Sharing

  1. Xigua Video Stability Governance System Construction 1: Tailor Principle and Practice
  2. Xigua Video Stability Governance System Construction 2: Raphael Principle and Practice
  3. Xigua Video Stability Governance System Construction 3: Sliver Principle and Practice
  4. Xigua Freeze & ANR Optimization Governance and Monitoring System Construction
  5. Toutiao ANR Optimization Practice Series - Design Principle and Influencing Factors
  6. Toutiao ANR Optimization Practice Series - Monitoring Tools and Analysis Ideas
  7. Toutiao ANR Optimization Practice Series - Example Analysis Collection
  8. Toutiao ANR Optimization Practice Series - Barrier Causes Main Thread Deadlock
  9. Toutiao ANR Optimization Practice Series - Goodbye, SharedPreference Waiting
  10. Android ANR | Principle Analysis and Common Cases

Reference

  1. https://duanqz.github.io/2015-10-12-ANR-Analysis#1-%E6%A6%82%E8%A7%88
  2. https://duanqz.github.io/2015-10-12-ANR-Analysis
  3. http://gityuan.com/2016/12/02/app-not-response/
  4. http://gityuan.com/2017/01/01/input-anr/
  5. https://xiaozhuanlan.com/topic/5097486132

About Me && Blog

Below is a personal introduction and related links. I look forward to communicating with you all!

  1. Blogger Personal Introduction: Contains personal WeChat and WeChat group links.
  2. Blog Content Navigation: A navigation of personal blog content.
  3. Excellent Blog Articles Collected and Organized by Individuals - Must-Know for Android Performance Optimization: Welcome everyone to recommend yourself and recommend (WeChat private chat is fine)
  4. Android Performance Optimization Knowledge Planet: Historical introduction; the community has closed.

One person can go faster, a group of people can go further

CATALOG
  1. 1. Common Causes of ANR
    1. 1.1. Issues Within the Current Process
    2. 1.2. Issues in Remote Processes or the System
  2. 2. ANR Case Studies
    1. 2.1. ANR Case: Toutiao - Deadlock
    2. 2.2. ANR Case: ANR caused by Freezing
    3. 2.3. ANR Case: Broadcast Timeout causing ANR
    4. 2.4. ANR Case: Launcher - Input ANR
  3. 3. Anomalous Log Examples
    1. 3.1. Main Thread Database Operation
    2. 3.2. Large Binder Payloads
    3. 3.3. Binder Communication Failure
  4. 4. ANR Related Information Sharing
  5. 5. Reference
  6. 6. About Me && Blog