From 51d7265215072a68fbd1a1314bdf7c13f2c2d787 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 25 Aug 2026 13:12:58 +0200 Subject: [PATCH 1/4] fix(android): symbolicate APK-embedded tombstone frames --- .../internal/tombstone/TombstoneParser.java | 52 +++- .../internal/tombstone/TombstoneParserTest.kt | 255 ++++++++++++++++++ .../resources/tombstone_apk_embedded.pb.gz | Bin 0 -> 73239 bytes 3 files changed, 293 insertions(+), 14 deletions(-) create mode 100644 sentry-android-core/src/test/resources/tombstone_apk_embedded.pb.gz diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java index c3966615899..aa8b3840165 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java @@ -147,6 +147,12 @@ private SentryStackTrace createStackTrace(@NonNull final TombstoneThread thread) stackFrame.setPackage(frame.fileName); stackFrame.setFunction(frame.functionName); stackFrame.setInstructionAddr(formatHex(frame.pc)); + if (!frame.buildId.isEmpty() && frame.pc >= frame.relPc) { + // libunwindstack has already resolved rel_pc against the embedded or standalone ELF. + // The containing file offset (for example, the offset inside an APK) is irrelevant to the + // ELF's runtime image address. + stackFrame.setImageAddr(formatHex(frame.pc - frame.relPc)); + } // inAppIncludes/inAppExcludes filter by Java/Kotlin package names, which don't overlap // with native C/C++ function names (e.g., "crash", "__libc_init"). For native frames, @@ -260,12 +266,34 @@ private static class ModuleAccumulator { String buildId; long beginAddress; long endAddress; + long startOffset; ModuleAccumulator(MemoryMapping mapping) { this.mappingName = mapping.mappingName; this.buildId = mapping.buildId; this.beginAddress = mapping.beginAddress; this.endAddress = mapping.endAddress; + this.startOffset = mapping.offset; + } + + boolean isSameModule(MemoryMapping mapping) { + return mappingName.equals(mapping.mappingName) && buildId.equals(mapping.buildId); + } + + boolean canExtendTo(MemoryMapping mapping, long pageSize) { + if (!mappingName.equals(mapping.mappingName) + || mapping.beginAddress < beginAddress + || mapping.offset < startOffset) { + return false; + } + + // PT_LOAD virtual addresses and file offsets grow together, modulo page alignment. This + // distinguishes a continuation from another ELF without build-id in the same APK. + final long addressDelta = mapping.beginAddress - beginAddress; + final long fileOffsetDelta = mapping.offset - startOffset; + final long delta = addressDelta - fileOffsetDelta; + final long alignmentTolerance = pageSize > 0 ? pageSize : 4096; + return delta >= -alignmentTolerance && delta <= alignmentTolerance; } void extendTo(long newEndAddress) { @@ -295,11 +323,9 @@ private DebugMeta createDebugMeta(@NonNull final Tombstone tombstone) { final List images = new ArrayList<>(); // Coalesce memory mappings into modules similar to how sentry-native does it. - // A module consists of all readable mappings for the same file, starting from - // the first mapping that has a valid ELF header (indicated by offset 0 with build_id). - // In sentry-native, is_valid_elf_header() reads the ELF magic bytes from memory, - // which is only present at the start of the file (offset 0). We use offset == 0 - // combined with non-empty build_id as a proxy for this check. + // Android's libunwindstack has already parsed each ELF and records its build ID in the + // tombstone. An ELF stored uncompressed inside an APK starts at a non-zero container offset, + // so the mapping offset cannot be used to validate whether the mapping starts an ELF. ModuleAccumulator currentModule = null; for (MemoryMapping mapping : tombstone.memoryMappings) { @@ -315,18 +341,16 @@ private DebugMeta createDebugMeta(@NonNull final Tombstone tombstone) { } final boolean hasBuildId = !mapping.buildId.isEmpty(); - final boolean isFileStart = mapping.offset == 0; - if (hasBuildId && isFileStart) { - // Check for duplicated mappings: On Android, the same ELF can have multiple - // mappings at offset 0 with different permissions (r--p, r-xp, r--p). - // If it's the same file as the current module, just extend it. - if (currentModule != null && mappingName.equals(currentModule.mappingName)) { + if (hasBuildId) { + // The same ELF can have multiple mappings with its build ID. APK-embedded ELFs all share + // the APK mapping name, so the build ID is also required to distinguish their modules. + if (currentModule != null && currentModule.isSameModule(mapping)) { currentModule.extendTo(mapping.endAddress); continue; } - // Flush the previous module (different file) + // Flush the previous module (different ELF) if (currentModule != null) { final DebugImage image = currentModule.toDebugImage(); if (image != null) { @@ -336,8 +360,8 @@ private DebugMeta createDebugMeta(@NonNull final Tombstone tombstone) { // Start a new module currentModule = new ModuleAccumulator(mapping); - } else if (currentModule != null && mappingName.equals(currentModule.mappingName)) { - // Extend the current module with this mapping (same file, continuation) + } else if (currentModule != null && currentModule.canExtendTo(mapping, tombstone.pageSize)) { + // Extend the current module with this mapping (same ELF, continuation). currentModule.extendTo(mapping.endAddress); } } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/internal/tombstone/TombstoneParserTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/internal/tombstone/TombstoneParserTest.kt index 70fc48fd9be..61a5748087e 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/internal/tombstone/TombstoneParserTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/internal/tombstone/TombstoneParserTest.kt @@ -5,6 +5,7 @@ import com.abovevacant.epitaph.core.MemoryMapping import com.abovevacant.epitaph.core.Signal import com.abovevacant.epitaph.core.Tombstone import com.abovevacant.epitaph.core.TombstoneThread +import com.google.common.truth.Truth.assertThat import io.sentry.ILogger import io.sentry.JsonObjectWriter import io.sentry.protocol.DebugMeta @@ -318,6 +319,232 @@ class TombstoneParserTest { assertEquals(0x7000003000 - 0x7000000000, image.imageSize) } + @Test + fun `creates images for multiple ELF files embedded in same APK`() { + val apkPath = "/data/app/io.sentry.sample/base.apk" + val firstBuildId = "f1c3bcc0279865fe3058404b2831d9e64135386c" + val secondBuildId = "a1647a1813da20ea7e0dad6cbc11486dfaeaeb8e" + + val tombstone = + Tombstone.Builder() + .pid(1234) + .tid(1234) + .signal(Signal(11, "SIGSEGV", 1, "SEGV_MAPERR", false, 0, 0, false, 0, null)) + .addMemoryMapping( + MemoryMapping( + 0x7000000000, + 0x7000001000, + 0x156c000, + true, + false, + true, + apkPath, + firstBuildId, + 0, + ) + ) + .addMemoryMapping( + MemoryMapping( + 0x7000001000, + 0x7000002000, + 0x156d000, + true, + false, + false, + apkPath, + firstBuildId, + 0, + ) + ) + .addMemoryMapping( + MemoryMapping( + 0x7100000000, + 0x7100001000, + 0x1578000, + true, + false, + true, + apkPath, + secondBuildId, + 0, + ) + ) + .addMemoryMapping( + MemoryMapping( + 0x7100001000, + 0x7100003000, + 0x1579000, + true, + false, + false, + apkPath, + secondBuildId, + 0, + ) + ) + .build() + + val images = parser.parse(tombstone).debugMeta!!.images!! + + assertThat(images).hasSize(2) + assertThat(images.map { it.codeFile }).containsExactly(apkPath, apkPath) + assertThat(images.map { it.codeId }).containsExactly(firstBuildId, secondBuildId).inOrder() + assertThat(images.map { it.imageAddr }) + .containsExactly("0x7000000000", "0x7100000000") + .inOrder() + assertThat(images.map { it.imageSize }).containsExactly(0x2000L, 0x3000L).inOrder() + } + + @Test + fun `coalesces ELF continuation aligned for 16 KiB pages`() { + val apkPath = "/data/app/io.sentry.sample/base.apk" + val buildId = "f1c3bcc0279865fe3058404b2831d9e64135386c" + + val tombstone = + Tombstone.Builder() + .pid(1234) + .tid(1234) + .signal(Signal(11, "SIGSEGV", 1, "SEGV_MAPERR", false, 0, 0, false, 0, null)) + .pageSize(0x4000) + .addMemoryMapping( + MemoryMapping( + 0x7000000000, + 0x7000001000, + 0x156c000, + true, + false, + true, + apkPath, + buildId, + 0, + ) + ) + // The virtual-address progression can differ from the file-offset progression by one page. + .addMemoryMapping( + MemoryMapping( + 0x7000005000, + 0x7000007000, + 0x156d000, + true, + false, + false, + apkPath, + "", + 0, + ) + ) + .build() + + val image = parser.parse(tombstone).debugMeta!!.images!!.single() + + assertThat(image.imageAddr).isEqualTo("0x7000000000") + assertThat(image.imageSize).isEqualTo(0x7000) + } + + @Test + fun `does not include a different embedded ELF without build ID in previous image`() { + val apkPath = "/data/app/io.sentry.sample/base.apk" + val buildId = "f1c3bcc0279865fe3058404b2831d9e64135386c" + + val tombstone = + Tombstone.Builder() + .pid(1234) + .tid(1234) + .signal(Signal(11, "SIGSEGV", 1, "SEGV_MAPERR", false, 0, 0, false, 0, null)) + .pageSize(0x4000) + .addMemoryMapping( + MemoryMapping( + 0x7000000000, + 0x7000001000, + 0x156c000, + true, + false, + true, + apkPath, + buildId, + 0, + ) + ) + // A different ELF in the APK that does not have a GNU build ID. + .addMemoryMapping( + MemoryMapping( + 0x7100000000, + 0x7100010000, + 0x163c000, + true, + false, + true, + apkPath, + "", + 0x4000, + ) + ) + .build() + + val image = parser.parse(tombstone).debugMeta!!.images!!.single() + + assertThat(image.codeId).isEqualTo(buildId) + assertThat(image.imageAddr).isEqualTo("0x7000000000") + assertThat(image.imageSize).isEqualTo(0x1000) + } + + @Test + fun `sets image address on frame for ELF embedded in APK`() { + val apkPath = "/data/app/io.sentry.sample/base.apk" + val buildId = "a1647a1813da20ea7e0dad6cbc11486dfaeaeb8e" + val imageAddress = 0x7000000000 + val relativePc = 0xac4L + + val tombstone = + Tombstone.Builder() + .pid(1234) + .tid(1234) + .signal(Signal(11, "SIGSEGV", 1, "SEGV_MAPERR", false, 0, 0, false, 0, null)) + .addMemoryMapping( + MemoryMapping( + imageAddress, + imageAddress + 0x1000, + 0x156c000, + true, + false, + true, + apkPath, + buildId, + 0, + ) + ) + .addThread( + TombstoneThread( + 1234, + "main", + emptyList(), + emptyList(), + emptyList(), + listOf( + BacktraceFrame( + relativePc, + imageAddress + relativePc, + 0, + "crash", + 0, + "$apkPath!libnative-sample.so", + 0x156c000, + buildId, + ) + ), + emptyList(), + 0, + 0, + ) + ) + .build() + + val frame = parser.parse(tombstone).threads!!.single().stacktrace!!.frames!!.single() + + assertThat(frame.instructionAddr).isEqualTo("0x7000000ac4") + assertThat(frame.imageAddr).isEqualTo("0x7000000000") + } + @Test fun `debugId falls back to codeId when OleGuidFormatter conversion fails`() { // Create a tombstone with a memory mapping that has an invalid buildId @@ -387,6 +614,34 @@ class TombstoneParserTest { assertEquals("c0bcc3f1-9827-fe65-3058-404b2831d9e6", validImage.debugId) } + @Test + fun `parses APK embedded ELF from full tombstone fixture`() { + val tombstoneStream = + GZIPInputStream( + TombstoneParserTest::class.java.getResourceAsStream("/tombstone_apk_embedded.pb.gz") + ) + val event = + TombstoneParser(tombstoneStream, inAppIncludes, inAppExcludes, nativeLibraryDir).parse() + val buildId = "a1647a1813da20ea7e0dad6cbc11486dfaeaeb8e" + + val image = event.debugMeta!!.images!!.single { it.codeId == buildId } + + assertThat(image.type).isEqualTo("elf") + assertThat(image.codeFile).endsWith("/base.apk") + assertThat(image.debugId).isEqualTo("187a64a1-da13-ea20-7e0d-ad6cbc11486d") + assertThat(image.imageAddr).isEqualTo("0x7646619000") + assertThat(image.imageSize).isEqualTo(0x5000) + + val frames = + event.threads!! + .flatMap { it.stacktrace!!.frames!! } + .filter { it.`package`!!.endsWith("base.apk!libnative-sample.so") } + + assertThat(frames).hasSize(2) + assertThat(frames.map { it.imageAddr }).containsExactly("0x7646619000", "0x7646619000") + assertThat(frames.map { it.instructionAddr }).containsExactly("0x7646619ac4", "0x7646619ae4") + } + @Test fun `debug meta images snapshot test`() { // test against a full snapshot so that we can track regressions in the VMA -> module reduction diff --git a/sentry-android-core/src/test/resources/tombstone_apk_embedded.pb.gz b/sentry-android-core/src/test/resources/tombstone_apk_embedded.pb.gz new file mode 100644 index 0000000000000000000000000000000000000000..59481c31fd5d34b35c4675fd14fdfd3c1f5bef9f GIT binary patch literal 73239 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 |?2o1a0%5e<#JB0pD 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 DVB#SN literal 0 HcmV?d00001 From 9db0caef1a886eaf1bd48a2b72d27375e8b2f810 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 25 Aug 2026 13:31:52 +0200 Subject: [PATCH 2/4] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02e1a8a906e..e7f0f98a92b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Prevent duplicated breadcrumbs on tombstone-merged native crash events ([#5888](https://github.com/getsentry/sentry-java/pull/5888)) - Prevent a class of Session Replay deadlocks by confining lifecycle state changes to Android's main thread ([#5965](https://github.com/getsentry/sentry-java/pull/5965)) +- Symbolicate tombstone native frames for libraries loaded directly from APKs ([#5992](https://github.com/getsentry/sentry-java/pull/5992)) ### Performance From 5f67c0eee11776d805c81b8d53136a60405d13e2 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 25 Aug 2026 14:18:06 +0200 Subject: [PATCH 3/4] coalesce aligned tombstone mappings --- .../internal/tombstone/TombstoneParser.java | 43 +++++++++++++------ .../internal/tombstone/TombstoneParserTest.kt | 29 +++++++++++-- 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java index aa8b3840165..1fc904a9b07 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java @@ -262,18 +262,25 @@ private Message constructMessage(@NonNull final Tombstone tombstone) { * runtime instruction addresses in the files uploaded for symbolication. */ private static class ModuleAccumulator { + private static final long PAGE_SIZE_4KIB = 4096; + private static final long PAGE_SIZE_16KIB = 16384; + String mappingName; String buildId; long beginAddress; long endAddress; - long startOffset; + long previousBeginAddress; + long previousEndAddress; + long previousOffset; ModuleAccumulator(MemoryMapping mapping) { this.mappingName = mapping.mappingName; this.buildId = mapping.buildId; this.beginAddress = mapping.beginAddress; this.endAddress = mapping.endAddress; - this.startOffset = mapping.offset; + this.previousBeginAddress = mapping.beginAddress; + this.previousEndAddress = mapping.endAddress; + this.previousOffset = mapping.offset; } boolean isSameModule(MemoryMapping mapping) { @@ -282,22 +289,30 @@ boolean isSameModule(MemoryMapping mapping) { boolean canExtendTo(MemoryMapping mapping, long pageSize) { if (!mappingName.equals(mapping.mappingName) - || mapping.beginAddress < beginAddress - || mapping.offset < startOffset) { + || mapping.beginAddress < previousEndAddress + || mapping.offset < previousOffset) { return false; } - // PT_LOAD virtual addresses and file offsets grow together, modulo page alignment. This - // distinguishes a continuation from another ELF without build-id in the same APK. - final long addressDelta = mapping.beginAddress - beginAddress; - final long fileOffsetDelta = mapping.offset - startOffset; - final long delta = addressDelta - fileOffsetDelta; - final long alignmentTolerance = pageSize > 0 ? pageSize : 4096; + // PT_LOAD virtual-address and file-offset gaps can differ by one segment-alignment unit. + // Compare adjacent mappings so this difference does not accumulate across the module. + final long previousSize = previousEndAddress - previousBeginAddress; + final long addressGap = mapping.beginAddress - previousEndAddress; + final long fileOffsetGap = mapping.offset - (previousOffset + previousSize); + final long delta = addressGap - fileOffsetGap; + + // Android ELFs built for 16 KiB pages can also run on 4 KiB devices, so the ELF alignment + // can be larger than the tombstone's runtime page size. + final long runtimePageSize = pageSize > 0 ? pageSize : PAGE_SIZE_4KIB; + final long alignmentTolerance = Math.max(runtimePageSize, PAGE_SIZE_16KIB); return delta >= -alignmentTolerance && delta <= alignmentTolerance; } - void extendTo(long newEndAddress) { - this.endAddress = newEndAddress; + void extendTo(MemoryMapping mapping) { + this.endAddress = Math.max(endAddress, mapping.endAddress); + this.previousBeginAddress = mapping.beginAddress; + this.previousEndAddress = mapping.endAddress; + this.previousOffset = mapping.offset; } DebugImage toDebugImage() { @@ -346,7 +361,7 @@ private DebugMeta createDebugMeta(@NonNull final Tombstone tombstone) { // The same ELF can have multiple mappings with its build ID. APK-embedded ELFs all share // the APK mapping name, so the build ID is also required to distinguish their modules. if (currentModule != null && currentModule.isSameModule(mapping)) { - currentModule.extendTo(mapping.endAddress); + currentModule.extendTo(mapping); continue; } @@ -362,7 +377,7 @@ private DebugMeta createDebugMeta(@NonNull final Tombstone tombstone) { currentModule = new ModuleAccumulator(mapping); } else if (currentModule != null && currentModule.canExtendTo(mapping, tombstone.pageSize)) { // Extend the current module with this mapping (same ELF, continuation). - currentModule.extendTo(mapping.endAddress); + currentModule.extendTo(mapping); } } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/internal/tombstone/TombstoneParserTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/internal/tombstone/TombstoneParserTest.kt index 61a5748087e..03e73b1ec93 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/internal/tombstone/TombstoneParserTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/internal/tombstone/TombstoneParserTest.kt @@ -396,7 +396,7 @@ class TombstoneParserTest { } @Test - fun `coalesces ELF continuation aligned for 16 KiB pages`() { + fun `coalesces multiple ELF continuations aligned for 16 KiB pages`() { val apkPath = "/data/app/io.sentry.sample/base.apk" val buildId = "f1c3bcc0279865fe3058404b2831d9e64135386c" @@ -433,12 +433,27 @@ class TombstoneParserTest { 0, ) ) + // Each PT_LOAD adds one page of alignment drift. Validation must compare adjacent + // mappings so this drift does not accumulate from the start of the module. + .addMemoryMapping( + MemoryMapping( + 0x700000b000, + 0x700000d000, + 0x156f000, + true, + true, + false, + apkPath, + "", + 0, + ) + ) .build() val image = parser.parse(tombstone).debugMeta!!.images!!.single() assertThat(image.imageAddr).isEqualTo("0x7000000000") - assertThat(image.imageSize).isEqualTo(0x7000) + assertThat(image.imageSize).isEqualTo(0xd000) } @Test @@ -624,7 +639,8 @@ class TombstoneParserTest { TombstoneParser(tombstoneStream, inAppIncludes, inAppExcludes, nativeLibraryDir).parse() val buildId = "a1647a1813da20ea7e0dad6cbc11486dfaeaeb8e" - val image = event.debugMeta!!.images!!.single { it.codeId == buildId } + val images = event.debugMeta!!.images!! + val image = images.single { it.codeId == buildId } assertThat(image.type).isEqualTo("elf") assertThat(image.codeFile).endsWith("/base.apk") @@ -640,6 +656,13 @@ class TombstoneParserTest { assertThat(frames).hasSize(2) assertThat(frames.map { it.imageAddr }).containsExactly("0x7646619000", "0x7646619000") assertThat(frames.map { it.instructionAddr }).containsExactly("0x7646619ac4", "0x7646619ae4") + + // This tombstone was captured on a 4 KiB device, but these ELFs use 16 KiB PT_LOAD + // alignment. Their mappings still need to be fully coalesced. + assertThat(images.single { it.codeId == "f86d542eccd3f652ab08ff210b5d009ef6c14cfe" }.imageSize) + .isEqualTo(0xcc000) + assertThat(images.single { it.codeId == "d76a948eaadeea8d0d1b17cdb026d8b4e4c39384" }.imageSize) + .isEqualTo(0x9000) } @Test From 0f8ef75242d5c299cd1e891a243c5aa90d26a639 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Tue, 25 Aug 2026 15:30:42 +0200 Subject: [PATCH 4/4] sentry-java-ify changes --- .../core/internal/tombstone/TombstoneParser.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java index 1fc904a9b07..b6ac22b12ef 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/tombstone/TombstoneParser.java @@ -273,7 +273,7 @@ private static class ModuleAccumulator { long previousEndAddress; long previousOffset; - ModuleAccumulator(MemoryMapping mapping) { + ModuleAccumulator(final @NotNull MemoryMapping mapping) { this.mappingName = mapping.mappingName; this.buildId = mapping.buildId; this.beginAddress = mapping.beginAddress; @@ -283,11 +283,12 @@ private static class ModuleAccumulator { this.previousOffset = mapping.offset; } - boolean isSameModule(MemoryMapping mapping) { + boolean isSameModule(final @NotNull MemoryMapping mapping) { return mappingName.equals(mapping.mappingName) && buildId.equals(mapping.buildId); } - boolean canExtendTo(MemoryMapping mapping, long pageSize) { + boolean canExtendTo(final @NotNull MemoryMapping mapping, final long pageSize) { + if (!mappingName.equals(mapping.mappingName) || mapping.beginAddress < previousEndAddress || mapping.offset < previousOffset) { @@ -308,7 +309,7 @@ boolean canExtendTo(MemoryMapping mapping, long pageSize) { return delta >= -alignmentTolerance && delta <= alignmentTolerance; } - void extendTo(MemoryMapping mapping) { + void extendTo(final @NotNull MemoryMapping mapping) { this.endAddress = Math.max(endAddress, mapping.endAddress); this.previousBeginAddress = mapping.beginAddress; this.previousEndAddress = mapping.endAddress; @@ -323,7 +324,7 @@ DebugImage toDebugImage() { image.setCodeId(buildId); image.setCodeFile(mappingName); - final String debugId = NativeEventUtils.buildIdToDebugId(buildId); + final @Nullable String debugId = NativeEventUtils.buildIdToDebugId(buildId); image.setDebugId(debugId != null ? debugId : buildId); image.setImageAddr(formatHex(beginAddress)); @@ -341,9 +342,9 @@ private DebugMeta createDebugMeta(@NonNull final Tombstone tombstone) { // Android's libunwindstack has already parsed each ELF and records its build ID in the // tombstone. An ELF stored uncompressed inside an APK starts at a non-zero container offset, // so the mapping offset cannot be used to validate whether the mapping starts an ELF. - ModuleAccumulator currentModule = null; + @Nullable ModuleAccumulator currentModule = null; - for (MemoryMapping mapping : tombstone.memoryMappings) { + for (final @NotNull MemoryMapping mapping : tombstone.memoryMappings) { // Skip mappings that are not readable if (!mapping.read) { continue;