ApplicationExitInfo-backed post-mortem ingest for Android.
Pulls the OS-held history of process exits via
ActivityManager.getHistoricalProcessExitReasons (available on
Android 11 / API 30 and later), filters against a persistent marker
so each exit is emitted exactly once across boots, and hands each new
entry to Mob.Defect.emit_appexit_reason/1 as a capsule on
Mob.Defect.Bus.
What the OS gives us
ApplicationExitInfo records the reason a previous process instance
of this app died — an ANR, a crash, an OOM, a user-initiated kill.
The list survives reboots and app updates, and the OS trims it
eventually (usually 16 entries per app). We do NOT run every boot
hoping to catch a live incident: we sweep whenever the caller does
and take whatever the OS still holds since the last sweep.
Persistent marker
Without a marker, every sweep on a fresh install re-emits the entire
historical list; every subsequent boot would re-emit the same
entries. The native NIF persists the highest-seen exit timestamp to
<filesDir>/mob_post_mortem_appexit_marker.txt and filters the OS
list to entries strictly newer. First sweep on a fresh install still
emits the current history (that is the point of a first sweep);
every subsequent sweep emits only what accumulated since.
Platform gating
The NIF is registered on both platforms (iOS returns []
unconditionally — the iOS substrate is MetricKit, MOB-179). This
module gates on :mob_nif.platform() == :android so a caller on
iOS or in a host test does no work at all. On an Android device
below API 30 the native side also returns [] — the API was added
in Android 11.
Redaction
The emitted capsule carries: numeric reason code, pid (an OS
identifier, not user data), timestamp, process name (normally the
app's package name; also OS-controlled), and a short
OS-generated description string like "remote process crash".
NOT included this phase: the trace file contents an ANR carries —
those can hold app strings and need the same
Mob.Agent.Receipt.summarize_error/3-style discipline before they
can safely reach the bus.
Summary
Functions
@spec sweep() :: [Mob.Defect.Capsule.t()]
Sweep any ApplicationExitInfo entries the OS has recorded since the persisted marker was last written.
Returns the list of capsules emitted, in the order the NIF returned them (typically OS-chronological). Empty on iOS, on Android < 11, on a host test with the NIF not loaded, or any time the marker filters everything out.