From 87a7763227272322fef06b78a9e2f8b13132214d Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 6 Aug 2026 16:50:53 +0200 Subject: [PATCH 1/2] perf(android): Defer Session Replay start off SDK init critical path The init-time ReplayController.start() ran synchronously on the main thread at the end of Sentry.init, paying for class-loading the capture strategy graph inline during app start. Post it to the main looper so init returns first. start() is idempotent, so the later lifecycle-driven start remains a no-op if this one ran first. Co-Authored-By: Claude Opus 4.8 --- .../main/java/io/sentry/android/core/SentryAndroid.java | 8 +++++++- .../test/java/io/sentry/android/core/SentryAndroidTest.kt | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java index ab18a5827b9..1989e06078e 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroid.java @@ -3,6 +3,8 @@ import android.annotation.SuppressLint; import android.app.Application; import android.content.Context; +import android.os.Handler; +import android.os.Looper; import android.os.Process; import android.os.SystemClock; import android.os.Trace; @@ -203,7 +205,11 @@ public static void init( scopes.startSession(); } } - scopes.getOptions().getReplayController().start(); + // Defer starting replay off the SDK init critical path so it doesn't add to app start + // time. start() is idempotent, so the later start() from the app lifecycle integration + // (once the first activity is in foreground) is a no-op if this one ran first. + new Handler(Looper.getMainLooper()) + .post(() -> scopes.getOptions().getReplayController().start()); } } catch (IllegalAccessException e) { logger.log(SentryLevel.FATAL, "Fatal error during SentryAndroid.init(...)", e); diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt index 2bd26051c07..d3239ebb1e6 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt @@ -352,6 +352,8 @@ class SentryAndroidTest { @Config(sdk = [26]) fun `init starts session replay if app is in foreground`() { initSentryWithForegroundImportance(true) { _ -> + // replay start is posted to the main looper, so drain it before asserting + Shadows.shadowOf(Looper.getMainLooper()).idle() assertTrue(Sentry.getCurrentHub().options.replayController.isRecording()) } } From 9495885a90ce71cc7d23c2bd87c12d19892f05d5 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 6 Aug 2026 16:51:46 +0200 Subject: [PATCH 2/2] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1da07233a0f..ff11b3220f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Performance + +- Defer starting Session Replay off the `Sentry.init` critical path to reduce app start time ([#5904](https://github.com/getsentry/sentry-java/pull/5904)) + ### Fixes - Clear contexts when calling `Scope.clear()` ([#5902](https://github.com/getsentry/sentry-java/pull/5902))