From f636ca7b998fb5162a711e3a82b02da71d176e5c Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 8 Aug 2025 15:58:38 +0200 Subject: [PATCH 01/12] fix(sessions): Move and flush unfinished previous session on init --- sentry/api/sentry.api | 2 + .../java/io/sentry/MovePreviousSession.java | 44 +++++ sentry/src/main/java/io/sentry/Sentry.java | 12 ++ .../java/io/sentry/cache/EnvelopeCache.java | 50 +++--- .../java/io/sentry/MovePreviousSessionTest.kt | 161 ++++++++++++++++++ sentry/src/test/java/io/sentry/SentryTest.kt | 75 +++++++- .../java/io/sentry/cache/EnvelopeCacheTest.kt | 67 ++++++++ 7 files changed, 383 insertions(+), 28 deletions(-) create mode 100644 sentry/src/main/java/io/sentry/MovePreviousSession.java create mode 100644 sentry/src/test/java/io/sentry/MovePreviousSessionTest.kt diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 767d0441593..52f2aa585a5 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -4346,6 +4346,7 @@ public class io/sentry/cache/EnvelopeCache : io/sentry/cache/IEnvelopeCache { public static final field SUFFIX_ENVELOPE_FILE Ljava/lang/String; protected static final field UTF_8 Ljava/nio/charset/Charset; protected final field cacheLock Lio/sentry/util/AutoClosableReentrantLock; + protected final field sessionLock Lio/sentry/util/AutoClosableReentrantLock; public fun (Lio/sentry/SentryOptions;Ljava/lang/String;I)V public static fun create (Lio/sentry/SentryOptions;)Lio/sentry/cache/IEnvelopeCache; public fun discard (Lio/sentry/SentryEnvelope;)V @@ -4353,6 +4354,7 @@ public class io/sentry/cache/EnvelopeCache : io/sentry/cache/IEnvelopeCache { public static fun getCurrentSessionFile (Ljava/lang/String;)Ljava/io/File; public static fun getPreviousSessionFile (Ljava/lang/String;)Ljava/io/File; public fun iterator ()Ljava/util/Iterator; + public fun movePreviousSession (Ljava/io/File;Ljava/io/File;)V public fun store (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)V public fun waitPreviousSessionFlush ()Z } diff --git a/sentry/src/main/java/io/sentry/MovePreviousSession.java b/sentry/src/main/java/io/sentry/MovePreviousSession.java new file mode 100644 index 00000000000..99b92d92653 --- /dev/null +++ b/sentry/src/main/java/io/sentry/MovePreviousSession.java @@ -0,0 +1,44 @@ +package io.sentry; + +import static io.sentry.SentryLevel.DEBUG; +import static io.sentry.SentryLevel.INFO; + +import io.sentry.cache.EnvelopeCache; +import io.sentry.cache.IEnvelopeCache; +import java.io.File; +import org.jetbrains.annotations.NotNull; + +final class MovePreviousSession implements Runnable { + + private final @NotNull SentryOptions options; + + MovePreviousSession(final @NotNull SentryOptions options) { + this.options = options; + } + + @Override + public void run() { + final String cacheDirPath = options.getCacheDirPath(); + if (cacheDirPath == null) { + options.getLogger().log(INFO, "Cache dir is not set, not moving the previous session."); + return; + } + + if (!options.isEnableAutoSessionTracking()) { + options + .getLogger() + .log(DEBUG, "Session tracking is disabled, bailing from previous session mover."); + return; + } + + final IEnvelopeCache cache = options.getEnvelopeDiskCache(); + if (cache instanceof EnvelopeCache) { + final File currentSessionFile = EnvelopeCache.getCurrentSessionFile(cacheDirPath); + final File previousSessionFile = EnvelopeCache.getPreviousSessionFile(cacheDirPath); + + ((EnvelopeCache) cache).movePreviousSession(currentSessionFile, previousSessionFile); + + ((EnvelopeCache) cache).flushPreviousSession(); + } + } +} diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index c462f91025b..bf96c5f3232 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -346,6 +346,8 @@ private static void init(final @NotNull SentryOptions options, final boolean glo options.setExecutorService(new SentryExecutorService(options)); options.getExecutorService().prewarm(); } + + movePreviousSession(options); // when integrations are registered on Scopes ctor and async integrations are fired, // it might and actually happened that integrations called captureSomething // and Scopes was still NoOp. @@ -497,6 +499,16 @@ private static void handleAppStartProfilingConfig( return options.getInternalTracesSampler().sample(appStartSamplingContext); } + @SuppressWarnings("FutureReturnValueIgnored") + private static void movePreviousSession(final @NotNull SentryOptions options) { + // enqueue a task to move previous unfinished session to its own file + try { + options.getExecutorService().submit(new MovePreviousSession(options)); + } catch (Throwable e) { + options.getLogger().log(SentryLevel.DEBUG, "Failed to move previous session.", e); + } + } + @SuppressWarnings("FutureReturnValueIgnored") private static void finalizePreviousSession( final @NotNull SentryOptions options, final @NotNull IScopes scopes) { diff --git a/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java index 8117002daf9..69ed2887dd6 100644 --- a/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java +++ b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java @@ -73,6 +73,7 @@ public class EnvelopeCache extends CacheStrategy implements IEnvelopeCache { private final @NotNull Map fileNameMap = new WeakHashMap<>(); protected final @NotNull AutoClosableReentrantLock cacheLock = new AutoClosableReentrantLock(); + protected final @NotNull AutoClosableReentrantLock sessionLock = new AutoClosableReentrantLock(); public static @NotNull IEnvelopeCache create(final @NotNull SentryOptions options) { final String cacheDirPath = options.getCacheDirPath(); @@ -113,20 +114,7 @@ public void store(final @NotNull SentryEnvelope envelope, final @NotNull Hint hi } if (HintUtils.hasType(hint, SessionStart.class)) { - if (currentSessionFile.exists()) { - options.getLogger().log(WARNING, "Current session is not ended, we'd need to end it."); - - try (final Reader reader = - new BufferedReader( - new InputStreamReader(new FileInputStream(currentSessionFile), UTF_8))) { - final Session session = serializer.getValue().deserialize(reader, Session.class); - if (session != null) { - writeSessionToDisk(previousSessionFile, session); - } - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error processing session.", e); - } - } + movePreviousSession(currentSessionFile, previousSessionFile); updateCurrentSession(currentSessionFile, envelope); boolean crashedLastRun = false; @@ -316,17 +304,12 @@ private void writeEnvelopeToDisk( } private void writeSessionToDisk(final @NotNull File file, final @NotNull Session session) { - if (file.exists()) { + try (final OutputStream outputStream = new FileOutputStream(file); + final Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, UTF_8))) { options .getLogger() .log(DEBUG, "Overwriting session to offline storage: %s", session.getSessionId()); - if (!file.delete()) { - options.getLogger().log(SentryLevel.ERROR, "Failed to delete: %s", file.getAbsolutePath()); - } - } - try (final OutputStream outputStream = new FileOutputStream(file); - final Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, UTF_8))) { serializer.getValue().serialize(session, writer); } catch (Throwable e) { options @@ -441,4 +424,29 @@ public boolean waitPreviousSessionFlush() { public void flushPreviousSession() { previousSessionLatch.countDown(); } + + public void movePreviousSession( + final @NotNull File currentSessionFile, final @NotNull File previousSessionFile) { + try (final @NotNull ISentryLifecycleToken ignored = sessionLock.acquire()) { + if (previousSessionFile.exists()) { + options.getLogger().log(DEBUG, "Previous session file already exists."); + return; + } + + if (currentSessionFile.exists()) { + options.getLogger().log(INFO, "Moving current session to previous session."); + + try { + final boolean renamed = currentSessionFile.renameTo(previousSessionFile); + if (!renamed) { + options.getLogger().log(WARNING, "Unable to move current session to previous session."); + } + } catch (Throwable e) { + options + .getLogger() + .log(SentryLevel.ERROR, "Error moving current session to previous session.", e); + } + } + } + } } diff --git a/sentry/src/test/java/io/sentry/MovePreviousSessionTest.kt b/sentry/src/test/java/io/sentry/MovePreviousSessionTest.kt new file mode 100644 index 00000000000..5319346ffff --- /dev/null +++ b/sentry/src/test/java/io/sentry/MovePreviousSessionTest.kt @@ -0,0 +1,161 @@ +package io.sentry + +import io.sentry.cache.EnvelopeCache +import io.sentry.cache.IEnvelopeCache +import io.sentry.transport.NoOpEnvelopeCache +import java.nio.file.Files +import java.nio.file.Path +import kotlin.test.AfterTest +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify + +class MovePreviousSessionTest { + + private class Fixture { + val tempDir: Path = Files.createTempDirectory("sentry-move-session-test") + val options = + SentryOptions().apply { + isDebug = true + setLogger(SystemOutLogger()) + } + val cache = mock() + + fun getSUT( + cacheDirPath: String? = tempDir.toAbsolutePath().toFile().absolutePath, + isEnableSessionTracking: Boolean = true, + envelopeCache: IEnvelopeCache? = null, + ): MovePreviousSession { + options.cacheDirPath = cacheDirPath + options.isEnableAutoSessionTracking = isEnableSessionTracking + options.setEnvelopeDiskCache(envelopeCache ?: EnvelopeCache.create(options)) + return MovePreviousSession(options) + } + + fun cleanup() { + tempDir.toFile().deleteRecursively() + } + } + + private lateinit var fixture: Fixture + + @BeforeTest + fun setup() { + fixture = Fixture() + } + + @AfterTest + fun teardown() { + fixture.cleanup() + } + + @Test + fun `when cache dir is null, logs and returns early`() { + val sut = fixture.getSUT(cacheDirPath = null, envelopeCache = fixture.cache) + + sut.run() + + verify(fixture.cache, never()).movePreviousSession(any(), any()) + verify(fixture.cache, never()).flushPreviousSession() + } + + @Test + fun `when session tracking is disabled, logs and returns early`() { + val sut = fixture.getSUT(isEnableSessionTracking = false, envelopeCache = fixture.cache) + + sut.run() + + verify(fixture.cache, never()).movePreviousSession(any(), any()) + verify(fixture.cache, never()).flushPreviousSession() + } + + @Test + fun `when envelope cache is not EnvelopeCache instance, does nothing`() { + val sut = fixture.getSUT(envelopeCache = NoOpEnvelopeCache.getInstance()) + + sut.run() + + verify(fixture.cache, never()).movePreviousSession(any(), any()) + verify(fixture.cache, never()).flushPreviousSession() + } + + @Test + fun `integration test with real EnvelopeCache`() { + val sut = fixture.getSUT() + + // Create a current session file + val currentSessionFile = EnvelopeCache.getCurrentSessionFile(fixture.options.cacheDirPath!!) + val previousSessionFile = EnvelopeCache.getPreviousSessionFile(fixture.options.cacheDirPath!!) + + currentSessionFile.createNewFile() + currentSessionFile.writeText("session content") + + assertTrue(currentSessionFile.exists()) + assertFalse(previousSessionFile.exists()) + + sut.run() + + // Wait for flush to complete + (fixture.options.envelopeDiskCache as EnvelopeCache).waitPreviousSessionFlush() + + // Current session file should have been moved to previous + assertFalse(currentSessionFile.exists()) + assertTrue(previousSessionFile.exists()) + assert(previousSessionFile.readText() == "session content") + + fixture.cleanup() + } + + @Test + fun `integration test when current session file does not exist`() { + val sut = fixture.getSUT() + + val currentSessionFile = EnvelopeCache.getCurrentSessionFile(fixture.options.cacheDirPath!!) + val previousSessionFile = EnvelopeCache.getPreviousSessionFile(fixture.options.cacheDirPath!!) + + assertFalse(currentSessionFile.exists()) + assertFalse(previousSessionFile.exists()) + + sut.run() + + (fixture.options.envelopeDiskCache as EnvelopeCache).waitPreviousSessionFlush() + + assertFalse(currentSessionFile.exists()) + assertFalse(previousSessionFile.exists()) + + fixture.cleanup() + } + + @Test + fun `integration test when previous session file already exists`() { + val sut = fixture.getSUT() + + val currentSessionFile = EnvelopeCache.getCurrentSessionFile(fixture.options.cacheDirPath!!) + val previousSessionFile = EnvelopeCache.getPreviousSessionFile(fixture.options.cacheDirPath!!) + + currentSessionFile.createNewFile() + currentSessionFile.writeText("current session") + previousSessionFile.createNewFile() + previousSessionFile.writeText("previous session") + + assertTrue(currentSessionFile.exists()) + assertTrue(previousSessionFile.exists()) + + sut.run() + + (fixture.options.envelopeDiskCache as EnvelopeCache).waitPreviousSessionFlush() + + // Files should remain unchanged when previous already exists + assertTrue(currentSessionFile.exists()) + assertTrue(previousSessionFile.exists()) + assert(currentSessionFile.readText() == "current session") + assert(previousSessionFile.readText() == "previous session") + + fixture.cleanup() + } +} diff --git a/sentry/src/test/java/io/sentry/SentryTest.kt b/sentry/src/test/java/io/sentry/SentryTest.kt index 87f4ce17c00..b152166b80c 100644 --- a/sentry/src/test/java/io/sentry/SentryTest.kt +++ b/sentry/src/test/java/io/sentry/SentryTest.kt @@ -52,6 +52,7 @@ import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argThat import org.mockito.kotlin.check import org.mockito.kotlin.eq +import org.mockito.kotlin.inOrder import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.verify @@ -917,13 +918,6 @@ class SentryTest { .deserialize(previousSessionFile.bufferedReader(), Session::class.java)!! .environment, ) - - it.addIntegration { scopes, _ -> - // this is just a hack to trigger the previousSessionFlush latch, so the finalizer - // does not time out waiting. We have to do it as integration, because this is where - // the scopes is already initialized - scopes.startSession() - } it.sessionFlushTimeoutMillis = 100 } @@ -1540,6 +1534,73 @@ class SentryTest { verify(mockDialogHandler).showDialog(eq(associatedEventId), eq(configurator)) } + @Test + fun `init calls movePreviousSession before registering integrations`() { + val mockExecutorService = mock() + val mockIntegration = mock() + + initForTest { + it.dsn = dsn + it.cacheDirPath = getTempPath() + it.isEnableAutoSessionTracking = true + it.executorService = mockExecutorService + it.addIntegration(mockIntegration) + } + + // Verify that movePreviousSession is called before integration registration + // This ensures the session move happens early in the init process + val inOrder = inOrder(mockExecutorService, mockIntegration) + inOrder.verify(mockExecutorService).submit(any()) + inOrder.verify(mockIntegration).register(any(), any()) + } + + @Test + fun `init moves previous session to its own file`() { + val cacheDir = tmpDir.newFolder().absolutePath + lateinit var currentSessionFile: File + + val previousSessionFile = EnvelopeCache.getPreviousSessionFile(cacheDir) + assertFalse(previousSessionFile.exists()) + + initForTest { + it.dsn = dsn + it.isDebug = true + it.setLogger(SystemOutLogger()) + + it.release = "io.sentry.sample@2.0" + + it.cacheDirPath = tmpDir.newFolder().absolutePath + it.executorService = ImmediateExecutorService() + + currentSessionFile = EnvelopeCache.getCurrentSessionFile(it.cacheDirPath!!) + currentSessionFile.parentFile.mkdirs() + it.serializer.serialize( + Session(null, null, "release", "io.sentry.samples@2.0"), + currentSessionFile.bufferedWriter(), + ) + assertEquals( + "release", + it.serializer + .deserialize(currentSessionFile.bufferedReader(), Session::class.java)!! + .environment, + ) + + it.addIntegration { scopes, _ -> + // this is just a hack to assert previous session has been moved to its own file. + // Integrations are being registered after moving but before finalizing previous session + // (== deleting the file) so we can check it's been moved here + assertFalse(currentSessionFile.exists()) + assertTrue(previousSessionFile.exists()) + assertEquals( + "release", + it.serializer + .deserialize(previousSessionFile.bufferedReader(), Session::class.java)!! + .environment, + ) + } + } + } + private class InMemoryOptionsObserver : IOptionsObserver { var release: String? = null private set diff --git a/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt b/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt index 2b34fac6ffc..4c798133fc6 100644 --- a/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt +++ b/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt @@ -377,4 +377,71 @@ class EnvelopeCacheTest { assertEquals(2, cache.directory.list()?.size) } + + @Test + fun `movePreviousSession moves current session file to previous session file`() { + val cache = fixture.getSUT() + + val currentSessionFile = EnvelopeCache.getCurrentSessionFile(fixture.options.cacheDirPath!!) + val previousSessionFile = EnvelopeCache.getPreviousSessionFile(fixture.options.cacheDirPath!!) + + // Create a current session file + currentSessionFile.createNewFile() + currentSessionFile.writeText("current session content") + + assertTrue(currentSessionFile.exists()) + assertFalse(previousSessionFile.exists()) + + // Call movePreviousSession directly + cache.movePreviousSession(currentSessionFile, previousSessionFile) + + // Current file should be moved to previous + assertFalse(currentSessionFile.exists()) + assertTrue(previousSessionFile.exists()) + assertEquals("current session content", previousSessionFile.readText()) + } + + @Test + fun `movePreviousSession does nothing when current session file does not exist`() { + val cache = fixture.getSUT() + + val currentSessionFile = EnvelopeCache.getCurrentSessionFile(fixture.options.cacheDirPath!!) + val previousSessionFile = EnvelopeCache.getPreviousSessionFile(fixture.options.cacheDirPath!!) + + assertFalse(currentSessionFile.exists()) + assertFalse(previousSessionFile.exists()) + + // Call movePreviousSession when no files exist + cache.movePreviousSession(currentSessionFile, previousSessionFile) + + // Nothing should happen + assertFalse(currentSessionFile.exists()) + assertFalse(previousSessionFile.exists()) + } + + @Test + fun `movePreviousSession does nothing when previous session file already exists`() { + val cache = fixture.getSUT() + + val currentSessionFile = EnvelopeCache.getCurrentSessionFile(fixture.options.cacheDirPath!!) + val previousSessionFile = EnvelopeCache.getPreviousSessionFile(fixture.options.cacheDirPath!!) + + // Create both files + currentSessionFile.createNewFile() + currentSessionFile.writeText("current session content") + previousSessionFile.createNewFile() + previousSessionFile.writeText("existing previous content") + + assertTrue(currentSessionFile.exists()) + assertTrue(previousSessionFile.exists()) + + // Call movePreviousSession when previous already exists + cache.movePreviousSession(currentSessionFile, previousSessionFile) + + // Both files should remain unchanged + assertTrue(currentSessionFile.exists()) + assertTrue(previousSessionFile.exists()) + assertEquals("current session content", currentSessionFile.readText()) + assertEquals("existing previous content", previousSessionFile.readText()) + } } From f98fb31684f30837aaba5c30f1d4449e986613f3 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 8 Aug 2025 16:09:05 +0200 Subject: [PATCH 02/12] Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b6d2381804..18216d04503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ - Ensure frame metrics listeners are registered/unregistered on the main thread ([#4582](https://github.com/getsentry/sentry-java/pull/4582)) - Do not report cached events as lost ([#4575](https://github.com/getsentry/sentry-java/pull/4575)) - Previously events were recorded as lost early despite being retried later through the cache +- Move and flush unfinished previous session on init ([#4624](https://github.com/getsentry/sentry-java/pull/4624)) + - This removes the need for unnecessary blocking our background queue for 15 seconds in the case of a background app start ## 8.18.0 From 0911f1de84df3cf76d1a24376f182fd49fdd7207 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 8 Aug 2025 22:37:13 +0200 Subject: [PATCH 03/12] chore(breadcrumbs): Add an option to disable reporting system events extras for breadcrumbs --- .../api/sentry-android-core.api | 2 + .../android/core/SentryAndroidOptions.java | 11 ++++ .../SystemEventsBreadcrumbsIntegration.java | 2 +- .../android/core/SentryAndroidOptionsTest.kt | 14 +++++ .../SystemEventsBreadcrumbsIntegrationTest.kt | 57 +++++++++++++++++++ 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/sentry-android-core/api/sentry-android-core.api b/sentry-android-core/api/sentry-android-core.api index f3adbd6ee8b..5b416486576 100644 --- a/sentry-android-core/api/sentry-android-core.api +++ b/sentry-android-core/api/sentry-android-core.api @@ -336,6 +336,7 @@ public final class io/sentry/android/core/SentryAndroidOptions : io/sentry/Sentr public fun isEnableRootCheck ()Z public fun isEnableScopeSync ()Z public fun isEnableSystemEventBreadcrumbs ()Z + public fun isEnableSystemEventBreadcrumbsExtras ()Z public fun isReportHistoricalAnrs ()Z public fun setAnrEnabled (Z)V public fun setAnrReportInDebug (Z)V @@ -360,6 +361,7 @@ public final class io/sentry/android/core/SentryAndroidOptions : io/sentry/Sentr public fun setEnableRootCheck (Z)V public fun setEnableScopeSync (Z)V public fun setEnableSystemEventBreadcrumbs (Z)V + public fun setEnableSystemEventBreadcrumbsExtras (Z)V public fun setFrameMetricsCollector (Lio/sentry/android/core/internal/util/SentryFrameMetricsCollector;)V public fun setNativeHandlerStrategy (Lio/sentry/android/core/NdkHandlerStrategy;)V public fun setNativeSdkName (Ljava/lang/String;)V diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java index 69ddfe4b0ad..8e5c48dad18 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java @@ -177,6 +177,9 @@ public final class SentryAndroidOptions extends SentryOptions { */ private boolean enableAutoTraceIdGeneration = true; + /** Enable or disable intent extras reporting for system event breadcrumbs. Default is false. */ + private boolean enableSystemEventBreadcrumbsExtras = false; + public interface BeforeCaptureCallback { /** @@ -614,6 +617,14 @@ public void setEnableAutoTraceIdGeneration(final boolean enableAutoTraceIdGenera this.enableAutoTraceIdGeneration = enableAutoTraceIdGeneration; } + public boolean isEnableSystemEventBreadcrumbsExtras() { + return enableSystemEventBreadcrumbsExtras; + } + + public void setEnableSystemEventBreadcrumbsExtras(boolean enableSystemEventBreadcrumbsExtras) { + this.enableSystemEventBreadcrumbsExtras = enableSystemEventBreadcrumbsExtras; + } + static class AndroidUserFeedbackIDialogHandler implements SentryFeedbackOptions.IDialogHandler { @Override public void showDialog( 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 91099d01253..561f507c5a1 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 @@ -370,7 +370,7 @@ String getStringAfterDotFast(final @Nullable String str) { if (batteryState.charging != null) { breadcrumb.setData("charging", batteryState.charging); } - } else { + } else if (options.isEnableSystemEventBreadcrumbsExtras()) { final Bundle extras = intent.getExtras(); if (extras != null && !extras.isEmpty()) { final Map newExtras = new HashMap<>(extras.size()); diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidOptionsTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidOptionsTest.kt index 6326018209f..8cb79b0bb5b 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidOptionsTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidOptionsTest.kt @@ -181,6 +181,20 @@ class SentryAndroidOptionsTest { ) } + @Test + fun `system event breadcrumbs extras disabled by default`() { + val sentryOptions = SentryAndroidOptions() + + assertFalse(sentryOptions.isEnableSystemEventBreadcrumbsExtras) + } + + @Test + fun `system event breadcrumbs extras can be enabled`() { + val sentryOptions = SentryAndroidOptions() + sentryOptions.isEnableSystemEventBreadcrumbsExtras = true + assertTrue(sentryOptions.isEnableSystemEventBreadcrumbsExtras) + } + private class CustomDebugImagesLoader : IDebugImagesLoader { override fun loadDebugImages(): List? = null 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 65eb3cb46f3..b2749e3940d 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 @@ -51,11 +51,13 @@ class SystemEventsBreadcrumbsIntegrationTest { fun getSut( enableSystemEventBreadcrumbs: Boolean = true, + enableSystemEventBreadcrumbsExtras: Boolean = false, executorService: ISentryExecutorService = ImmediateExecutorService(), ): SystemEventsBreadcrumbsIntegration { options = SentryAndroidOptions().apply { isEnableSystemEventBreadcrumbs = enableSystemEventBreadcrumbs + isEnableSystemEventBreadcrumbsExtras = enableSystemEventBreadcrumbsExtras this.executorService = executorService } return SystemEventsBreadcrumbsIntegration( @@ -528,4 +530,59 @@ class SystemEventsBreadcrumbsIntegrationTest { assertNull(sut.receiver) } + + @Test + fun `system event breadcrumbs include extras when enableSystemEventBreadcrumbsExtras is true`() { + val sut = fixture.getSut(enableSystemEventBreadcrumbsExtras = true) + + sut.register(fixture.scopes, fixture.options) + val intent = + Intent().apply { + action = Intent.ACTION_TIME_CHANGED + putExtra("test", 10) + putExtra("test2", 20) + } + sut.receiver!!.onReceive(fixture.context, intent) + + verify(fixture.scopes) + .addBreadcrumb( + check { + assertEquals("device.event", it.category) + assertEquals("system", it.type) + assertEquals(SentryLevel.INFO, it.level) + assertEquals("TIME_SET", it.data["action"]) + assertNotNull(it.data["extras"]) + val extras = it.data["extras"] as Map + assertEquals("10", extras["test"]) + assertEquals("20", extras["test2"]) + }, + anyOrNull(), + ) + } + + @Test + fun `system event breadcrumbs do not include extras when enableSystemEventBreadcrumbsExtras is false`() { + val sut = fixture.getSut(enableSystemEventBreadcrumbsExtras = false) + + sut.register(fixture.scopes, fixture.options) + val intent = + Intent().apply { + action = Intent.ACTION_TIME_CHANGED + putExtra("test", 10) + putExtra("test2", 20) + } + sut.receiver!!.onReceive(fixture.context, intent) + + verify(fixture.scopes) + .addBreadcrumb( + check { + assertEquals("device.event", it.category) + assertEquals("system", it.type) + assertEquals(SentryLevel.INFO, it.level) + assertEquals("TIME_SET", it.data["action"]) + assertNull(it.data["extras"]) + }, + anyOrNull(), + ) + } } From de006bab8ba418de231ede2b485edd392b041fc7 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 8 Aug 2025 22:40:09 +0200 Subject: [PATCH 04/12] Changelog --- CHANGELOG.md | 4 ++++ .../java/io/sentry/android/core/SentryAndroidOptions.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18216d04503..7be04b36523 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- Add a `isEnableSystemEventBreadcrumbsExtras` option to disable reporting system events extras for breadcrumbs ([#4625](https://github.com/getsentry/sentry-java/pull/4625)) + ### Improvements - Session Replay: Use main thread looper to schedule replay capture ([#4542](https://github.com/getsentry/sentry-java/pull/4542)) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java index 8e5c48dad18..2ef0435e688 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java @@ -621,7 +621,7 @@ public boolean isEnableSystemEventBreadcrumbsExtras() { return enableSystemEventBreadcrumbsExtras; } - public void setEnableSystemEventBreadcrumbsExtras(boolean enableSystemEventBreadcrumbsExtras) { + public void setEnableSystemEventBreadcrumbsExtras(final boolean enableSystemEventBreadcrumbsExtras) { this.enableSystemEventBreadcrumbsExtras = enableSystemEventBreadcrumbsExtras; } From 58fda1c6e96546c13e0d1fde32436c607e15da85 Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Fri, 8 Aug 2025 20:43:25 +0000 Subject: [PATCH 05/12] Format code --- .../main/java/io/sentry/android/core/SentryAndroidOptions.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java index 2ef0435e688..221495172eb 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java @@ -621,7 +621,8 @@ public boolean isEnableSystemEventBreadcrumbsExtras() { return enableSystemEventBreadcrumbsExtras; } - public void setEnableSystemEventBreadcrumbsExtras(final boolean enableSystemEventBreadcrumbsExtras) { + public void setEnableSystemEventBreadcrumbsExtras( + final boolean enableSystemEventBreadcrumbsExtras) { this.enableSystemEventBreadcrumbsExtras = enableSystemEventBreadcrumbsExtras; } From 8c1ff59ee2b7c2aaea2989758e5538400d7da639 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 09:26:13 +0200 Subject: [PATCH 06/12] build(deps): bump actions/download-artifact from 4 to 5 (#4626) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/integration-tests-ui-critical.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests-ui-critical.yml b/.github/workflows/integration-tests-ui-critical.yml index 5e5f8030b99..c3d82cd5cb1 100644 --- a/.github/workflows/integration-tests-ui-critical.yml +++ b/.github/workflows/integration-tests-ui-critical.yml @@ -91,7 +91,7 @@ jobs: sudo udevadm trigger --name-match=kvm - name: Download APK artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: ${{env.APK_ARTIFACT_NAME}} From 5958d61a688962c083d9a8c3a052c41d376f7a0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 10:00:41 +0200 Subject: [PATCH 07/12] build(deps): bump github/codeql-action from 3.29.2 to 3.29.8 (#4627) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.2 to 3.29.8. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/181d5eefc20863364f96762470ba6f862bdef56b...76621b61decf072c1cee8dd1ce2d2a82d33c17ed) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.29.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 543bd74d2b7..951d1f9f4f8 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -36,7 +36,7 @@ jobs: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} - name: Initialize CodeQL - uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # pin@v2 + uses: github/codeql-action/init@76621b61decf072c1cee8dd1ce2d2a82d33c17ed # pin@v2 with: languages: 'java' @@ -45,4 +45,4 @@ jobs: ./gradlew buildForCodeQL --no-build-cache - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # pin@v2 + uses: github/codeql-action/analyze@76621b61decf072c1cee8dd1ce2d2a82d33c17ed # pin@v2 From 28d3dcc23d7e1c8d7185cc0c0dfd24d749aa7889 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 08:05:58 +0000 Subject: [PATCH 08/12] build(deps): bump actions/create-github-app-token from 2.0.6 to 2.1.0 (#4628) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2.0.6 to 2.1.0. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/df432ceedc7162793a195dd1713ff69aefc7379e...0f859bf9e69e887678d5bbfbee594437cb440ffe) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: 2.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Roman Zavarnitsyn --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6bfa1ce0c7f..7f63e7f5789 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + uses: actions/create-github-app-token@0f859bf9e69e887678d5bbfbee594437cb440ffe # v2.1.0 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From 8cf042110456ba2b90e580e9df13d9b5b6f049df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 08:09:37 +0000 Subject: [PATCH 09/12] build(deps): bump gradle/actions from 4.4.1 to 4.4.2 (#4629) Bumps [gradle/actions](https://github.com/gradle/actions) from 4.4.1 to 4.4.2. - [Release notes](https://github.com/gradle/actions/releases) - [Commits](https://github.com/gradle/actions/compare/ac638b010cf58a27ee6c972d7336334ccaf61c96...017a9effdb900e5b5b2fddfb590a105619dca3c3) --- updated-dependencies: - dependency-name: gradle/actions dependency-version: 4.4.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/agp-matrix.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/enforce-license-compliance.yml | 2 +- .github/workflows/format-code.yml | 2 +- .github/workflows/generate-javadocs.yml | 2 +- .github/workflows/integration-tests-benchmarks.yml | 4 ++-- .github/workflows/integration-tests-ui-critical.yml | 2 +- .github/workflows/integration-tests-ui.yml | 2 +- .github/workflows/release-build.yml | 2 +- .github/workflows/system-tests-backend.yml | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/agp-matrix.yml b/.github/workflows/agp-matrix.yml index b4ddc7f7716..47d307ad4e2 100644 --- a/.github/workflows/agp-matrix.yml +++ b/.github/workflows/agp-matrix.yml @@ -39,7 +39,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 + uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a3f98e3b1c2..001cf480132 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,7 +37,7 @@ jobs: key: build-logic-${{ hashFiles('buildSrc/src/**', 'buildSrc/build.gradle.kts','buildSrc/settings.gradle.kts') }} - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 + uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 951d1f9f4f8..283d573671a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,7 +31,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 + uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} diff --git a/.github/workflows/enforce-license-compliance.yml b/.github/workflows/enforce-license-compliance.yml index 4dbffbc9009..d4026de5820 100644 --- a/.github/workflows/enforce-license-compliance.yml +++ b/.github/workflows/enforce-license-compliance.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 + uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 - name: Set up Java uses: actions/setup-java@v4 diff --git a/.github/workflows/format-code.yml b/.github/workflows/format-code.yml index a597a90cf8e..f2ff878caab 100644 --- a/.github/workflows/format-code.yml +++ b/.github/workflows/format-code.yml @@ -19,7 +19,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 + uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} diff --git a/.github/workflows/generate-javadocs.yml b/.github/workflows/generate-javadocs.yml index 74283f5e47e..29b4fdedd9c 100644 --- a/.github/workflows/generate-javadocs.yml +++ b/.github/workflows/generate-javadocs.yml @@ -20,7 +20,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 + uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 - name: Generate Aggregate Javadocs run: | diff --git a/.github/workflows/integration-tests-benchmarks.yml b/.github/workflows/integration-tests-benchmarks.yml index 99bc735683b..f196dd53206 100644 --- a/.github/workflows/integration-tests-benchmarks.yml +++ b/.github/workflows/integration-tests-benchmarks.yml @@ -38,7 +38,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 + uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} @@ -88,7 +88,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 + uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} diff --git a/.github/workflows/integration-tests-ui-critical.yml b/.github/workflows/integration-tests-ui-critical.yml index c3d82cd5cb1..a5b91290c9c 100644 --- a/.github/workflows/integration-tests-ui-critical.yml +++ b/.github/workflows/integration-tests-ui-critical.yml @@ -36,7 +36,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 + uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} diff --git a/.github/workflows/integration-tests-ui.yml b/.github/workflows/integration-tests-ui.yml index 44b83d2b7c9..b0e58febbb4 100644 --- a/.github/workflows/integration-tests-ui.yml +++ b/.github/workflows/integration-tests-ui.yml @@ -33,7 +33,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 + uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 84d41833f7a..b16ca7b6959 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -26,7 +26,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 + uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 - name: Build artifacts run: make publish diff --git a/.github/workflows/system-tests-backend.yml b/.github/workflows/system-tests-backend.yml index e6bf48a139f..a052e4a03d7 100644 --- a/.github/workflows/system-tests-backend.yml +++ b/.github/workflows/system-tests-backend.yml @@ -75,7 +75,7 @@ jobs: java-version: '17' - name: Setup Gradle - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 + uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 with: cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} From 58ac0d46e05a2e75c9633d2b121d690f89f1402e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 10:51:57 +0200 Subject: [PATCH 10/12] chore: update scripts/update-sentry-native-ndk.sh to 0.10.0 (#4623) Co-authored-by: GitHub --- CHANGELOG.md | 6 ++++++ gradle/libs.versions.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7be04b36523..ada67ab049d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,12 @@ - Move and flush unfinished previous session on init ([#4624](https://github.com/getsentry/sentry-java/pull/4624)) - This removes the need for unnecessary blocking our background queue for 15 seconds in the case of a background app start +### Dependencies + +- Bump Native SDK from v0.8.4 to v0.10.0 ([#4623](https://github.com/getsentry/sentry-java/pull/4623)) + - [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#0100) + - [diff](https://github.com/getsentry/sentry-native/compare/0.8.4...0.10.0) + ## 8.18.0 ### Features diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4379c63d615..06fa80f9436 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -120,7 +120,7 @@ quartz = { module = "org.quartz-scheduler:quartz", version = "2.3.0" } reactor-core = { module = "io.projectreactor:reactor-core", version = "3.5.3" } retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } retrofit-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" } -sentry-native-ndk = { module = "io.sentry:sentry-native-ndk", version = "0.8.4" } +sentry-native-ndk = { module = "io.sentry:sentry-native-ndk", version = "0.10.0" } servlet-api = { module = "javax.servlet:javax.servlet-api", version = "3.1.0" } servlet-jakarta-api = { module = "jakarta.servlet:jakarta.servlet-api", version = "5.0.0" } slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } From 78dc1799cb4f7544371c1c7c72252a451341733d Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 11 Aug 2025 15:05:42 +0200 Subject: [PATCH 11/12] fix(compose): Switch to compileOnly dependency for compose-ui-material (#4630) * fix(compose): Switch to compileOnly dependency for compose-ui-material * Changelog --- CHANGELOG.md | 2 ++ sentry-compose/build.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ada67ab049d..a7aaeec99fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,8 @@ - Previously events were recorded as lost early despite being retried later through the cache - Move and flush unfinished previous session on init ([#4624](https://github.com/getsentry/sentry-java/pull/4624)) - This removes the need for unnecessary blocking our background queue for 15 seconds in the case of a background app start +- Switch to compileOnly dependency for compose-ui-material ([#4630](https://github.com/getsentry/sentry-java/pull/4630)) + - This fixes `StackOverflowError` when using OSS Licenses plugin ### Dependencies diff --git a/sentry-compose/build.gradle.kts b/sentry-compose/build.gradle.kts index 9624bd018b9..7d0da428a21 100644 --- a/sentry-compose/build.gradle.kts +++ b/sentry-compose/build.gradle.kts @@ -43,8 +43,8 @@ kotlin { dependencies { api(projects.sentry) api(projects.sentryAndroidNavigation) - implementation(libs.androidx.compose.material3) + compileOnly(libs.androidx.compose.material3) compileOnly(libs.androidx.navigation.compose) implementation(libs.androidx.lifecycle.common.java8) } From a9fed8c44a89eed52bc9b79eca5c866b6a149abf Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Mon, 11 Aug 2025 15:06:15 +0200 Subject: [PATCH 12/12] fix(sessions): Move and flush unfinished previous session on init (#4624) * fix(sessions): Move and flush unfinished previous session on init * Changelog * Address PR review --- sentry/src/test/java/io/sentry/SentryTest.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/sentry/src/test/java/io/sentry/SentryTest.kt b/sentry/src/test/java/io/sentry/SentryTest.kt index b152166b80c..3b8549ce00d 100644 --- a/sentry/src/test/java/io/sentry/SentryTest.kt +++ b/sentry/src/test/java/io/sentry/SentryTest.kt @@ -957,9 +957,6 @@ class SentryTest { } } - // to trigger previous session flush - Sentry.startSession() - await.untilTrue(triggered) assertFalse(previousSessionFile.exists()) }