Skip to content

Conversation

@markushi
Copy link
Member

@markushi markushi commented Nov 12, 2025

📜 Description

Adds ANR (Application Not Responding) profiling integration that profiles the main thread when an ANR is detected and reports the captured profiles to Sentry.

Key Changes:

  • New AnrProfilingIntegration to capture profiles during ANR events
  • AnrV2Integration now takes care of matching and capturing the profile on the next start
  • If the captured ANR event only contains system frames, a static fingerprint will get set, effectively changing the grouping behavior to group all noisy ANRs into a single issue

💡 Motivation and Context

This feature enables better ANR diagnostics by capturing profiling data at the time of ANR detection, allowing developers to identify performance bottlenecks and problematic code paths causing application hangs.

💚 How did you test it?

  • Added tests

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

🔮 Next steps

@github-actions
Copy link
Contributor

github-actions bot commented Nov 12, 2025

Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against 4c95292

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Nov 12, 2025

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 304.53 ms 351.20 ms 46.67 ms
Size 1.58 MiB 2.13 MiB 563.71 KiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
3d205d0 352.15 ms 432.53 ms 80.38 ms
fc5ccaf 256.80 ms 322.36 ms 65.56 ms
ee747ae 374.71 ms 455.18 ms 80.47 ms
6edfca2 314.02 ms 383.20 ms 69.18 ms
674d437 355.28 ms 504.18 ms 148.90 ms
6405ec5 310.88 ms 354.56 ms 43.69 ms
bbc35bb 324.88 ms 425.73 ms 100.85 ms
dba088c 321.78 ms 364.59 ms 42.82 ms
fc5ccaf 279.11 ms 353.34 ms 74.23 ms
3699cd5 423.60 ms 495.52 ms 71.92 ms

App size

Revision Plain With Sentry Diff
3d205d0 1.58 MiB 2.10 MiB 532.97 KiB
fc5ccaf 1.58 MiB 2.13 MiB 557.54 KiB
ee747ae 1.58 MiB 2.10 MiB 530.95 KiB
6edfca2 1.58 MiB 2.13 MiB 559.07 KiB
674d437 1.58 MiB 2.10 MiB 530.94 KiB
6405ec5 1.58 MiB 2.12 MiB 552.23 KiB
bbc35bb 1.58 MiB 2.12 MiB 553.01 KiB
dba088c 1.58 MiB 2.13 MiB 558.99 KiB
fc5ccaf 1.58 MiB 2.13 MiB 557.54 KiB
3699cd5 1.58 MiB 2.10 MiB 533.45 KiB

Previous results on branch: markushi/feat/anr-profiling

Startup times

Revision Plain With Sentry Diff
be4960b 322.67 ms 380.85 ms 58.18 ms
184b846 276.09 ms 351.65 ms 75.56 ms
b238cff 332.00 ms 401.47 ms 69.47 ms
c22421f 331.24 ms 367.91 ms 36.67 ms
a4af52f 304.52 ms 364.92 ms 60.40 ms

App size

Revision Plain With Sentry Diff
be4960b 1.58 MiB 2.13 MiB 562.64 KiB
184b846 1.58 MiB 2.13 MiB 558.70 KiB
b238cff 1.58 MiB 2.13 MiB 562.66 KiB
c22421f 1.58 MiB 2.13 MiB 563.53 KiB
a4af52f 1.58 MiB 2.13 MiB 563.53 KiB

@markushi markushi marked this pull request as draft December 3, 2025 07:19
@markushi
Copy link
Member Author

@sentry review

@markushi markushi marked this pull request as ready for review December 17, 2025 09:51
Copy link
Member Author

@markushi markushi left a comment

Choose a reason for hiding this comment

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

Addressing bot comments:

Concurrent QueueFile Access (Comments on AnrV2Integration.java:327, :367):
✅ Working as designed. The reader uses AnrProfileRotationHelper.getLastFile() which reads from a rotated/archived file, while the writer writes to the current file. They access different files.

AnrProfileManager file descriptor leak (AnrProfileManager.java:50):
✅ Already fixed. The code uses try-with-resources: try (final AnrProfileManager provider = new AnrProfileManager(options, lastFile))

lowQualityPackages initialization (AnrCulpritIdentifier.java:85):
✅ Already fixed. The field uses a static initializer block.

Stack depth calculation (AggregatedStackTrace.java:38):
✅ Already fixed.

Incomplete stack trace handling (AnrCulpritIdentifier.java:138):
✅ Already fixed. Code has if (stackTraceMap.isEmpty()) return null; guard at line 140.

Empty debug log (AnrV2Integration.java:346):
✅ Already fixed.

Missing rotate() call (AnrV2Integration.java:424):
✅ Working as designed. Rotation should only happen once after app start, not on every ANR event read.

Stack trace serialization (AnrStackTrace.java:35):
✅ Already fixed.

Missing listener removal (AnrProfilingIntegration.java:79):
✅ Already fixed.

Profile ID mismatch (AnrV2Integration.java:418):
✅ Working as designed. We intentionally return chunk.getProfilerId() to reference the chunk_id as profiler_id.

hasOnlySystemFrames() fingerprinting (AnrV2Integration.java:321, :497):
✅ FIXED in this update. Modified to return false when exceptions list is null/empty, preventing incorrect fingerprinting when profiling fails.

@linear
Copy link

linear bot commented Jan 30, 2026

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

final @NotNull SentryOptions opts =
Objects.requireNonNull(options, "Options can't be null");
final @NotNull File currentFile =
AnrProfileRotationHelper.getFileForRecording(new File(opts.getCacheDirPath()));
Copy link

Choose a reason for hiding this comment

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

Missing null check for cacheDirPath causes NPE

Medium Severity

When opts.getCacheDirPath() returns null, new File(null) throws a NullPointerException. Unlike AnrV2Integration which checks for null cacheDirPath before using it (line 94 and 236), AnrProfilingIntegration has no such validation. If ANR profiling is enabled but cacheDirPath is null, the integration will register itself as a listener, and upon the first ANR suspicion, calling clearStacks() or addStackTrace() will crash.

Fix in Cursor Fix in Web


if (this.options == null) {
return;
}
Copy link

Choose a reason for hiding this comment

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

Dead code due to requireNonNull throwing before null check

Low Severity

The if (this.options == null) return; check is unreachable dead code. Objects.requireNonNull on line 51-54 throws an IllegalArgumentException when the ternary expression evaluates to null (i.e., when options is not a SentryAndroidOptions). The null check can never execute because the exception is thrown first.

Fix in Cursor Fix in Web

if (!AnrProfileRotationHelper.deleteLastFile(cacheDir)) {
options.getLogger().log(SentryLevel.INFO, "Could not delete ANR profile file");
}
}
Copy link

Choose a reason for hiding this comment

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

Profile file deleted prematurely when reporting historical ANRs

Medium Severity

The ANR profile file is deleted in a finally block on every call to applyAnrProfile, regardless of whether the profile was actually matched and used. When reportHistoricalAnrs is enabled, historical ANRs are processed before the latest ANR. Each historical ANR triggers applyAnrProfile, which deletes the profile file even though the timestamp doesn't match. By the time the latest ANR (which should match the profile) is processed, the file is already deleted and the profile is lost.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants