Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
205 lines (144 sloc) 7.03 KB

Android Components > 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 and 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 (Setup repository):

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():

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.

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:

CrashReporter(
    services = listOf(
        SentryService(applicationContext, "your sentry DSN")
    )
).install(applicationContext)

By default only the DSN is needed. But there are additional option configuration parameters:

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 is the name for the Mozilla Crash Stats project.

⚠️ Note: Socorro filters crashes by "app name". New app names need to be whitelisted for the server to accept the crash. File a bug if you would like to get your app added to the whitelist.

Add a MozillaSocorroService instance to your CrashReporter in order to upload crashes to Socorro:

CrashReporter(
    services = listOf(
		MozillaSocorroService(applicationContext, "your app name"),
    )
).install(applicationContext)

⚠️ 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.

Showing a crash reporter prompt

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:

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:

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.

Provide a PendingIntent that will be invoked when a non-fatal crash occurs:

// 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)
    },
    0)

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.

// 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:

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/
You can’t perform that action at this time.