From d68e020eb17b05bc3196bfc3c13fcbc3116cc272 Mon Sep 17 00:00:00 2001 From: viyakovlev Date: Fri, 20 Feb 2026 12:54:14 +0300 Subject: [PATCH 1/4] fix: safe unregister SystemEventsBroadcastReceiver --- .../SystemEventsBreadcrumbsIntegration.java | 18 +++++-- .../SystemEventsBreadcrumbsIntegrationTest.kt | 47 ++++++++++++------- 2 files changed, 45 insertions(+), 20 deletions(-) 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 a5e56fcc3f2..034424a6270 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 @@ -203,13 +203,13 @@ private void scheduleUnregisterReceiver() { } try { - options.getExecutorService().submit(() -> unregisterReceiver()); + options.getExecutorService().submit(() -> unregisterReceiver(options)); } catch (RejectedExecutionException e) { - unregisterReceiver(); + unregisterReceiver(options); } } - private void unregisterReceiver() { + private void unregisterReceiver(final @NotNull SentryAndroidOptions options) { final @Nullable SystemEventsBroadcastReceiver receiverRef; try (final @NotNull ISentryLifecycleToken ignored = receiverLock.acquire()) { isStopped = true; @@ -218,7 +218,17 @@ private void unregisterReceiver() { } if (receiverRef != null) { - context.unregisterReceiver(receiverRef); + try { + context.unregisterReceiver(receiverRef); + } catch (IllegalArgumentException exception) { + options + .getLogger() + .log( + SentryLevel.ERROR, + exception, + "Failed to unregister SystemEventsBroadcastReceiver: the receiver is already unregistered or was never registered." + ); + } } } 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 fe5e6c775b2..b8ea114b862 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 @@ -16,15 +16,6 @@ import io.sentry.ISentryExecutorService import io.sentry.SentryLevel import io.sentry.test.DeferredExecutorService import io.sentry.test.ImmediateExecutorService -import java.util.concurrent.CountDownLatch -import kotlin.test.AfterTest -import kotlin.test.BeforeTest -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertNotNull -import kotlin.test.assertNull -import kotlin.test.assertTrue import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull @@ -41,6 +32,15 @@ import org.robolectric.annotation.Config import org.robolectric.shadow.api.Shadow import org.robolectric.shadows.ShadowActivityManager import org.robolectric.shadows.ShadowBuild +import java.util.concurrent.CountDownLatch +import kotlin.test.AfterTest +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.assertTrue @RunWith(AndroidJUnit4::class) @Config(sdk = [Build.VERSION_CODES.TIRAMISU]) @@ -52,6 +52,7 @@ class SystemEventsBreadcrumbsIntegrationTest { lateinit var shadowActivityManager: ShadowActivityManager fun getSut( + contextForSut: Context = context, enableSystemEventBreadcrumbs: Boolean = true, enableSystemEventBreadcrumbsExtras: Boolean = false, executorService: ISentryExecutorService = ImmediateExecutorService(), @@ -64,7 +65,7 @@ class SystemEventsBreadcrumbsIntegrationTest { this.executorService = executorService } return SystemEventsBreadcrumbsIntegration( - context, + contextForSut, SystemEventsBreadcrumbsIntegration.getDefaultActions().toTypedArray(), handler, ) @@ -313,6 +314,20 @@ class SystemEventsBreadcrumbsIntegrationTest { assertFalse(fixture.options.isEnableSystemEventBreadcrumbs) } + @Test + fun `Do not crash if receiver already unregistered`() { + val realContext = ApplicationProvider.getApplicationContext() + val sut = fixture.getSut(realContext) + + sut.register(fixture.scopes, fixture.options) + + realContext.unregisterReceiver(sut.receiver) + + val result = runCatching { sut.onBackground() } + + assertFalse(result.isFailure) + } + @Test fun `when str has full package, return last string after dot`() { val sut = fixture.getSut() @@ -421,9 +436,9 @@ class SystemEventsBreadcrumbsIntegrationTest { sut.register(fixture.scopes, fixture.options) Thread { - sut.close() - latch.countDown() - } + sut.close() + latch.countDown() + } .start() latch.await() @@ -505,9 +520,9 @@ class SystemEventsBreadcrumbsIntegrationTest { assertNotNull(sut.receiver) Thread { - sut.close() - latch.countDown() - } + sut.close() + latch.countDown() + } .start() latch.await() From 7c0a5a770b6946d221c7c5589335ebd1f5ef6e89 Mon Sep 17 00:00:00 2001 From: viyakovlev Date: Fri, 20 Feb 2026 13:06:51 +0300 Subject: [PATCH 2/4] Add changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b74bc0886e1..994ee075f18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 8.34.0 + +### Fixes + +- Fix crash when unregistering `SystemEventsBroadcastReceiver` with try-catch block. ([#5106](https://github.com/getsentry/sentry-java/pull/5106)) + ## 8.33.0 ### Features From 8e37e3a982cca9fe78a52a45257f771da0378137 Mon Sep 17 00:00:00 2001 From: viyakovlev Date: Fri, 20 Feb 2026 13:08:46 +0300 Subject: [PATCH 3/4] Revert format changes --- .../SystemEventsBreadcrumbsIntegrationTest.kt | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) 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 b8ea114b862..2505b6f7f7d 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 @@ -16,6 +16,15 @@ import io.sentry.ISentryExecutorService import io.sentry.SentryLevel import io.sentry.test.DeferredExecutorService import io.sentry.test.ImmediateExecutorService +import java.util.concurrent.CountDownLatch +import kotlin.test.AfterTest +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.assertTrue import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull @@ -32,15 +41,6 @@ import org.robolectric.annotation.Config import org.robolectric.shadow.api.Shadow import org.robolectric.shadows.ShadowActivityManager import org.robolectric.shadows.ShadowBuild -import java.util.concurrent.CountDownLatch -import kotlin.test.AfterTest -import kotlin.test.BeforeTest -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertNotNull -import kotlin.test.assertNull -import kotlin.test.assertTrue @RunWith(AndroidJUnit4::class) @Config(sdk = [Build.VERSION_CODES.TIRAMISU]) @@ -436,9 +436,9 @@ class SystemEventsBreadcrumbsIntegrationTest { sut.register(fixture.scopes, fixture.options) Thread { - sut.close() - latch.countDown() - } + sut.close() + latch.countDown() + } .start() latch.await() @@ -520,9 +520,9 @@ class SystemEventsBreadcrumbsIntegrationTest { assertNotNull(sut.receiver) Thread { - sut.close() - latch.countDown() - } + sut.close() + latch.countDown() + } .start() latch.await() From a9ce4a359cbc1b904eef0109dfc4e4903dc8c4d7 Mon Sep 17 00:00:00 2001 From: viyakovlev Date: Fri, 20 Feb 2026 13:11:19 +0300 Subject: [PATCH 4/4] Fix code format --- .../core/SystemEventsBreadcrumbsIntegration.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) 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 034424a6270..5c3e0575bb0 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 @@ -222,12 +222,11 @@ private void unregisterReceiver(final @NotNull SentryAndroidOptions options) { context.unregisterReceiver(receiverRef); } catch (IllegalArgumentException exception) { options - .getLogger() - .log( - SentryLevel.ERROR, - exception, - "Failed to unregister SystemEventsBroadcastReceiver: the receiver is already unregistered or was never registered." - ); + .getLogger() + .log( + SentryLevel.ERROR, + exception, + "Failed to unregister SystemEventsBroadcastReceiver: the receiver is already unregistered or was never registered."); } } }