Skip to content

Commit 0d34c42

Browse files
43jayclaude
andcommitted
feat(profiling): Add useProfilingManager option
Adds a new boolean option `useProfilingManager` that gates whether the SDK uses Android's ProfilingManager API (API 35+) for Perfetto-based profiling. On devices below API 35 where ProfilingManager is not available, no profiling data is collected — the legacy Debug-based profiler is not used as a fallback. Wired through SentryOptions and ManifestMetadataReader (AndroidManifest meta-data). Defaults to false (opt-in). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e2dce0b commit 0d34c42

File tree

5 files changed

+70
-0
lines changed

5 files changed

+70
-0
lines changed

sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ final class ManifestMetadataReader {
108108

109109
static final String ENABLE_APP_START_PROFILING = "io.sentry.profiling.enable-app-start";
110110

111+
static final String USE_PROFILING_MANAGER = "io.sentry.profiling.use-profiling-manager";
112+
111113
static final String ENABLE_SCOPE_PERSISTENCE = "io.sentry.enable-scope-persistence";
112114

113115
static final String REPLAYS_SESSION_SAMPLE_RATE = "io.sentry.session-replay.session-sample-rate";
@@ -494,6 +496,10 @@ static void applyMetadata(
494496
readBool(
495497
metadata, logger, ENABLE_APP_START_PROFILING, options.isEnableAppStartProfiling()));
496498

499+
options.setUseProfilingManager(
500+
readBool(
501+
metadata, logger, USE_PROFILING_MANAGER, options.isUseProfilingManager()));
502+
497503
options.setEnableScopePersistence(
498504
readBool(
499505
metadata, logger, ENABLE_SCOPE_PERSISTENCE, options.isEnableScopePersistence()));

sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,31 @@ class ManifestMetadataReaderTest {
14691469
assertFalse(fixture.options.isEnableAppStartProfiling)
14701470
}
14711471

1472+
@Test
1473+
fun `applyMetadata reads useProfilingManager flag to options`() {
1474+
// Arrange
1475+
val bundle = bundleOf(ManifestMetadataReader.USE_PROFILING_MANAGER to true)
1476+
val context = fixture.getContext(metaData = bundle)
1477+
1478+
// Act
1479+
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)
1480+
1481+
// Assert
1482+
assertTrue(fixture.options.isUseProfilingManager)
1483+
}
1484+
1485+
@Test
1486+
fun `applyMetadata reads useProfilingManager flag to options and keeps default if not found`() {
1487+
// Arrange
1488+
val context = fixture.getContext()
1489+
1490+
// Act
1491+
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)
1492+
1493+
// Assert
1494+
assertFalse(fixture.options.isUseProfilingManager)
1495+
}
1496+
14721497
@Test
14731498
fun `applyMetadata reads enableScopePersistence flag to options`() {
14741499
// Arrange

sentry/api/sentry.api

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3688,6 +3688,7 @@ public class io/sentry/SentryOptions {
36883688
public fun isTraceOptionsRequests ()Z
36893689
public fun isTraceSampling ()Z
36903690
public fun isTracingEnabled ()Z
3691+
public fun isUseProfilingManager ()Z
36913692
public fun merge (Lio/sentry/ExternalOptions;)V
36923693
public fun setAttachServerName (Z)V
36933694
public fun setAttachStacktrace (Z)V
@@ -3809,6 +3810,7 @@ public class io/sentry/SentryOptions {
38093810
public fun setTransactionProfiler (Lio/sentry/ITransactionProfiler;)V
38103811
public fun setTransportFactory (Lio/sentry/ITransportFactory;)V
38113812
public fun setTransportGate (Lio/sentry/transport/ITransportGate;)V
3813+
public fun setUseProfilingManager (Z)V
38123814
public fun setVersionDetector (Lio/sentry/IVersionDetector;)V
38133815
public fun setViewHierarchyExporters (Ljava/util/List;)V
38143816
}

sentry/src/main/java/io/sentry/SentryOptions.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,13 @@ public class SentryOptions {
622622
*/
623623
private boolean startProfilerOnAppStart = false;
624624

625+
/**
626+
* When true, the SDK uses Android's {@code ProfilingManager} (Perfetto-based stack sampling) on
627+
* API 35+ devices. On older devices where ProfilingManager is not available, no profiling data is
628+
* collected — the legacy {@code Debug}-based profiler is not used as a fallback.
629+
*/
630+
private boolean useProfilingManager = false;
631+
625632
/**
626633
* Controls the deadline timeout in milliseconds for automatic transactions. When set to a
627634
* positive value, that value is used as the deadline timeout. When set to a value less than or
@@ -2213,6 +2220,25 @@ public void setStartProfilerOnAppStart(final boolean startProfilerOnAppStart) {
22132220
this.startProfilerOnAppStart = startProfilerOnAppStart;
22142221
}
22152222

2223+
/**
2224+
* Whether to use Android's ProfilingManager (Perfetto) for profiling on Android 35+.
2225+
*
2226+
* @return true if ProfilingManager-based profiling is enabled.
2227+
*/
2228+
public boolean isUseProfilingManager() {
2229+
return useProfilingManager;
2230+
}
2231+
2232+
/**
2233+
* Set whether to use Android's ProfilingManager (Perfetto) for profiling on Android 35+. On
2234+
* devices below API 35 where ProfilingManager is not available, no profiling data is collected.
2235+
*
2236+
* @param useProfilingManager true to use ProfilingManager-based profiling.
2237+
*/
2238+
public void setUseProfilingManager(final boolean useProfilingManager) {
2239+
this.useProfilingManager = useProfilingManager;
2240+
}
2241+
22162242
public long getDeadlineTimeout() {
22172243
return deadlineTimeout;
22182244
}

sentry/src/test/java/io/sentry/SentryOptionsTest.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,17 @@ class SentryOptionsTest {
750750
assertTrue(options.isEnableAppStartProfiling)
751751
}
752752

753+
@Test
754+
fun `when options are initialized, useProfilingManager is set to false by default`() {
755+
assertFalse(SentryOptions().isUseProfilingManager)
756+
}
757+
758+
@Test
759+
fun `when setUseProfilingManager is called, value is set`() {
760+
val options = SentryOptions().apply { isUseProfilingManager = true }
761+
assertTrue(options.isUseProfilingManager)
762+
}
763+
753764
@Test
754765
fun `when options are initialized, profilingTracesHz is set to 101 by default`() {
755766
assertEquals(101, SentryOptions().profilingTracesHz)

0 commit comments

Comments
 (0)