android-components/components/lib/crash/README.md

240 lines
9.1 KiB
Markdown
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# [Android Components](../../../README.md) > Libraries > Crash
A generic crash reporter component that can report crashes to multiple services.
Main features:
* Support for multiple crash reporting services (included is support for [Sentry](https://sentry.io) and [Socorro](https://wiki.mozilla.org/Socorro)).
* Support for crashes caused by uncaught exceptions.
* Support for native code crashes (currently primarily focused on GeckoView crashes).
* Can optionally prompt the user for confirmation before sending a crash report.
* Support for showing in-app confirmation UI for non-fatal crashes.
## Usage
### Setting up the dependency
Use Gradle to download the library from [maven.mozilla.org](https://maven.mozilla.org/) ([Setup repository](../../../README.md#maven-repository)):
```Groovy
implementation "org.mozilla.components:lib-crash:{latest-version}"
```
### Setting up crash reporting
In the `onCreate()` method of your Application class create a `CrashReporter` instance and call `install()`:
```Kotlin
CrashReporter(
services = listOf(
// List the crash reporting services you want to use
)
).install(this)
```
With this minimal setup the crash reporting library will capture "uncaught exception" crashes and "native code" crashes and forward them to the configured crash reporting services.
⚠️ Note: To avoid conflicting setups do not use any other crash reporting libraries/services independently from this library.
### Recording crash breadcrumbs to supported services
Using the `CrashReporter` instance to record crash breadcrumbs. These breadcrumbs will then be sent when a crash occurs to aid in debugging. Breadcrumbs are reported only if the underlying crash reporter service supports it.
⚠️ Note: Directly using Sentry's breadcrumb will not work as expected on Android 10 or above. Using the `CrashReporter` breadcrumb is preferred.
```Kotlin
crashReporter.recordCrashBreadcrumb(
CrashBreadcrumb("Settings button clicked", data, "UI", Level.INFO, Type.USER)
)
```
### Sending crash reports to Sentry
⚠️ Note: The crash reporter library is compiled against the Sentry SDK but it doesn't require it as a dependency. The app using the component is responsible for adding the Sentry dependency to its build files in order to use Sentry crash reporting.
Add a `SentryService` instance to your `CrashReporter` in order to upload crashes to Sentry:
```Kotlin
CrashReporter(
services = listOf(
SentryService(applicationContext, "your sentry DSN")
)
).install(applicationContext)
```
By default only the `DSN` is needed. But there are additional option configuration parameters:
```Kotlin
SentryService(
applicationContext,
"your sentry DSN",
// Optionally add tags that will be sent with every crash report
tags = mapOf(
"build_flavor" to BuildConfig.FLAVOR,
"build_type" to BuildConfig.BUILD_TYPE
),
// Send an event to Sentry for every native code crash. Native code crashes
// can't be uploaded to Sentry currently. But sending an event to Sentry
// gives you an idea about how often native code crashes. For sending native
// crash reports add additional services like Socorro.
sendEventForNativeCrashes = true
)
```
### Sending crash reports to Mozilla Socorro
[Socorro](https://wiki.mozilla.org/Socorro) is the name for the [Mozilla Crash Stats](https://crash-stats.mozilla.org/) project.
⚠️ Note: Socorro filters crashes by "app name". New app names need to be safelisted for the server to accept the crash. [File a bug](https://bugzilla.mozilla.org/enter_bug.cgi?product=Socorro) if you would like to get your app added to the safelist.
Add a `MozillaSocorroService` instance to your `CrashReporter` in order to upload crashes to Socorro:
```Kotlin
CrashReporter(
services = listOf(
MozillaSocorroService(applicationContext, "your app name")
)
).install(applicationContext)
```
`MozillaSocorroService` will report version information such as App version, Android Component version, Glean version, Application Services version, GeckoView version and Build ID
⚠️ Note: Currently only native code crashes get uploaded to Socorro. Socorro has limited support for "uncaught exception" crashes too, but it is recommended to use a more elaborate solution like Sentry for that.
### Sending crash reports to Glean
[Glean](https://docs.telemetry.mozilla.org/concepts/glean/glean.html) is a new way to collect telemetry by Mozilla.
This will record crash counts as a labeled counter with each label corresponding to a specific type of crash (`fatal_native_code_crash`, `nonfatal_native_code_crash`, `caught_exception`, `uncaught_exception`, currently).
The list of collected metrics is available in the [metrics.yaml file](metrics.yaml), with their documentation [living here](https://dictionary.telemetry.mozilla.org/apps/fenix/pings/crash).
Due to the fact that Glean can only be recorded to in the main process and lib-crash runs in a separate process when it runs to handle the crash,
lib-crash persists the data in a file format and then reads and records the data from the main process when the application is next run since the `GleanCrashReporterService`
constructor is loaded from the main process.
Add a `GleanCrashReporterService` instance to your `CrashReporter` in order to record crashes in Glean:
```Kotlin
CrashReporter(
services = listOf(
GleanCrashReporterService()
)
).install(applicationContext)
```
⚠️ Note: Applications using the `GleanCrashReporterService` are **required** to undergo [Data Collection Review](https://wiki.mozilla.org/Firefox/Data_Collection) for the crash counts that they will be collecting.
### Showing a crash reporter prompt
![](images/crash-dialog.png)
Optionally the library can show a prompt asking the user for confirmation before sending a crash report.
The behavior can be controlled using the `shouldPrompt` parameter:
```Kotlin
CrashReporter(
// Always prompt
shouldPrompt = CrashReporter.Prompt.ALWAYS,
// Or: Only prompt for native crashes
shouldPrompt = CrashReporter.Prompt.ONLY_NATIVE_CRASH,
// Or: Never show the prompt
shouldPrompt = CrashReporter.Prompt.NEVER,
// ..
).install(applicationContext)
```
#### Customizing the prompt
The crash reporter prompt can be customized by providing a `PromptConfiguration` object:
```Kotlin
CrashReporter(
promptConfiguration = CrashReporter.PromptConfiguration(
appName = "My App",
organizationName = "My Organization",
// An additional message that will be shown in the prompt
message = "We are very sorry!"
// Use a custom theme for the prompt (Extend Theme.Mozac.CrashReporter)
theme = android.R.style.Theme_Holo_Dialog
),
// ..
).install(applicationContext)
```
#### Handling non-fatal crashes
A native code crash can be non-fatal. In this situation a child process crashed but the main process (in which the application runs) is not affected. In this situation a crash can be handled more gracefully and instead of using the crash reporter prompt of the component an app may want to show an in-app UI for asking the user for confirmation.
![](images/crash-in-app.png)
Provide a `PendingIntent` that will be invoked when a non-fatal crash occurs:
```Kotlin
// Launch this activity when a crash occurs.
val pendingIntent = PendingIntent.getActivity(
context,
0,
Intent(this, MyActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
},
PendingIntentUtils.defaultFlags
)
CrashReporter(
shouldPrompt = CrashReporter.Prompt.ALWAYS,
services = listOf(
// ...
),
nonFatalCrashIntent = pendingIntent
).install(this)
```
In your component that receives the Intent (e.g. `Activity`) you can use `Crash.fromIntent()` to receive the `Crash` object. Once the user has approved sending a report call `submitReport()` on your `CrashReporter` instance.
```Kotlin
// In your crash handling component (e.g. Activity)
if (Crash.isCrashIntent(intent) {
val crash = Crash.fromIntent(intent)
...
}
// Once the user has confirmed sending a crash report:
crashReporter.submitReport(crash)
```
⚠️ Note: `submitReport()` may block and perform I/O on the calling thread.
### Sending GeckoView crash reports
⚠️ Note: For sending GeckoView crash reports GeckoView **64.0** or higher is required!
Register `CrashHandlerService` as crash handler for GeckoView:
```Kotlin
val settings = GeckoRuntimeSettings.Builder()
.crashHandler(CrashHandlerService::class.java)
.build()
// Crashes of this runtime will be forwarded to the crash reporter component
val runtime = GeckoRuntime.create(applicationContext, settings)
// If you are using the browser-engine-gecko component then pass the runtime
// to your code initializing the engine:
val engine = GeckoEngine(applicationContext, defaultSettings, runtime)
```
You can force a child process crash (non fatal!) using a multi-process (E10S) GeckoView by loading the test URL `about:crashcontent`. Using a non-multi-process GeckoView you can use `about:crashparent` to force a fatal crash.
## License
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/