Runtime and integration

Prevent ANRs in Android Local AI Apps

Keep model delivery, load, preprocessing, inference, persistence, and cleanup away from blocking UI ownership.

Review status: Fact and editorial QA complete; owner review pending · 2026-10-07 · Fact IDs: COVE-LIFECYCLE-01, BENCHMARK-01

Direct answer

Diagnose an ANR by classifying why Android considered a component unresponsive. Input dispatch, broadcasts, services, providers, and jobs have different triggers and callback boundaries. Timeout behavior depends on event type, platform, device, and system state; Android says AOSP and Pixel examples vary by OEM. No example is a universal deadline for local inference. For input dispatch, inspect the main-thread stack at the event time. Blocking I/O, synchronous binder calls, initialization, and lock waits require different checks. If the UI thread waits for a lock, inspect its owner and wait chain. Moving work off the main thread is not enough if the UI immediately waits for that worker or contends on the same lock. Correlate the ANR signature with reports and available traces. Android recommends Perfetto for main-thread running/runnable state, system_server lock contention, and slow binder replies. Stacks can be incomplete or captured after the cause. Treat signatures as clues and correlate event type, component, process, timestamp, and reproduction steps. ApplicationExitInfo is available from API 30 and can report REASON_ANR and expose a system trace, but it is retrospective, not a live monitor. A recovered ANR trace may be attached to a later process-exit record with a different reason, so correlate process identity and timestamps instead of assigning cause from the exit reason or one stack. getTraceInputStream can return null if the shared circular buffer was overwritten and can throw IOException. Guard by API level; unavailable trace data does not prove no ANR occurred. Separate ANRs from crashes, low-memory kills, initialization failures, and slow but responsive background inference; ApplicationExitInfo has distinct reason codes. A long off-UI task can be a latency concern without an ANR, while a short call can contribute if it blocks input or holds a needed lock. For local AI, map trace frames to the UI callback, model manager, native call, persistence, and return callback. Check whether evidence shows a blocking wait or lock owner; do not infer an ANR from a slow-looking model operation alone. COVE-LIFECYCLE-01 documents ModelManager states and serialized loading, not a Cove ANR incident or trace-collection feature. BENCHMARK-01 says the repository lacks a complete real-device dataset. This is a diagnostic method, not a measured Cove defect or device result. Redact private prompts, transcripts, images, and account data from attachments. After one targeted change, repeat the same interaction on the same build and environment. Preserve the ANR type, process/component, thread evidence, suspected wait owner, and retest. If evidence is missing, mark the cause unconfirmed. Never turn this method into a blanket five-second limit for model tasks.

The model appears ready, but the first tap shows an ANR dialog

A tester opens a local-AI feature whose model was marked ready, taps an action, and sees an ANR dialog. Install and initialization succeeded, but no trace shows whether preprocessing blocked the main thread, a lock owner stalled, or another component caused the delay.

Decision

Capture the ANR type and report, inspect main-thread and lock-owner evidence, and distinguish an ANR from background inference or another process exit before changing threading.

Expected outcome

Record a cause only when a trace or controlled reproduction supports it. If evidence is missing, mark the cause unconfirmed rather than blaming the model.

Evidence to collect

The claim becomes reviewable only when the following evidence is attached to the same artifact and test run:

  • Main-thread and task ownership map
  • Slow-path fixtures
  • Cancellation and responsiveness result

A runtime comparison is publishable only when artifact identity, build configuration, selected backend, task fixture, and failures are recorded.

Implementation workflow

  1. Classify the trigger. Save ANR subject, component, process, platform, time, and foreground context. Identify the event type because input, receiver, service, provider, and job callbacks have different boundaries.
  2. Collect reports and exit records. Preserve system or test-generated reports and stacks. On API 30+, inspect ApplicationExitInfo and getTraceInputStream; handle null and IOException, and correlate process/time if a recovered ANR trace appears on a later exit record.
  3. Inspect stacks and scheduling evidence. Locate blocking I/O, binder, initialization, or lock frames. If the UI thread waits on a lock, inspect its owner. Use Perfetto when available to distinguish running, runnable, blocked, and contended states.
  4. Map evidence to the local-AI path. Correlate frames with the UI callback, model manager, native call, persistence, and return callback. Treat pool saturation or lock cycles as hypotheses until trace evidence supports them.
  5. Fix one cause and rerun. Keep the build and reproduction inputs fixed; change only the confirmed blocking or contention edge. Recapture evidence and record unresolved causes as unknown. Redact private content from reports.

Keep each transition observable. A failure should identify the stage, artifact, runtime, and recovery action without logging private user content.

Acceptance criteria

  • The report names the ANR type and component and distinguishes ANR evidence from crash, low-memory exit, initialization failure, or a slow background task.
  • A proposed root cause is tied to a main-thread stack, lock-owner or scheduling trace, or repeatable controlled reproduction; missing traces remain explicitly unavailable.
  • The same recorded user path is rerun after a targeted change, and no universal timeout, Cove incident, trace-collection feature, or performance result is claimed without evidence.

Decision table

DimensionChoice or evidenceHow to interpret it
First-screen readinessCheck shell rendering and model prerequisitesFinds startup gaps but does not classify an ANR or blocked thread.
Build/runtime triageLocate the earliest failed stage from packaging through task executionSeparates install and initialization failures; thread evidence is still needed to explain unresponsiveness.
ANR diagnosisCorrelate event type, stacks, lock owner, and trace timingSupports a specific cause when evidence exists; absent traces leave the cause unconfirmed.
Long-task policyChoose asynchronous ownership, progress, and cancellation behaviorImproves task design but is not an ANR timeout or proof that the UI blocked.

Failure patterns to prevent

  • Loading inside composition
  • Blocking lifecycle callbacks

Also prevent silent fallback, unpinned artifacts, missing cancellation, and conclusions that combine unlike configurations. Store unsuccessful runs alongside successful ones.

Minimum reproducibility record

LayerRecord
DeviceManufacturer, model, chipset, RAM class, operating-system build
SoftwareApplication version and git commit
ModelFamily, variant, revision, format, file length, hash, quantization
RuntimeName, revision, requested backend, observed backend evidence
WorkloadFixture revision, input hash, prompt hash, output policy
OutcomeCompleted, failed, cancelled, fallback, and privacy-safe diagnostics

Release checklist

  • ☐ The primary query is answered without an unsupported number.
  • ☐ Every artifact and runtime is pinned.
  • ☐ The representative task and failure policy are explicit.
  • ☐ Lifecycle, cancellation, cleanup, and fallback are tested.
  • ☐ User-content and network boundaries are documented.
  • ☐ Result wording applies only to the recorded configuration.
  • ☐ The page links to raw method or evidence when results are added.

Sources and related evidence

Chinese deployment and troubleshooting content is organized in the .奇连 AI 端侧专题.

Frequently asked questions

Does every Android ANR mean model inference ran too long?

No. ANRs have different component triggers. Inspect the event type and relevant stacks before attributing the cause to inference during that task.

Can ApplicationExitInfo always provide the ANR trace?

No. From API 30 it can expose exit reasons and traces, but the trace may be null or unavailable. Correlate process and time.

Should every model request have a five-second deadline to prevent ANRs?

No. A timeout is not a diagnosis; an asynchronous request can run longer without blocking UI. Use event and trace evidence.

Can an idle main-thread stack prove the app was not responsible?

No. The sync-barrier leak is fixed in Android 17, but Android 16 and earlier can still show the symptom. Check related threads and traces.