Add didANRKillOnPreviousExecution() to FirebaseCrashlytics#8178
Conversation
Implements firebase-android-sdk#4201 by exposing a new public API method that detects whether the app was killed by an ANR in the previous run, mirroring the existing didCrashOnPreviousExecution() pattern. On Android API 30+ the method queries ApplicationExitInfo (already used internally for ANR session reporting) against the previous session's start timestamp. On older API levels it always returns false.
… check failures - Add null guard on ActivityManager from getSystemService() before calling getHistoricalProcessExitReasons() to avoid potential NPE. - Log exceptions in checkForPreviousAnr() at verbose level instead of silently ignoring them, to aid diagnosability.
The previous implementation called future.get(3, SECONDS) from onPreExecute on the main thread during eager Crashlytics initialization, just to populate a boolean that almost no app would read. Defer the work to the first call of didANRKillOnPreviousExecution() and cache the result. Apps that never call the API pay nothing at cold start; apps that do call it pay on their own thread, once. To keep the result correct after finalizeSessions removes the previous session, capture the previous-execution session ID on the common worker during onPreExecute (cheap, no blocking get) and read it from the cached field instead of getCurrentSessionId() when the ANR check finally runs.
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. |
📝 PRs merging into main branchOur main branch should always be in a releasable state. If you are working on a larger change, or if you don't want this change to see the light of the day just yet, consider using a feature branch first, and only merge into the main branch when the code complete and ready to be released. |
Add didANRKillOnPreviousExecution() to FirebaseCrashlytics
Implements #4201.
Crashlytics already detects ANRs and files reports for them, and developers have
long been able to call
didCrashOnPreviousExecution()to gate logic that shouldonly run after a fatal crash. However, there was no equivalent API for ANRs:
developers who want to adapt their app's behavior after an ANR (e.g., disable a
heavy feature on the next cold start, log a custom key, or show a recovery
dialog) had no supported way to do so.
didCrashOnPreviousExecution()works by reading a marker file written at crashtime. ANRs cannot use that mechanism because the main thread is frozen and the
crash handler never runs. Instead, the new method uses
ApplicationExitInfo(API 30+), which records process-exit reasons at the OS level — the same source
already queried internally by
SessionReportingCoordinatorwhen filing ANRreports. The new API delegates to that existing infrastructure rather than
introducing a separate detection path.
Usage
The API mirrors
didCrashOnPreviousExecution()— synchronous, returns aboolean. Call it once on a cold start (typically from
Application.onCreateor your DI startup) and react to the result. The first call may briefly
block, so prefer a background thread.
Kotlin
What you can do with it
setCustomKey("recovered_from_anr", true)to tag any follow-upreport this run might file, for correlation in the console.
What to avoid
(Binder IPC + filesystem I/O); subsequent calls are cached and free.
FirebaseCrashlytics.getInstance()is available.trueas "the user just crashed" — ANRs and fatal crashes areindependent; both predicates can fire on the same cold start.
false.Test plan
./gradlew :firebase-crashlytics:testDebugUnitTestpasses locally.SessionReportingCoordinatorRobolectricTestcovers the fourdidRelevantAnrOccurbranches.CrashlyticsCoreInitializationTest.testOnPreExecute_didNotANROnPreviousExecutionverifies the happy (no-ANR) path end-to-end through
CrashlyticsCore,including the lazy first-call path.