From Android 11 (API 30), the Android OS provides information of an application process’s death in the ApplicationExitInfo
API. This can be particularly useful for diagnosing native (NDK) crashes and ANR events.
You can augment your error reporting with this data by enabling the bugsnag-plugin-android-exitinfo
plugin. Furthermore, ANR events can be created entirely from the trace file provided in the ApplicationExitInfo, if the original ANR was not captured by the BugSnag ANR handler. This happens, for example, if an app receieves an ANR whilst in the background.
Use the bugsnag-plugin-android-exitinfo
plugin to augment your native crashes and ANRs with:
These are shown on the Threads tab of the BugSnag dashboard. Without the plugin, only the thread names and states can be captured in a native crash or ANR.
The “Open FileDescriptors” tab of the BugSnag dashboard shows the files that were open at the time of the crash.
The app’s Logcat messages leading up to the error are shown on the “Log Messages” tab on the BugSnag dashboard for apps running on Android 11 to 14 (the data is no longer available from Android 15).
Install bugsnag-plugin-android-exitinfo
on devices running Android 11+ (API 30) by adding the dependency to your app/build.gradle
or build.gradle.kts
file:
dependencies {
implementation("com.bugsnag:bugsnag-plugin-android-exitinfo:6.+")
}
dependencies {
implementation("com.bugsnag:bugsnag-plugin-android-exitinfo:6.+")
}
Then add the plugin to your configuration:
BugsnagExitInfoPlugin bugsnagExitInfoPlugin = new BugsnagExitInfoPlugin();
Configuration config = Configuration.load(this);
config.addPlugin(bugsnagExitInfoPlugin);
Bugsnag.start(this, config);
Bugsnag.start(this, Configuration.load(this).apply {
addPlugin(BugsnagExitInfoPlugin())
})
Please note that v6.0.0 or above of bugsnag-android
is required for this plugin.
The plugin can be configured by passing it an ExitInfoPluginConfiguration
object with one or more of the following options:
To match a BugSnag event to a reported exit info record, we use ActivityManager
‘s ProcessStateSummary
to store a unique session ID. This may interfere with other tools using this API, in which case the behavior can be disabled as follows:
ExitInfoPluginConfiguration exitInfoPluginConfiguration = new ExitInfoPluginConfiguration();
exitInfoPluginConfiguration.setDisableProcessStateSummaryOverride(false);
BugsnagExitInfoPlugin bugsnagExitInfoPlugin = new BugsnagExitInfoPlugin(exitInfoPluginConfiguration);
Configuration config = Configuration.load(this);
config.addPlugin(bugsnagExitInfoPlugin);
Bugsnag.start(this, config);
Bugsnag.start(Configuration.load(this).apply {
val exitInfoPluginConfiguration = ExitInfoPluginConfiguration().apply {
disableProcessStateSummaryOverride = true
}
addPlugin(BugsnagExitInfoPlugin(exitInfoPluginConfiguration))
})
If disabled – or if session tracking is disabled – BugSnag falls back to using the process ID (PID) stored in a file.
This information is no longer available on devices running Android 15 or later.
When enabled, sends Logcat messages with your event to a “Log Messages” tab on the dashboard:
ExitInfoPluginConfiguration exitInfoPluginConfiguration = new ExitInfoPluginConfiguration();
exitInfoPluginConfiguration.setIncludeLogcat(true);
BugsnagExitInfoPlugin bugsnagExitInfoPlugin = new BugsnagExitInfoPlugin(exitInfoPluginConfiguration);
Configuration config = Configuration.load(this);
config.addPlugin(bugsnagExitInfoPlugin);
Bugsnag.start(this, config);
Bugsnag.start(Configuration.load(this).apply {
val exitInfoPluginConfiguration = ExitInfoPluginConfiguration().apply {
includeLogcat = true
}
addPlugin(BugsnagExitInfoPlugin(exitInfoPluginConfiguration))
})
The messages are ordered with the newest first with the oldest being truncated if the maxStringValueLength
value is reached (10,000 characters by default).
This option is off by default to avoid duplicate reporting if Logcat messages are already being recorded as breadcrumbs.
Sends a list of open file descriptors at the time of the crash with your event to an “Open FileDescriptors” tab on the dashboard:
ExitInfoPluginConfiguration exitInfoPluginConfiguration = new ExitInfoPluginConfiguration();
exitInfoPluginConfiguration.setListOpenFds(false);
BugsnagExitInfoPlugin bugsnagExitInfoPlugin = new BugsnagExitInfoPlugin(exitInfoPluginConfiguration);
Configuration config = Configuration.load(this);
config.addPlugin(bugsnagExitInfoPlugin);
Bugsnag.start(this, config);
Bugsnag.start(Configuration.load(this).apply {
val exitInfoPluginConfiguration = ExitInfoPluginConfiguration().apply {
listOpenFds = false
}
addPlugin(BugsnagExitInfoPlugin(exitInfoPluginConfiguration))
})
This option is enabled by default.
If a trace file indicates an ANR that wasn’t reported with the in-process ANR handler, the plugin can “synthesize” a BugSnag event from the data in the file. This can happen if your app is in the background when it received the ANR as the normal handler cannot run. These will appear on your dashboard without BugSnag data such as breadcrumbs and metadata.
To enable this functionality:
ExitInfoPluginConfiguration exitInfoPluginConfiguration = new ExitInfoPluginConfiguration();
exitInfoPluginConfiguration.setReportUnmatchedANR(true);
BugsnagExitInfoPlugin bugsnagExitInfoPlugin = new BugsnagExitInfoPlugin(exitInfoPluginConfiguration);
Configuration config = Configuration.load(this);
config.addPlugin(bugsnagExitInfoPlugin);
Bugsnag.start(this, config);
Bugsnag.start(Configuration.load(this).apply {
addPlugin(BugsnagExitInfoPlugin(ExitInfoPluginConfiguration(
reportUnmatchedANR = true
)))
})
This option is disabled by default.