Skip to content

fix(android): symbolicate APK-embedded tombstone frames - #5992

Merged
supervacuus merged 4 commits into
mainfrom
fix/android/symbolicate-APK-embedded-tombstone-frames
Aug 25, 2026
Merged

supervacuus merged 4 commits into
mainfrom
fix/android/symbolicate-APK-embedded-tombstone-frames

Conversation

@supervacuus

@supervacuus supervacuus commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

📜 Description

Fix tombstone symbolication for native libraries loaded directly from uncompressed APK entries.

The parser now accepts ELF mappings with build IDs at nonzero APK offsets, distinguishes multiple ELFs sharing the same APK path, validates mapping continuations using the tombstone page size, and sets frame image_addr from pc - rel_pc.

Correction during review:

  • ELF PT_LOAD virtual addresses and file offsets can diverge by one segment-alignment unit at each boundary. Meaning continuations must be validated relative to the previous mapping rather than the module start, so we don't accumulate drift (across multi-segment ELFs).
  • The tolerance now also accounts for the case where 16 KiB-aligned ELFs run on 4 KiB devices (meaning ELF alignment would exceed the tombstone's reported runtime page size).

💡 Motivation and Context

TombstoneParser required mapping.offset == 0, excluding ELFs mapped from inside an APK. This removed their debug images when tombstone data replaced the original native event metadata, resulting in unknown_image.

But Android's libunwindstack already resolved the ELF and supplied its build ID, so Java doesn't need to reopen or parse the APK (as the Native SDK module loader does).

Fixes #5986.

💚 How did you test it?

I added the following test cases (names taken directly from the test module):

  • creates images for multiple ELF files embedded in same APK: verifies distinct build IDs produce distinct images despite sharing base.apk.
  • coalesces multiple ELF continuations aligned for 16 KiB pages: covers an ELF with three PT_LOAD mappings and verifies that per-segment alignment drift does not accumulate.
  • does not include a different embedded ELF without build ID in previous image: prevents unrelated APK mappings from expanding the previous image.
  • sets image address on frame for ELF embedded in APK: verifies image_addr is derived from pc - rel_pc.
  • parses APK embedded ELF from full tombstone fixture: validates an Android 15 tombstone produced by a non-legacy packaging build (but only the relevant diffs to the default fixture are asserted and not a full snapshot test which would just duplicate most of the existing tests). Now also verifies complete module sizes for 16KiB-aligned ELFs captured on a 4KiB device.

Ran the tombstone tests.

Also "manually" compared the resulting envelopes when running from a non-legacy packaged sample build against the tombstone integration and the ndk integration (both now have the debug images for the APK, whereas previously they didn't).

📝 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.
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec.

🔮 Next steps

@sentry

sentry Bot commented Aug 25, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.53.0 (1) release

⚙️ sentry-android Build Distribution Settings

@markushi markushi added the sanity-check PR needs a lightweight review for obvious issues label Aug 25, 2026

@markushi markushi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks great, thank you!

@supervacuus
supervacuus merged commit 27e07a5 into main Aug 25, 2026
70 checks passed
@supervacuus
supervacuus deleted the fix/android/symbolicate-APK-embedded-tombstone-frames branch August 25, 2026 14:29
bgriggs added a commit to bgriggs/redmist-timing-ui that referenced this pull request Sep 15, 2026
The app's native crash events come from the Android SDK's signal handler, and for the GC crash they
arrive in Sentry (REDMIST-APP-M) as SIGSEGV with a single unknown frame: no backtrace for debug files to
be matched against, so uploading the runtime's symbols alone would not have named anything. Android 12
and later keep a tombstone for a native crash, with the whole backtrace and every loaded library's build
id, and hand it back through ApplicationExitInfo. The Sentry Android SDK's tombstone integration reports
that, merging it into the signal handler's event when that caught the same crash. It is now on.

One consequence is deliberate to call out. Historical tombstones stay off, but the SDK always reports
the most recent native crash it has not reported yet, up to 91 days old, and on the first launch with
tombstones on nothing counts as reported. So each phone that crashed recently sends one extra event for
a crash already reported, with the release the SDK saved on that earlier run rather than the new one.
With the frames named, the crash will also group under its real stack instead of REDMIST-APP-M's single
unknown frame. Both would skew judging the GC change by that issue's events per release, so the csproj
comment now says to judge it by native crashes per release across issues, or by crash-free sessions.

That needs Sentry 6.11. Sentry 6.9.0 bundles sentry-android 8.52.0, and reading a tombstone's frames for
a library loaded straight out of the APK - which is how a Play install loads libmonosgen, from
split_config.arm64_v8a.apk - only arrived in 8.54.0 (getsentry/sentry-java#5992). 8.55.0 also stopped a
dropped tombstone being reported again at every app start (#6002). Sentry .NET 6.11.0 bundles 8.55.0.

The upgrade makes SentryOptions.EnableMetrics obsolete and ignored (getsentry/sentry-dotnet#5509), so
the line setting it false is gone: a metric is only sent through SentrySdk.Metrics, which the app never
calls, or by the System.Diagnostics.Metrics integration, which stays disabled. On iOS the upgrade also
brings a fix for managed exceptions being captured twice as NSExceptions; the iOS head has not been run
on it here.

All 528 tests pass on 6.11.0, and the Android release build restores the four Sentry packages at 6.11.0
with no new NuGet or obsolete-API warnings; its dex carries sentry-android 8.55.0 where the 6.9.0
build's carried 8.52.0. Installed on the SM-S135DL, the pinned smoke run passes: every screen, final PSS
368 MB against a 366 baseline, first frame 6342 ms against 5991 and inside the harness's tolerance. Its
live patch check was skipped, since no live event had a session running.

What has not been exercised is the tombstone path itself. A local build carries no Sentry DSN, so the
SDK is never initialized on the test phone; the first native crash reported after the next release is
where a full, symbolicated stack should show.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sanity-check PR needs a lightweight review for obvious issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tombstone crashes missing symbolication

2 participants