Skip to content

Conversation

@markushi
Copy link
Member

📜 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
  • AnrProfileManager to manage ANR profile lifecycle
  • AnrCulpritIdentifier to identify the culprit code causing ANR
  • Stack trace and profile aggregation utilities
  • Added comprehensive tests for ANR profiling functionality

💡 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?

  • Unit tests for AnrCulpritIdentifier with various stack trace scenarios
  • Integration tests for AnrProfilingIntegration
  • Profile manager lifecycle tests
  • Stack trace converter 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 5824f8f

Comment on lines 326 to 327
final AnrProfileManager provider = new AnrProfileManager(options);
anrProfile = provider.load();
Copy link

Choose a reason for hiding this comment

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

Bug: AnrProfilingIntegration and AnrV2Integration concurrently access the same QueueFile without synchronization.
Severity: CRITICAL | Confidence: 1.00

🔍 Detailed Analysis

The AnrProfilingIntegration (writer) and AnrV2Integration (reader) concurrently access the same underlying QueueFile at options.getCacheDirPath() + "anr_profile" without any synchronization. This violates the explicit contract of QueueFile which states, "Only one instance should access a given file at a time." Concurrent unsynchronized access can lead to data corruption, lost stack traces, or file format inconsistencies due to conflicting writes and reads to the shared file header and data structures.

💡 Suggested Fix

Implement a synchronization mechanism (e.g., file-level locking) to ensure exclusive access to the QueueFile, or refactor to use a single QueueFile instance managed by a central component.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location:
sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java#L326-L327

Potential issue: The `AnrProfilingIntegration` (writer) and `AnrV2Integration` (reader)
concurrently access the same underlying `QueueFile` at `options.getCacheDirPath() +
"anr_profile"` without any synchronization. This violates the explicit contract of
`QueueFile` which states, "Only one instance should access a given file at a time."
Concurrent unsynchronized access can lead to data corruption, lost stack traces, or file
format inconsistencies due to conflicting writes and reads to the shared file header and
data structures.

Did we get this right? 👍 / 👎 to inform future reviews.

Reference_id: 2623394

}
} catch (IOException e) {
logger.log(ERROR, "Failed to create stacktrace queue", e);
}
Copy link

Choose a reason for hiding this comment

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

Bug: AnrProfileManager instances created in AnrV2Integration are not closed, leading to file descriptor leaks.
Severity: CRITICAL | Confidence: 1.00

🔍 Detailed Analysis

Instances of AnrProfileManager created within AnrV2Integration.applyAnrProfile() are not properly closed. Each AnrProfileManager creates an underlying QueueFile which holds a RandomAccessFile resource. Since AnrProfileManager does not implement Closeable and its ObjectQueue field is never closed, these RandomAccessFile instances remain open indefinitely. This leads to file descriptor leaks, which can exhaust system resources and cause failures, especially if multiple ANR events occur.

💡 Suggested Fix

Ensure AnrProfileManager implements Closeable and its close() method is called after use, for example, by wrapping its instantiation and usage in a try-with-resources block.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location:
sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileManager.java#L47

Potential issue: Instances of `AnrProfileManager` created within
`AnrV2Integration.applyAnrProfile()` are not properly closed. Each `AnrProfileManager`
creates an underlying `QueueFile` which holds a `RandomAccessFile` resource. Since
`AnrProfileManager` does not implement `Closeable` and its `ObjectQueue` field is never
closed, these `RandomAccessFile` instances remain open indefinitely. This leads to file
descriptor leaks, which can exhaust system resources and cause failures, especially if
multiple ANR events occur.

Did we get this right? 👍 / 👎 to inform future reviews.

Reference_id: 2623394

@github-actions
Copy link
Contributor

github-actions bot commented Nov 12, 2025

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 311.43 ms 365.32 ms 53.89 ms
Size 1.58 MiB 2.13 MiB 558.96 KiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
ee747ae 415.92 ms 470.15 ms 54.23 ms
9fbb112 401.87 ms 515.87 ms 114.00 ms
9fbb112 404.51 ms 475.65 ms 71.14 ms
604a261 380.65 ms 451.27 ms 70.62 ms
674d437 355.28 ms 504.18 ms 148.90 ms
33a08cc 267.08 ms 340.45 ms 73.37 ms
27d7cf8 309.43 ms 364.27 ms 54.85 ms
96449e8 361.30 ms 423.39 ms 62.09 ms
c8125f3 397.65 ms 485.14 ms 87.49 ms
ee747ae 382.73 ms 435.41 ms 52.68 ms

App size

Revision Plain With Sentry Diff
ee747ae 1.58 MiB 2.10 MiB 530.95 KiB
9fbb112 1.58 MiB 2.11 MiB 539.18 KiB
9fbb112 1.58 MiB 2.11 MiB 539.18 KiB
604a261 1.58 MiB 2.10 MiB 533.42 KiB
674d437 1.58 MiB 2.10 MiB 530.94 KiB
33a08cc 1.58 MiB 2.12 MiB 555.28 KiB
27d7cf8 1.58 MiB 2.12 MiB 549.42 KiB
96449e8 1.58 MiB 2.11 MiB 539.35 KiB
c8125f3 1.58 MiB 2.10 MiB 532.32 KiB
ee747ae 1.58 MiB 2.10 MiB 530.95 KiB

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

Startup times

Revision Plain With Sentry Diff
184b846 276.09 ms 351.65 ms 75.56 ms

App size

Revision Plain With Sentry Diff
184b846 1.58 MiB 2.13 MiB 558.70 KiB

options);
chunk.setSentryProfile(profile);

options.getLogger().log(SentryLevel.DEBUG, "");
Copy link

Choose a reason for hiding this comment

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

Bug: Silence the Empty Debug Logs

Empty debug log statement with no message at options.getLogger().log(SentryLevel.DEBUG, "") appears to be accidentally committed debugging code that provides no diagnostic value and should be removed or given a meaningful message.

Fix in Cursor Fix in Web

anrProfile = provider.load();
} catch (Throwable t) {
options.getLogger().log(SentryLevel.INFO, "Could not retrieve ANR profile");
}
Copy link

Choose a reason for hiding this comment

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

Bug: Concurrent File Access Causes Data Corruption

Creating a new AnrProfileManager instance in applyAnrProfile while AnrProfilingIntegration may still be running creates a race condition. Both instances open file handles to the same anr_profile file, potentially corrupting data as AnrProfilingIntegration writes while AnrV2Integration reads and closes the queue file, leading to concurrent access issues with the underlying QueueFile.

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