diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java index 7817b5d6c6..5ce2746649 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java @@ -305,6 +305,28 @@ private static void setupProfiler( final @NotNull CompositePerformanceCollector performanceCollector) { if (options.isProfilingEnabled() || options.getProfilesSampleRate() != null) { options.setContinuousProfiler(NoOpContinuousProfiler.getInstance()); + // Transaction-based profiling always relies on the legacy Debug-based profiler, so it is + // disabled together with legacy profiling. Perfetto profiling only supports continuous + // profiling. + if (!options.isEnableLegacyProfiling()) { + options + .getLogger() + .log( + SentryLevel.WARNING, + "Transaction-based profiling (profilesSampleRate/profilesSampler) is disabled " + + "because enableLegacyProfiling is false. Transaction-based profiling always " + + "uses the legacy profiler and is not supported by Perfetto. No profiling " + + "data will be collected. Use profileSessionSampleRate for continuous " + + "profiling instead."); + options.setTransactionProfiler(NoOpTransactionProfiler.getInstance()); + if (appStartTransactionProfiler != null) { + appStartTransactionProfiler.close(); + } + if (appStartContinuousProfiler != null) { + appStartContinuousProfiler.close(true); + } + return; + } // This is a safeguard, but it should never happen, as the app start profiler should be the // continuous one. if (appStartContinuousProfiler != null) { diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt index 229d7ac2b6..855ee03267 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt @@ -424,6 +424,51 @@ class AndroidOptionsInitializerTest { assertEquals(fixture.sentryOptions.continuousProfiler, NoOpContinuousProfiler.getInstance()) } + @Test + fun `init with profilesSampleRate and enableLegacyProfiling false noops both profilers`() { + fixture.initSut( + configureOptions = { + profilesSampleRate = 1.0 + isEnableLegacyProfiling = false + } + ) + + assertEquals(NoOpTransactionProfiler.getInstance(), fixture.sentryOptions.transactionProfiler) + assertEquals(NoOpContinuousProfiler.getInstance(), fixture.sentryOptions.continuousProfiler) + } + + @Test + fun `init with profilesSampler and enableLegacyProfiling false noops both profilers`() { + fixture.initSut( + configureOptions = { + profilesSampler = mock() + isEnableLegacyProfiling = false + } + ) + + assertEquals(NoOpTransactionProfiler.getInstance(), fixture.sentryOptions.transactionProfiler) + assertEquals(NoOpContinuousProfiler.getInstance(), fixture.sentryOptions.continuousProfiler) + } + + @Test + fun `init with profilesSampleRate and enableLegacyProfiling false closes app start profiler`() { + val appStartProfiler = mock() + AppStartMetrics.getInstance().appStartProfiler = appStartProfiler + fixture.initSut( + configureOptions = { + profilesSampleRate = 1.0 + isEnableLegacyProfiling = false + } + ) + + assertEquals(NoOpTransactionProfiler.getInstance(), fixture.sentryOptions.transactionProfiler) + verify(appStartProfiler).close() + + // AppStartMetrics should be cleared + assertNull(AppStartMetrics.getInstance().appStartProfiler) + assertNull(AppStartMetrics.getInstance().appStartContinuousProfiler) + } + @Test fun `init reuses transaction profiler of appStartMetrics, if exists`() { val appStartProfiler = mock() diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 5340e20c6e..db10830c05 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -649,8 +649,8 @@ public class SentryOptions { private boolean startProfilerOnAppStart = false; /** - * When false, the legacy {@code Debug}-based profiler is disabled on API < 35 devices. On API 35+ - * devices, Android's {@code ProfilingManager} (Perfetto-based stack sampling) is always used + * When false, the legacy {@code Debug}-based profiler is disabled on API < 35 devices. On API + * 35+ devices, Android's {@code ProfilingManager} (Perfetto-based stack sampling) is always used * regardless of this setting. This option will be deprecated in the next major release and * removed in the one after. */ @@ -2247,9 +2247,13 @@ public void setStartProfilerOnAppStart(final boolean startProfilerOnAppStart) { } /** - * Whether the legacy {@code Debug}-based profiler is enabled on API < 35 devices. On API 35+, - * Android's {@code ProfilingManager} (Perfetto) is always used regardless of this setting. This - * option will be deprecated in the next major release and removed in the one after. + * Whether the legacy {@code Debug}-based profiler is enabled. This controls continuous profiling + * on API < 35 devices (on API 35+, Android's {@code ProfilingManager} / Perfetto is always + * used for continuous profiling regardless of this setting) as well as transaction-based + * profiling ({@code profilesSampleRate}/{@code profilesSampler}) on all devices, since + * transaction-based profiling always relies on the legacy profiler and is not supported by + * Perfetto. This option will be deprecated in the next major release and removed in the one + * after. * * @return true if legacy profiling is enabled (default). */ @@ -2258,12 +2262,15 @@ public boolean isEnableLegacyProfiling() { } /** - * Set whether the legacy {@code Debug}-based profiler is enabled on API < 35 devices. Set to - * {@code false} to disable profiling on devices below API 35. On API 35+ devices, Android's - * {@code ProfilingManager} (Perfetto) is always used and this setting has no effect. This option - * will be deprecated in the next major release and removed in the one after. + * Set whether the legacy {@code Debug}-based profiler is enabled. Set to {@code false} to disable + * continuous profiling on devices below API 35 (on API 35+ devices, Android's {@code + * ProfilingManager} / Perfetto is always used for continuous profiling and this setting has no + * effect) as well as transaction-based profiling ({@code profilesSampleRate}/{@code + * profilesSampler}) on all devices, since transaction-based profiling always relies on the legacy + * profiler and is not supported by Perfetto. This option will be deprecated in the next major + * release and removed in the one after. * - * @param enableLegacyProfiling false to disable legacy profiling on API < 35. + * @param enableLegacyProfiling false to disable legacy profiling. */ public void setEnableLegacyProfiling(final boolean enableLegacyProfiling) { this.enableLegacyProfiling = enableLegacyProfiling;