From 7b4b8c2f3a7d89b6f1e87c6839ab973c885d1761 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto <5731772+marandaneto@users.noreply.github.com> Date: Mon, 4 Oct 2021 08:46:42 +0200 Subject: [PATCH] Fix: Handle exception if Context.registerReceiver throws (#1747) --- CHANGELOG.md | 1 + .../SystemEventsBreadcrumbsIntegration.java | 14 +++++- .../SystemEventsBreadcrumbsIntegrationTest.kt | 48 ++++++++++++------- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7086207b01..dc8a5861b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +* Fix: Handle exception if Context.registerReceiver throws (#1747) * Feat: Attach Java vendor and version to events and transactions (#1703) ## 5.2.0 diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java index 005b184d68..fc09c6fbea 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java @@ -95,8 +95,18 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio for (String item : actions) { filter.addAction(item); } - context.registerReceiver(receiver, filter); - options.getLogger().log(SentryLevel.DEBUG, "SystemEventsBreadcrumbsIntegration installed."); + try { + // registerReceiver can throw SecurityException but it's not documented in the official docs + context.registerReceiver(receiver, filter); + this.options + .getLogger() + .log(SentryLevel.DEBUG, "SystemEventsBreadcrumbsIntegration installed."); + } catch (Exception e) { + this.options.setEnableSystemEventBreadcrumbs(false); + this.options + .getLogger() + .log(SentryLevel.ERROR, "Failed to initialize SystemEventsBreadcrumbsIntegration.", e); + } } } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegrationTest.kt index 81f6a7e2e0..2be1d6783f 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegrationTest.kt @@ -7,11 +7,13 @@ import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever import io.sentry.Breadcrumb import io.sentry.IHub import io.sentry.SentryLevel import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFalse import kotlin.test.assertNotNull import kotlin.test.assertNull @@ -19,8 +21,13 @@ class SystemEventsBreadcrumbsIntegrationTest { private class Fixture { val context = mock() + var options = SentryAndroidOptions() + val hub = mock() - fun getSut(): SystemEventsBreadcrumbsIntegration { + fun getSut(enableSystemEventBreadcrumbs: Boolean = true): SystemEventsBreadcrumbsIntegration { + options = SentryAndroidOptions().apply { + isEnableSystemEventBreadcrumbs = enableSystemEventBreadcrumbs + } return SystemEventsBreadcrumbsIntegration(context) } } @@ -30,21 +37,19 @@ class SystemEventsBreadcrumbsIntegrationTest { @Test fun `When system events breadcrumb is enabled, it registers callback`() { val sut = fixture.getSut() - val options = SentryAndroidOptions() - val hub = mock() - sut.register(hub, options) + + sut.register(fixture.hub, fixture.options) + verify(fixture.context).registerReceiver(any(), any()) assertNotNull(sut.receiver) } @Test fun `When system events breadcrumb is disabled, it doesn't register callback`() { - val sut = fixture.getSut() - val options = SentryAndroidOptions().apply { - isEnableSystemEventBreadcrumbs = false - } - val hub = mock() - sut.register(hub, options) + val sut = fixture.getSut(enableSystemEventBreadcrumbs = false) + + sut.register(fixture.hub, fixture.options) + verify(fixture.context, never()).registerReceiver(any(), any()) assertNull(sut.receiver) } @@ -52,10 +57,10 @@ class SystemEventsBreadcrumbsIntegrationTest { @Test fun `When ActivityBreadcrumbsIntegration is closed, it should unregister the callback`() { val sut = fixture.getSut() - val options = SentryAndroidOptions() - val hub = mock() - sut.register(hub, options) + + sut.register(fixture.hub, fixture.options) sut.close() + verify(fixture.context).unregisterReceiver(any()) assertNull(sut.receiver) } @@ -63,19 +68,28 @@ class SystemEventsBreadcrumbsIntegrationTest { @Test fun `When broadcast received, added breadcrumb with type and category`() { val sut = fixture.getSut() - val options = SentryAndroidOptions() - val hub = mock() - sut.register(hub, options) + + sut.register(fixture.hub, fixture.options) val intent = Intent().apply { action = Intent.ACTION_TIME_CHANGED } sut.receiver!!.onReceive(any(), intent) - verify(hub).addBreadcrumb(check { + verify(fixture.hub).addBreadcrumb(check { assertEquals("device.event", it.category) assertEquals("system", it.type) assertEquals(SentryLevel.INFO, it.level) // cant assert data, its not a public API }) } + + @Test + fun `Do not crash if registerReceiver throws exception`() { + val sut = fixture.getSut() + whenever(fixture.context.registerReceiver(any(), any())).thenThrow(SecurityException()) + + sut.register(fixture.hub, fixture.options) + + assertFalse(fixture.options.isEnableSystemEventBreadcrumbs) + } }