Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
9a60ad1
feat(profiling): Add useProfilingManager option
43jay Mar 27, 2026
1250aa1
chore(samples): Update sample app to support Perfetto profiling testing
43jay Mar 27, 2026
05d73b1
chore(samples): Improve ProfilingActivity UI for Perfetto testing
43jay Apr 7, 2026
5f894d0
feat(profiling): Skip legacy app-start profiling when useProfilingMan…
43jay Mar 27, 2026
c2a4442
feat(profiling): Add PerfettoProfiler and wire into AndroidContinuous…
43jay Mar 30, 2026
bc2e59d
fix(profiling): Fix meta_length not serialized in Perfetto envelope h…
43jay Apr 9, 2026
a53c383
ref(profiling): Extract PerfettoContinuousProfiler from AndroidContin…
43jay Apr 1, 2026
dd2c5a4
test(profiling): Extract shared profiler test cases into ContinuousPr…
43jay Apr 10, 2026
6ebea19
test(profiling): Wire PerfettoContinuousProfilerTest to shared test c…
43jay Apr 1, 2026
5e4bead
ref(profiling): Remove app-start profiling logic from PerfettoContinu…
43jay Apr 7, 2026
443cc45
ref(profiling): Improve thread safety in PerfettoContinuousProfiler
43jay Apr 7, 2026
dcee449
chore: Run spotlessApply and apiDump
43jay Apr 7, 2026
331622b
ref(profiling): Move frame metrics collection from PerfettoProfiler t…
43jay Apr 10, 2026
85e54fc
ref(profiling): Consolidate measurement collection into ChunkMeasurem…
43jay Apr 10, 2026
11331ea
fix(profiling): Move shouldStop reset inside !isRunning() guard
43jay Apr 13, 2026
4c48101
Format code
getsentry-bot Apr 13, 2026
35b2bcb
fix(profiling): Add API level guard for PerfettoContinuousProfiler
43jay Apr 13, 2026
268a1e0
fix(profiling): Snapshot frame measurement deques before async serial…
43jay Apr 17, 2026
ffd5c6b
Format code
getsentry-bot Apr 17, 2026
a1e703e
review-feedback: Revert any change to AndroidContinuousProfiler
43jay Apr 20, 2026
0c7f8fd
review-feedback: Regenerate sentry.api to match public surface
43jay Apr 20, 2026
1a6742c
review-feedback: Fix meta_length omitted from Perfetto envelope header
43jay Apr 20, 2026
e387e89
fix(profiler): restore ns-since-chunk-start conversion for Perfetto m…
43jay Apr 21, 2026
cd26427
Format code
getsentry-bot Apr 22, 2026
d760522
Address lock and thread issues, add tests
markushi May 15, 2026
e3a6c2b
Refine comment
markushi May 15, 2026
8a37dec
Simplify profiling activity, switch to compose
markushi May 15, 2026
bab9781
fix(profiler): Flush BufferedWriter before reading metadata bytes and…
markushi May 15, 2026
b4c224a
Merge branch 'main' into claude/dreamy-solomon
markushi May 15, 2026
8c560c6
Update content type to match relay
markushi May 15, 2026
ac104ed
Fix async callback race condition
markushi May 15, 2026
6e522f6
Fix api files
markushi May 15, 2026
24bcfed
fix(profiler): Address Perfetto profiling PR review feedback
markushi Jun 18, 2026
9c8285a
feat(profiling): replace useProfilingManager with enableLegacyProfili…
romtsn Jun 26, 2026
c53be37
Format code
getsentry-bot Jun 26, 2026
bc39a7d
feat(profiling): undeprecate enableLegacyProfiling
romtsn Jun 29, 2026
9648cd5
Format code
getsentry-bot Jun 29, 2026
c787eeb
fix: undeprecate enableLegacyProfiling in SentryAppStartProfilingOptions
romtsn Jun 29, 2026
a49856e
api dump
romtsn Jun 29, 2026
5149ee9
fix: resolve app context before lambda to prevent Activity leak
romtsn Jun 29, 2026
ad4925c
Format code
getsentry-bot Jun 29, 2026
642e7a5
fix: update expected JSON in SentryAppStartProfilingOptions serializa…
romtsn Jun 29, 2026
9c9715f
Merge branch 'main' into claude/dreamy-solomon
markushi Jul 14, 2026
9d3cb80
fix(profiling): Disable transaction-based profiling when enableLegacy…
markushi Jul 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions sentry-android-core/api/sentry-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,24 @@ public final class io/sentry/android/core/NetworkBreadcrumbsIntegration : io/sen
public fun register (Lio/sentry/IScopes;Lio/sentry/SentryOptions;)V
}

public class io/sentry/android/core/PerfettoContinuousProfiler : io/sentry/IContinuousProfiler, io/sentry/transport/RateLimiter$IRateLimitObserver {
public fun <init> (Lio/sentry/ILogger;Lio/sentry/android/core/internal/util/SentryFrameMetricsCollector;Lio/sentry/util/LazyEvaluator$Evaluator;Ljava/util/function/Supplier;)V
public fun close (Z)V
public fun getChunkId ()Lio/sentry/protocol/SentryId;
public fun getProfilerId ()Lio/sentry/protocol/SentryId;
public fun isRunning ()Z
public fun onRateLimitChanged (Lio/sentry/transport/RateLimiter;)V
public fun reevaluateSampling ()V
public fun startProfiler (Lio/sentry/ProfileLifecycle;Lio/sentry/TracesSampler;)V
public fun stopProfiler (Lio/sentry/ProfileLifecycle;)V
}

public class io/sentry/android/core/PerfettoProfiler {
public fun <init> (Landroid/content/Context;Lio/sentry/ILogger;Lio/sentry/ISentryExecutorService;)V
public fun endAndCollect (Ljava/util/function/Consumer;)V
public fun start (J)Z
}
Comment thread
cursor[bot] marked this conversation as resolved.

public final class io/sentry/android/core/ScreenshotEventProcessor : io/sentry/EventProcessor {
public fun <init> (Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/BuildInfoProvider;Z)V
public fun getOrder ()Ljava/lang/Long;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.VisibleForTesting;

/**
* Legacy Android implementation of {@link IContinuousProfiler}, using Android's {@code
* Debug.startMethodTracingSampling} See {@link PerfettoContinuousProfiler} for the new
* implementation using {@code ProfilingManager}, available on API 35+.
*/
@ApiStatus.Internal
public class AndroidContinuousProfiler
implements IContinuousProfiler, RateLimiter.IRateLimitObserver {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static io.sentry.android.core.NdkIntegration.SENTRY_NDK_CLASS_NAME;

import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
Expand Down Expand Up @@ -294,6 +295,7 @@ static void initializeIntegrationsAndProcessors(
}

/** Setup the correct profiler (transaction or continuous) based on the options. */
@SuppressLint("NewApi")
private static void setupProfiler(
final @NotNull SentryAndroidOptions options,
final @NotNull Context context,
Expand All @@ -303,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) {
Expand Down Expand Up @@ -336,16 +360,36 @@ private static void setupProfiler(
performanceCollector.start(chunkId.toString());
}
} else {
options.setContinuousProfiler(
new AndroidContinuousProfiler(
buildInfoProvider,
Objects.requireNonNull(
options.getFrameMetricsCollector(),
"options.getFrameMetricsCollector is required"),
options.getLogger(),
options.getProfilingTracesDirPath(),
options.getProfilingTracesHz(),
() -> options.getExecutorService()));
final @NotNull SentryFrameMetricsCollector frameMetricsCollector =
Objects.requireNonNull(
options.getFrameMetricsCollector(), "options.getFrameMetricsCollector is required");
if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
final @NotNull Context appContext = context.getApplicationContext();
options.setContinuousProfiler(
new PerfettoContinuousProfiler(
options.getLogger(),
frameMetricsCollector,
() -> options.getExecutorService(),
() ->
new PerfettoProfiler(
appContext, options.getLogger(), options.getExecutorService())));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Null app context crashes profiling

Medium Severity

setupProfiler assigns context.getApplicationContext() directly into a @NotNull variable and captures it in the PerfettoProfiler factory. That call can return null (which is why ContextUtils.getApplicationContext exists and is used elsewhere in this file), so the first startInternal can throw when creating PerfettoProfiler.

Fix in CursorΒ Fix in Web

Reviewed by Cursor Bugbot for commit 9c9715f. Configure here.

} else if (options.isEnableLegacyProfiling()) {
options.setContinuousProfiler(
new AndroidContinuousProfiler(
buildInfoProvider,
frameMetricsCollector,
options.getLogger(),
options.getProfilingTracesDirPath(),
options.getProfilingTracesHz(),
() -> options.getExecutorService()));
} else {
options
.getLogger()
.log(
SentryLevel.WARNING,
"enableLegacyProfiling is disabled and device is below API 35. "
+ "No profiling data will be collected.");
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ final class ManifestMetadataReader {

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

static final String ENABLE_LEGACY_PROFILING = "io.sentry.profiling.enable-legacy-profiling";

static final String ENABLE_SCOPE_PERSISTENCE = "io.sentry.enable-scope-persistence";

static final String REPLAYS_SESSION_SAMPLE_RATE = "io.sentry.session-replay.session-sample-rate";
Expand Down Expand Up @@ -542,6 +544,9 @@ static void applyMetadata(
readBool(
metadata, logger, ENABLE_APP_START_PROFILING, options.isEnableAppStartProfiling()));

options.setEnableLegacyProfiling(
readBool(metadata, logger, ENABLE_LEGACY_PROFILING, options.isEnableLegacyProfiling()));

options.setEnableScopePersistence(
readBool(
metadata, logger, ENABLE_SCOPE_PERSISTENCE, options.isEnableScopePersistence()));
Expand Down
Loading
Loading