-
-
Notifications
You must be signed in to change notification settings - Fork 464
feat: minimal tombstone integration #4933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: minimal tombstone integration #4933
Conversation
sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java
Outdated
Show resolved
Hide resolved
|
@markushi, I just realized I cannot omit having a separate "tombstone" marker, even if I report all events, without repeating them. I mean, this was clear to me, but, in addition to it being a must for this PR already, unlike the ANR marker, I must also align it with I wonder if it would make the most sense to do it similarly to The biggest issue with that approach is that the The PR still makes sense for a first review from you (since, if the general direction makes sense and you have todos not in my list, I can also add a test for the integration itself). Still, I would appreciate a short sync on how to align these execution paths (maybe I don't need to align tombstones with I can convert the PR back to a draft if you prefer. |
markushi
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a few comments - great work so far!
...ry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java
Outdated
Show resolved
Hide resolved
...ry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java
Outdated
Show resolved
Hide resolved
...ry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java
Outdated
Show resolved
Hide resolved
...ry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java
Show resolved
Hide resolved
...ry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java
Outdated
Show resolved
Hide resolved
sentry-android-core/src/main/proto/io/sentry/android/core/internal/tombstone/tombstone.proto
Show resolved
Hide resolved
Co-authored-by: Markus Hintersteiner <[email protected]>
...ry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java
Show resolved
Hide resolved
sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java
Outdated
Show resolved
Hide resolved
… S, since that is the earliest version where `REASON_CRASH_NATIVE` provides tombstones via the `traceInputStream`)
sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java
Outdated
Show resolved
Hide resolved
…rker This currently does not work: While we now can optionally enable reporting of "historical" tombstones, by making the `TombstoneHint` `Backfillable` it will automatically be enriched by the `ANRv2EventProcessor` which is currently the only `BackfillingEventProcessor`. The `ANRv2EventProcessor` is partially written in way that is potentially generic for events with `Backfillable` hints, but other parts are enriching as if those are always were ANRs, which up to now was true, but with Tombstones that assumption now breaks. Next Steps: * There is considerable duplication between the ANRv2Integration and TombstoneIntegration
sentry-android-core/src/main/java/io/sentry/android/core/AnrV2EventProcessor.java
Outdated
Show resolved
Hide resolved
…tProcessor this handles all events with Backfillable hint, but adds an interface HintEnricher, to allow hint-specific enrichment (like for ANRs) before and after the generic backfilling happened.
sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java
Show resolved
Hide resolved
| @NotNull SentryEvent event, @NotNull Backfillable hint, @NotNull Object rawHint); | ||
| } | ||
|
|
||
| private final class AnrHintEnricher implements HintEnricher { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like a pretty good solution to me, nice!
sentry-android-core/src/main/java/io/sentry/android/core/TombstoneEventProcessor.java
Outdated
Show resolved
Hide resolved
...-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoHistoryDispatcher.java
Show resolved
Hide resolved
… iterator instead of for-each
sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java
Show resolved
Hide resolved
...ry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java
Outdated
Show resolved
Hide resolved
| if (mainThread == null) { | ||
| // if there's no main thread in the event threads, we just create a dummy thread so the | ||
| // exception is properly created as well, but without stacktrace | ||
| mainThread = new SentryThread(); | ||
| mainThread.setStacktrace(new SentryStackTrace()); | ||
| } | ||
| event.setExceptions( | ||
| sentryExceptionFactory.getSentryExceptionsFromThread(mainThread, mechanism, anr)); | ||
| } | ||
| } | ||
| // endregion | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: app.inForeground is missing for TombstoneHint events due to AnrHintEnricher not supporting NativeCrashExit hints.
Severity: HIGH | Confidence: High
🔍 Detailed Analysis
The app.inForeground field is no longer set for TombstoneHint (native crash) events. The new code moved inForeground logic to AnrHintEnricher.setAppForeground(), which only supports AbnormalExit (ANR) hints. As a result, when ApplicationExitInfoEventProcessor.process() handles a TombstoneHint, no enricher is found, and setAppForeground() is never invoked. This is a functional regression, causing missing context data for native crash events that was previously available.
💡 Suggested Fix
Extend AnrHintEnricher or create a dedicated enricher (e.g., TombstoneHintEnricher) to support NativeCrashExit hints and set the app.inForeground field for TombstoneHint events.
🤖 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/ApplicationExitInfoEventProcessor.java#L665-L782
Potential issue: The `app.inForeground` field is no longer set for `TombstoneHint`
(native crash) events. The new code moved `inForeground` logic to
`AnrHintEnricher.setAppForeground()`, which only supports `AbnormalExit` (ANR) hints. As
a result, when `ApplicationExitInfoEventProcessor.process()` handles a `TombstoneHint`,
no enricher is found, and `setAppForeground()` is never invoked. This is a functional
regression, causing missing context data for native crash events that was previously
available.
Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 6496195
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is 100% intentional from my side, at least for now.
|
|
||
| final SentryStackTrace stacktrace = createStackTrace(threadEntryValue); | ||
| thread.setStacktrace(stacktrace); | ||
| if (tombstone.getTid() == threadEntryValue.getId()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Inconsistent thread ID source may misidentify crashed thread
The SentryThread.id is set from threadEntry.getKey() (the map key), but the crashed thread identification on line 77 compares tombstone.getTid() with threadEntryValue.getId() (the Thread's internal id field). If these values ever differ, the crashed thread would not be correctly identified. For consistency and correctness, the comparison at line 77 should use threadEntry.getKey() instead of threadEntryValue.getId(), since that's the source used to set the thread ID.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is also intentional, because the key and the ID should be equivalent.
|
@markushi and @romtsn, I think I also found an okay solution to reduce duplication between the tests for the two AEI integrations. That means the first three "milestones" required for a release (without Native SDK event enrichment/merging) are finished. Please let me know if something is missing from your POV or not yet up to par, and how you would like to proceed. Btw, multiple |
| // TODO: if we align this with ANRv2 this would be overwritten in a BackfillingEventProcessor as | ||
| // `ApplicationExitInfo` not sure what the right call is. `ApplicationExitInfo` is | ||
| // certainly correct. But `signalhandler` isn't wrong either, since all native crashes | ||
| // retrieved via `REASON_CRASH_NATIVE` will be signals. I am not sure what the side-effect | ||
| // in ingestion/processing will be if we change the mechanism, but initially i wanted to | ||
| // stay close to the Native SDK. | ||
| mechanism.setType("signalhandler"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This TODO asks whether to use the mechanism type signalhandler (as we do in the Native SDK) or to change it. If we decide on the latter, should we do it in this PR now? What is the trade-off (what do we gain from ApplicationExitInfo as a mechanism type vs what do we lose when dropping signalhandler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think signalhandler is the best choice here, as it also makes a potential upgrade path easier (e.g. existing sentry.io dashboard queries will continue to work when switching from sentry-native to ApplicationExitInfo)
| // TODO: not sure about this. all tests are written with AbnormalExit, but enrichment changes | ||
| // are ANR-specific. I called it AnrHintEnricher because that is what it does, but it | ||
| // actually triggers on AbnormalExit. Let me know what makes most sense. | ||
| return hint instanceof AbnormalExit; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is primarily about naming things: the class is called AnrHintEnricher (i.e., specific for ANR), but we discriminate based on AbnormalExit (which is arguably broader).
But it is also about "correctness": right now, the tests related to the event processor all use AbnormalExit when constructing test events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd keep it as-is for compatibility reasons, maybe some javadoc on AbnormalExit could help to make it more clear.
| // TODO: this should probably check whether the Native SDK integration is currently enabled or | ||
| // remove the marker file if it isn't. Otherwise, application that disable the Native SDK, | ||
| // will report a crash for the last run forever. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unrelated to this PR, but it can serve as a trigger to fix it: if the native SDK was once enabled and then disabled, do we have a cleanup process elsewhere that would remove the old native marker? If the marker's lifecycle is managed only by the Native SDK, we would report crashedLastRun == true forever.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do some cleanup within sentry core here, regardless if the native SDK is initialized or not.
| if (HintUtils.hasType(hint, AbnormalExit.class)) { | ||
| tryEndPreviousSession(hint); | ||
| } | ||
| // TODO: adapt tryEndPreviousSession(hint); to CrashExit.class |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
likely relevant for this PR
| } | ||
| } | ||
|
|
||
| // TODO: maybe set crashLastRun for tombstone too? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
likely relevant for this PR
| * adjusted before they are symbolicated. TODO: should we make this an enum or is a string value | ||
| * fine? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is part of the public API, it is also a sensible decision to make now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we should introduce an enum with the values outlined in https://github.com/timfish/sentry-rfcs/blob/main/text/0043-instruction-addr-adjustment.md#proposed-protocol-extension
📜 Description
As discussed last week with @markushi, the process will be to make minimal atomic changes in each PR and merge directly to
mainrather than accumulating on an uber feature branch. This allows for easier review/feedback/corrections, and we can already test a subset of the entire feature "in the field".The first minimal change is a basic tombstone integration:
sentry-android-core) or get two reports for the same crashthe current implementation is not entirely correct: we should either remove any remaining)ApplicationExitInfoentries withREASON_CRASH_NATIVEor report them too, including the option for the latter; I left this out for minimal interface exposure in the first step, but either variant is easy to add to this PR or laterprotobuf-javalite(the entire features adds ca. 75KiB to the Android sample release APK)protobufplugin and theprotoccompiler to automate protocol updatesOpen Issues:
While theprotobufruntime is relatively small, there is still the possibility of conflicting with client-sideprotobufversions (major versions often introduce quite severe breakage, but I haven't tested this yet, only reviewed change logs).finding clarity in how to proceed with older tombstones (ignore or handling similarly toANRv2)decision if this minimal setup already makes sense to release as an internal APIManifestMetadataReaderto configure conveniently? (or not since the corresponding options are only internal?)💡 Motivation and Context
First sensible release step for #3295
Part of https://linear.app/getsentry/project/tombstone-support-android-0024cb6e3ffd/
💚 How did you test it?
📝 Checklist
sendDefaultPIIis enabled.🔮 Next steps
protobufruntime library as a dependency tosentry-android-core(or shade/relocate, or implement our own decoder, given that this is a stable format which only requires a subset ofprotobuf).EventProcessorthat merges crash events fromsentry-nativewith tombstones.#skip-changelog (for now)