feat(anr): Profile main thread when ANR and report ANR profiles to Sentry#4899
feat(anr): Profile main thread when ANR and report ANR profiles to Sentry#4899
Conversation
|
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileManager.java
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrCulpritIdentifier.java
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AggregatedStackTrace.java
Outdated
Show resolved
Hide resolved
Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| b6cfb57 | 372.92 ms | 507.77 ms | 134.85 ms |
| ce0a49e | 532.00 ms | 609.96 ms | 77.96 ms |
| e59e22a | 374.68 ms | 442.14 ms | 67.46 ms |
| fc5ccaf | 256.80 ms | 322.36 ms | 65.56 ms |
| d15471f | 294.13 ms | 399.49 ms | 105.36 ms |
| d15471f | 303.49 ms | 439.08 ms | 135.59 ms |
| abfcc92 | 337.38 ms | 427.39 ms | 90.00 ms |
| ee35ac3 | 346.83 ms | 435.48 ms | 88.65 ms |
| d15471f | 322.58 ms | 396.08 ms | 73.50 ms |
| f634d01 | 359.58 ms | 433.88 ms | 74.30 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| b6cfb57 | 1.58 MiB | 2.28 MiB | 718.80 KiB |
| ce0a49e | 1.58 MiB | 2.10 MiB | 532.94 KiB |
| e59e22a | 1.58 MiB | 2.20 MiB | 635.34 KiB |
| fc5ccaf | 1.58 MiB | 2.13 MiB | 557.54 KiB |
| d15471f | 1.58 MiB | 2.13 MiB | 559.54 KiB |
| d15471f | 1.58 MiB | 2.13 MiB | 559.54 KiB |
| abfcc92 | 1.58 MiB | 2.13 MiB | 557.31 KiB |
| ee35ac3 | 1.58 MiB | 2.13 MiB | 558.77 KiB |
| d15471f | 1.58 MiB | 2.13 MiB | 559.54 KiB |
| f634d01 | 1.58 MiB | 2.10 MiB | 533.40 KiB |
Previous results on branch: markushi/feat/anr-profiling
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 00299fd | 359.87 ms | 424.85 ms | 64.98 ms |
| 4c0ffee | 314.94 ms | 377.79 ms | 62.86 ms |
| ddbbe91 | 289.51 ms | 359.74 ms | 70.23 ms |
| 2cee1ab | 318.29 ms | 361.00 ms | 42.71 ms |
| eb02e45 | 362.67 ms | 431.71 ms | 69.04 ms |
| fca8df8 | 326.79 ms | 379.69 ms | 52.90 ms |
| fa76e86 | 274.32 ms | 349.63 ms | 75.31 ms |
| eb7143a | 347.66 ms | 408.54 ms | 60.88 ms |
| 83a9ec4 | 333.84 ms | 390.30 ms | 56.47 ms |
| c10e603 | 367.92 ms | 393.50 ms | 25.58 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 00299fd | 1.58 MiB | 2.29 MiB | 723.50 KiB |
| 4c0ffee | 1.58 MiB | 2.29 MiB | 723.67 KiB |
| ddbbe91 | 1.58 MiB | 2.29 MiB | 724.15 KiB |
| 2cee1ab | 1.58 MiB | 2.29 MiB | 723.68 KiB |
| eb02e45 | 1.58 MiB | 2.29 MiB | 725.26 KiB |
| fca8df8 | 1.58 MiB | 2.29 MiB | 723.68 KiB |
| fa76e86 | 1.58 MiB | 2.29 MiB | 724.06 KiB |
| eb7143a | 1.58 MiB | 2.29 MiB | 724.12 KiB |
| 83a9ec4 | 1.58 MiB | 2.29 MiB | 723.99 KiB |
| c10e603 | 1.58 MiB | 2.29 MiB | 723.72 KiB |
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrCulpritIdentifier.java
Show resolved
Hide resolved
…ntry-java into markushi/feat/anr-profiling
sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrStackTrace.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java
Show resolved
Hide resolved
|
@sentry review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/StackTraceConverter.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileRotationHelper.java
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileRotationHelper.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfile.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileManager.java
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileManager.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileManager.java
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrCulpritIdentifier.java
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileRotationHelper.java
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java
Show resolved
Hide resolved
romtsn
left a comment
There was a problem hiding this comment.
Great work already! I believe there are some things to address but I can check once more after that
sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| value.serialize(dos); | ||
| dos.flush(); | ||
| } | ||
| sink.flush(); |
There was a problem hiding this comment.
toStream closes caller-owned stream then flushes it
Low Severity
The toStream converter wraps sink in a DataOutputStream try-with-resources, which closes both dos and the underlying sink when the block exits. The sink.flush() call afterward operates on an already-closed stream. This works only because the actual sink from FileObjectQueue is a ByteArrayOutputStream where close() is a no-op, but the pattern violates stream ownership conventions and the post-close flush is dead code.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable autofix in the Cursor dashboard.
| } | ||
| } | ||
| return true; | ||
| } |
There was a problem hiding this comment.
hasOnlySystemFrames returns true with no frames present
Medium Severity
hasOnlySystemFrames returns true when exceptions have no stacktrace or empty frames, not just when all frames are system frames. When the main thread is absent from the ANR thread dump, setAnrExceptions creates a dummy exception with a null stacktrace. The loop in hasOnlySystemFrames skips exceptions with null stacktraces and never finds any non-system frame, so it returns true. This causes setDefaultAnrFingerprint to apply the "system-frames-only-anr" fingerprint, grouping these no-information ANRs with ANRs that genuinely contain only system frames — two different categories that likely warrant separate investigation.
Additional Locations (1)
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable autofix in the Cursor dashboard.
| if (thread == null) { | ||
| error = new ApplicationNotResponding(message); | ||
| } else { | ||
| error = new ApplicationNotResponding(message, anr.getThread()); |
There was a problem hiding this comment.
Redundant method call bypasses local null-checked variable
Low Severity
The local variable thread is assigned from anr.getThread() on line 142 and null-checked on line 144, but the else branch on line 147 calls anr.getThread() again instead of using the already-validated thread variable. The thread local variable was created specifically to handle the null case, so the else branch can safely pass thread directly to the constructor.


📜 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:
AnrProfilingIntegrationto capture profiles during ANR eventsAnrV2Integrationnow takes care of matching and capturing the profile on the next start💡 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.
Example event: https://sentry-sdks.sentry.io/issues/7229210096/events/4598ff6fcc0f402d8ecca615005e7f64/
💚 How did you test it?
📝 Checklist
sendDefaultPIIis enabled.🔮 Next steps