Anr Audit And Fix
Android (Google)OfficialCreated by Google LLCDistributed by Android (Google)
- Skill
- Review and audit
- Software development
- Apache-2.0
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The anr-audit-and-fix skill provides a structured methodology for identifying and remediating Application Not Responding (ANR) issues in Android applications. It supports two primary workflows: a static analysis path for auditing source code to detect potential thread-blocking operations or sync barrier leaks, and a trace-driven path for analyzing existing ANR stack dumps to determine root causes and propose fixes.
What it does
- Performs static analysis on Android source code to identify potential main-thread blocking operations.
- Detects Sync Barrier Leak risks caused by off-main-thread mutations of attached Views.
- Systematically diagnoses ANR stack dumps and trace files.
- Categorizes ANR findings into application defects, resource overloads, or external bottlenecks.
- Provides a standardized reporting template for ANR trace analysis.
- Offers guidance on distinguishing between actual ANR risks and non-blocking operations.
When to use it
- When auditing Android source code to proactively find potential ANR-causing code patterns.
- When investigating a reported ANR to determine if it is caused by application code or external factors.
- When analyzing stack dumps to identify specific blocking chains or thread contention issues.
- When verifying if off-main-thread UI access is creating a Sync Barrier Leak risk.
Advantages
- Enforces a rigorous proof-based approach to identifying thread-blocking candidates.
- Distinguishes between critical ANR risks and minor frame drops.
- Provides a clear framework for differentiating between application-level defects and external system bottlenecks.
- Standardizes the documentation and reporting of ANR investigations.
Usage examples
- “Audit this Activity for potential ANR risks.”
- The agent will scan the provided code, verify the executing thread for blocking primitives, and report any confirmed ANR risks or Sync Barrier Leaks.
- “Analyze this ANR stack dump and suggest a fix.”
- The agent will process the trace, identify the unresponsive thread and blocking mechanism, and provide a structured report with a recommended code fix if the issue is an application defect.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/android/anr-audit-and-fix/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip anr-audit-and-fix.zip -d .agents/skills
Documentation by Google LLC
Select the execution path matching the user's request:
1. Path A: Static codebase ANR risk audit
When auditing source files or scanning for thread-blocking operations:
Follow references/risk_analysis_guide.md step by step: list candidates, prove the executing thread (trace callers when the thread depends on them), prove the call blocks, then attribute and grade. Report only candidates that pass these checks; list the dismissed ones separately with a one-line reason.
Evaluate off-main-thread mutations of attached Views not merely as crash risks (
CalledFromWrongThreadException), but as Sync Barrier Leak ANR risks with their own proof (off-main execution plus an attached View).
2. Path B: Trace-driven diagnosis and remediation
When analyzing ANR traces or stack dumps:
Diagnose systematically using references/trace_analysis_guide.md and format the report with references/anr_trace_report_template.md.
Base findings strictly on log evidence. Propose application fixes only for
APP_DEFECTorAPP_RESOURCE_OVERLOAD(never forEXTERNAL_BOTTLENECK).
Files
- ATTRIBUTION.mdAdded by AutoGineer972 B
- LICENSELicence file added by AutoGineer11.1 KiB
- SKILL.md1.7 KiB
- references/anr_trace_report_template.md1.9 KiB
- references/risk_analysis_guide.md6.9 KiB
- references/trace_analysis_guide.md11.6 KiB
references/trace_analysis_guide.md
Diagnose ANR traces using the following rules and format the output with references/anr_trace_report_template.md.
1. Pre-flight context checks
Process match : confirm that the dumped process (
--- pid N at .../Cmd line:header) matches the ANRSubject.Input dispatching timed outsubjects often carry no package or PID; recordunknownrather than aborting.Capture delay (
Immediatevs.Delayed Snapshot) :Immediate: dump captured at the ANR timestamp (the unresponsive thread's stack reflects the freeze).Delayed Snapshot (unresponsive thread stack bypassed): significant lag between the ANR and dump timestamps, ORDebug Storerecords a slow main-threadLooperMsgthat finished right before the dump while the unresponsive thread is now idle innativePollOnce. Don't dismiss as bug-free or misclassify a completed slow transaction as a Sync Barrier Leak.Debug Storeexists only on Android 15+ (absence on older devices is not a signal). ItsLooperMsgentry logs slow (over 2 seconds)ActivityThread$Hmessages (such as Activity lifecycle transactions orBIND_APPLICATION), whereas receiver and service start or bind callbacks use separateDebug Storetags and genericHandler.postrunnables are not logged. A completedLooperMsgtherefore directly identifies a slow main-thread callback: reportIndeterminate (Delayed Snapshot)and attribute it using Section 2 (APP_DEFECTunless external starvation holds).
User-perceived ANR :
Yes(Foreground UI freeze / Foreground termination) : anyInput dispatching timed outANR, OR any component, service, job, or startup ANR whenForeground: Yes(killing a foreground process terminates the user's visible app).No(Silent background termination) : background component or watchdog ANRs whenForeground: No.
2. Attribution verdict
Always commit to a single primary Verdict (never output "Shared" or
"Mixed"). Record any secondary environmental or app contention in
Contributing Factor (None | EXTERNAL (<process or metric>) | APP (<thread or workload>)).
The verdict's job is to tell the developer whether there is something in the
app to fix. Evaluate the verdicts in the following order and stop at the
first one whose evidence is present; record the lower-ranked explanation, if
any, as a one-line Contributing Factor. Precedence never promotes a verdict
without real app-side evidence.
APP_DEFECT(application code, lock, lifecycle contract, or threading bug). Applies when the unresponsive thread (tid=1, thebinder:thread for ContentProvider ANRs, or the custom-HandlerorgoAsync()worker thread for broadcast receivers) has a concrete app-side blocking dependency or contract violation, regardless of background system load:Direct I/O or heavy computation on the unresponsive thread, a synchronous wait on in-process or cross-process work (such as
Future.get(), a latch, synchronous SDK initialization, an avoidable synchronous Binder call, a lock, monitor, or futex whose holder is actively executing app work on the CPU, or a deadlock where the holder waits on a resource the unresponsive thread owns), or a View threading violation that leaked a sync barrier (Section 3). This isAPP_DEFECTeven when the waited-on work is slow because of app-driven CPU, GC, or memory pressure; the primary fix is removing the blocking dependency and the overload goes inContributing Factor: APP (<thread or workload>). (DistinguishBlockedon<0x...>from normalNativeidle polling inMessageQueue.nativePollOnce.)Guard : a lock or GC wait whose target thread (the lock holder or GC daemon, when the app's own heap is not exhausted) is itself starved by external load (waiting on the run queue or in kernel I/O
state=D) is not app-side evidence only if the device is actually saturated ; fall through to the following verdicts. If total CPU has headroom and the holder still can't get scheduled because the app runs it at a much lower priority than the waiting unresponsive thread, that is a priority inversion the app created: stay withAPP_DEFECT.
APP_RESOURCE_OVERLOAD(system resource contention driven by the target app). Applies when device CPU, memory, or I/O is saturated (or thrashing on major page faults) AND the target app is a dominant resource driver (for example, a top CPU consumer alongside heavy major page faults, GC thrashing, or excessive thread creation in the hundreds). If the target app has a low share of total CPU whilekswapd0or other processes dominate---even if cold-start code paging produces several hundred major faults or standard framework/SDK thread pools---fall through toEXTERNAL_BOTTLENECK. Other processes being loaded when the target app is a dominant driver does not downgrade this verdict; note them inContributing Factor: EXTERNAL (<process or metric>).EXTERNAL_BOTTLENECK(External Starvation; target app is a passive victim). Applies only when neither verdict 1 nor verdict 2 holds: other processes or the kernel saturate CPU, memory, or I/O while the target app consumes negligible or low CPU and has no blocking app-side dependency (including cold-start class, library, or provider initialization stalled in disk wait or starved under system I/O and memory pressure, or app threads suspended in kernel cgroup freezer channels).Strict no-fix rule : when Verdict is
EXTERNAL_BOTTLENECK, never propose app code fixes or defensive workarounds . Fill both Section 4 fields withN/A -- No application code change required (External system bottleneck).
3. Root cause and special forensic patterns
Sync Barrier Leakvs.Indeterminatevs.Async Lifecycle Timeout(whentid=1is innativePollOnce,dispatchVsync, or rendering VSYNC frames):Exclusions first:
All threads suspended in kernel cgroup freezer channels ->
EXTERNAL_BOTTLENECK(External Starvation).Debug Storeshows a completed slowLooperMsgcovering the ANR window, or dump capture was significantly delayed ->Indeterminate (Delayed Snapshot)(with the Verdict from Section 2 evidence, orAPP_DEFECTwhen no external or resource-overload evidence is present).Uncompleted async component contract (
BroadcastReceiver.goAsync()withoutPendingResult.finish(),JobServicetimeout, orSHORT_SERVICEexceeding its deadline withoutService.stopSelf()) ->Async Lifecycle Timeout. Only claim this when the trace shows it (for example,GoAsyncor job-stop records inDebug Store, or aSHORT_SERVICEtimeout named in theSubject:line); never infer an async contract leak from an emptyDebug Store.Mechanism :
ViewRootImpl.requestLayout()callscheckThread(), but invalidation paths (invalidate()->onDescendantInvalidated()->scheduleTraversals()) don't, allowing a background thread to enterscheduleTraversals()concurrently with the main thread. Both callmHandler.getLooper().getQueue().postSyncBarrier()and overwrite the unsynchronizedmTraversalBarriertoken;doTraversal()removes only the latest token, leaking an orphaned sync barrier (Message.target == null) inMessageQueue. Synchronous messages starve behind the barrier while asynchronous VSYNC frames continue to run. Android 17 fixed this platform race; Android 16 and older remain vulnerable, so check the trace's Android version when weighing this pattern.ANR subject signatures : background component timeouts (
Broadcast of Intent,executing service) andInput dispatching timed out (Application does not have a focused window), because the window-focus request is also a synchronous main-thread message that starves behind the leaked barrier. A no-focused-window subject alone is not evidence of a sync barrier (for example, if companion code or window state explicitly setsFLAG_NOT_FOCUSABLE); apply the criteria that follow.View Threading Violation (Sync Barrier Leak [Confirmed]): background thread caught mutating UI views/ViewRootImplin the dump, ORtid=1is actively rendering a VSYNC frame (doFrame -> doTraversal) while a synchronous message (SchRcvinDebug Store) starves alongside a spinning background worker.View Threading Violation (Sync Barrier Leak [probable]): when the offending background thread has already exited, don't diagnose by elimination alone. Require corroborating VSYNC rendering evidence (such astid=1caught indispatchVsync, or elevated context switches and CPU ticks onmainandRenderThreadshowing asynchronous rendering continued while the synchronous message starved), immediate capture,tid=1innativePollOnce(idle or dispatching VSYNC), an empty or absentDebug Store, and no lock, IPC, orstate=DI/O wait ontid=1.Remediation and detection : confine all View mutations to the main thread at the root scope (launching on
Dispatchers.MainorlifecycleScopeand wrapping only slow I/O inwithContext(Dispatchers.IO)). When the offending call site isn't on the stack, audit background callbacks and pinpoint it using Android 17's compatibility check (adb shell am compat enable ENFORCE_THREAD_CHECKS_ON_VIEW_ROOT_IMPL_APIS <package>, debuggable builds only), Android 17'sView#registerCalledFromWrongThreadListener(requirescompileSdk 37; guard calls withBuild.VERSION.SDK_INT >= 37) for production telemetry, the Robolectric unit-test flag-Drobolectric.enforceViewMethodsCalledOnMainThread=true, or crash logs forIllegalStateExceptionatMessageQueue.removeSyncBarrier.
Blocked or missing unresponsive thread :
If the unresponsive thread is
Blockedon a lock, identify the holder thread and diagnose what it is doing (app work, GC, I/O, waiting on a lock the unresponsive thread owns, or a lower-priority thread being starved) rather than the waiting thread's own frames; the remediation follows from the holder's workload.If
tid=1is absent fromDALVIK THREADS, locate the main thread among the(not attached)entries inDALVIK THREADS(sysTid == PID) before concluding anything; its frames (such as VM teardown waiting on other threads) reveal the actual stall.
Stackless traces (stack-dump timeout or missing thread stacks) :
Distinguish using kernel
Waiting Channels(sysTid=<tid> <wchan>lines) and/procstats:External starvation (
EXTERNAL_BOTTLENECK) : severe system I/O or memory pressure with the main thread (sysTid == PID) in kernel disk or file system wait and negligible app CPU.Internal futex contention (
APP_DEFECT/Lock Contention) : the main thread and a convoy of app worker threads parked infutex_*wait channels while the app actively consumes CPU.App-driven overload (
APP_RESOURCE_OVERLOAD): the app dominates CPU or major page faults without an internal futex convoy.ART
Signal Catchervs. customSIGQUITinterception : ART's built-inSignal Catcherthread normally waits insigtimedwait/do_sigtimedwait. Never flag it alone; only flag customSIGQUITinterception when an additional app thread also appears in a signal-wait channel.
Secondary or compounding threads (
Secondary / Compounding Threads) :Scan worker threads and report concurrent aggravators (or
None): kernel disk sync (state=Dinfsync/fdatasync), third-party JNI or C/C++ hooks in ART/GC/signal paths, custom signal-wait threads, unbounded thread pools, or thread priority abuse.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Google LLC
- Publisher
- Android (Google) (Official)
- Distributed by
- Android (Google)
- Source
- android/skills · performance/anr-audit-and-fix · commit bf68e2d
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.txt)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Google LLC or Android (Google).
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download anr-audit-and-fix.zip