All Decisions

ADR-0049: Crash and ANR Reporting via Firebase Crashlytics

DateFebruary 28, 2026
CategoryInfrastructure
Tags
ci-cdprivacy-security

Context

The app currently has zero crash or ANR reporting. Errors are logged to Log.e() in three ViewModels and are otherwise silent. Once the app is publicly released, there is no mechanism to learn about crashes, their frequency, affected devices, or stack traces.

ADR-0005 established a no-network-stack policy to keep the MVP focused and privacy-first. However, crash reporting is a fundamentally different concern from user-data networking: it transmits only diagnostic metadata (stack traces, device info, app state) and is an industry baseline for any shipped application. Operating blind in production is a greater risk to users (undetected data-corrupting crashes) than the minimal privacy cost of diagnostic telemetry.

The project already declares firebase-bom as a dependency, has a configured google-services.json, and uses Firebase for Test Lab and App Distribution in CI (ADR-0022). Adding Crashlytics is an incremental step within an existing Firebase integration, not a new vendor dependency.

Decision

We will add Firebase Crashlytics as the crash and ANR reporting tool, amending ADR-0005 to carve out crash reporting as a controlled exception to the no-network policy.

Specifically:

  1. Add dependencies: firebase-crashlytics (via existing BOM) and the Crashlytics Gradle plugin for mapping file uploads.
  2. Initialize in LocusFlowApplication: Enable automatic crash collection. No explicit FirebaseCrashlytics.init() is needed — the content provider auto-initializes.
  3. Non-fatal recording: Wrap caught exceptions in ViewModels and the data layer with FirebaseCrashlytics.getInstance().recordException(e) to surface handled errors that degrade UX without crashing.
  4. PII protection: Never attach user-generated content (reflection text, inbox items, display name) to crash reports. Custom keys are limited to: feature flag states, current screen, database version, model load state.
  5. Mapping file upload: Configure the Crashlytics Gradle plugin to upload ProGuard/R8 mapping files on release builds (depends on ADR-0036 enabling R8).
  6. ANR detection: Crashlytics automatically captures ANR traces on Android 11+; no additional configuration is required.
  7. Amend ADR-0005: Add a "Controlled Exceptions" section noting that crash/ANR reporting via Crashlytics is permitted under the no-network policy, with a reference to this ADR.

Rationale

  • Observability is non-negotiable: Without crash data, production issues are invisible. Users rarely report crashes; they just uninstall.
  • Firebase is already integrated: BOM, google-services.json, Test Lab, and App Distribution are already in the project. Crashlytics is a natural extension, not a new vendor.
  • Minimal privacy impact: Crashlytics transmits stack traces and device metadata, not user content. No PII is included when custom key discipline is maintained.
  • Industry standard: Every production Android app uses crash reporting. Shipping without it is an outlier choice with no upside.

Consequences

Positive:

  • Visibility into crash rates, ANR rates, and affected devices from day one.
  • Non-fatal exception recording surfaces degraded-but-not-crashed states.
  • Stack traces with symbolication (via R8 mapping files) enable fast root-cause analysis.
  • Crashlytics dashboard provides crash-free session rates, trends, and device breakdowns.

Known downsides:

  • Introduces a network call from the app (diagnostic telemetry only).
  • Requires amending ADR-0005, which was a clean "no network" stance.
  • Crashlytics SDK adds ~200KB to the APK.
  • Requires INTERNET permission (added automatically by the Crashlytics SDK manifest merge).
  • Data Safety form must disclose crash/diagnostic data collection (see ADR-0038).

Follow-up work:

  • Configure a Crashlytics-forwarding Timber tree after ADR-0040 (structured logging) is implemented.
  • Set up Crashlytics alerts for crash-free rate drops below a threshold (e.g., <99.5%).
  • Consider adding a user-facing opt-out toggle for crash reporting in a future release (not required for launch).

Alternatives Considered

Sentry:

  • Pros: Open-source, self-hostable, richer error context.
  • Cons: Requires a separate account/project, no existing integration, higher setup cost.
  • Rejected: Firebase is already integrated; adding a second vendor adds unnecessary complexity.

On-device crash log export (via existing export feature):

  • Pros: No network call, fully offline, aligns with ADR-0005.
  • Cons: Users must manually trigger export after a crash — which they almost never do. Crashes that prevent app launch make export impossible. Provides no aggregate statistics.
  • Rejected: Fundamentally inadequate for production observability.

No crash reporting (status quo):

  • Rejected: Operating blind in production is unacceptable for a publicly released app.

Notes

  • Related: ADR-0005 (no network stack — to be amended), ADR-0022 (CI pipeline), ADR-0036 (R8), ADR-0038 (Data Safety form).
  • The INTERNET permission added by Crashlytics is limited to diagnostic telemetry. The app makes no other network calls.
  • Crashlytics respects Android's "Usage & diagnostics" system setting; users who opt out at the OS level will not send crash reports.