Skip to content

Commit f64bc5a

Browse files
committed
fix: native code abort signal crash
1 parent 4290a7c commit f64bc5a

4 files changed

Lines changed: 75 additions & 0 deletions

File tree

Justfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,12 @@ build task="assembleDevDebug":
137137
{{ gradle }} {{ task }}
138138

139139
release:
140+
#!/usr/bin/env sh
141+
set -eu
140142
{{ gradle }} assembleMainnetRelease bundleMainnetRelease
143+
symbols="app/build/outputs/native-debug-symbols/mainnetRelease/native-debug-symbols.zip"
144+
test -f "$symbols"
145+
ls -lh "$symbols"
141146
142147
install:
143148
{{ gradle }} installDevDebug

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ android {
230230
)
231231
signingConfig = signingConfigs.getByName("release")
232232
ndk {
233+
debugSymbolLevel = "FULL"
233234
// noinspection ChromeOsAbiSupport
234235
abiFilters += listOf("armeabi-v7a", "arm64-v8a")
235236
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package to.bitkit.build
2+
3+
import kotlin.io.path.Path
4+
import kotlin.io.path.exists
5+
import kotlin.io.path.readText
6+
import kotlin.test.Test
7+
import kotlin.test.assertTrue
8+
9+
class NativeReleaseConfigTest {
10+
11+
private val repoRoot = generateSequence(
12+
Path(requireNotNull(System.getProperty("user.dir")) { "user.dir is required" }),
13+
) { it.parent }
14+
.first { it.resolve("gradle/libs.versions.toml").exists() }
15+
16+
@Test
17+
fun `release build keeps full native debug symbols`() {
18+
val buildFile = repoRoot.resolve("app/build.gradle.kts").readText()
19+
20+
assertTrue(
21+
buildFile.contains("""debugSymbolLevel = "FULL""""),
22+
"Release builds must keep full native debug symbols for Play crash symbolication.",
23+
)
24+
}
25+
26+
@Test
27+
fun `release recipe verifies native debug symbols archive`() {
28+
val justfile = repoRoot.resolve("Justfile").readText()
29+
30+
assertTrue(
31+
justfile.contains(
32+
"""symbols="app/build/outputs/native-debug-symbols/mainnetRelease/native-debug-symbols.zip"""",
33+
),
34+
"Release builds must verify the native debug symbols archive before publishing.",
35+
)
36+
}
37+
}

docs/issue-982-native-sigabrt.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Issue 982 Native SIGABRT
2+
3+
## Summary
4+
5+
Google Play reported production SIGABRT crashes for mainnet build 181 / 2.2.0. Play showed raw native program-counter addresses in `split_config.arm64_v8a.apk` instead of resolving them to library functions.
6+
7+
Android Studio Quail 2 was running locally, but the available `android studio` CLI/MCP commands only exposed Studio status, source navigation, file analysis, Compose preview rendering, and version lookup. No App Quality Insights or Android Vitals retrieval command was available, so the GitHub issue's Play Vitals details were used as the machine-readable crash source.
8+
9+
## Symbolication
10+
11+
Exact release context:
12+
13+
- tag: `v2.2.0`
14+
- version code: `181`
15+
- native deps: `bitkit-core-android 0.1.56`, `ldk-node-android 0.7.0-rc.36`
16+
- rebuilt temp worktree: `/tmp/bitkit-android-v2.2.0-symbols`
17+
18+
The historical release build completed through native library extraction and failed only at final bundle signing in the temporary worktree. The generated intermediary AAB was converted to APK splits with bundletool, then the arm64 split was inspected.
19+
20+
Reproduction used a detached `v2.2.0` worktree at the temp path above, authenticated GitHub Packages through `gh auth token`, built the `mainnetRelease` bundle task until native extraction completed, converted the intermediary AAB to APK splits with bundletool `1.18.1`, and inspected `/tmp/bitkit-v2.2.0-apks/splits/base-arm64_v8a.apk`.
21+
22+
The crash addresses resolve directly as library-relative addresses in `libbitkitcore.so`. Running `llvm-addr2line` against `libbitkitcore.so` maps frames into bitkit-core Rust code and dependencies such as `btleplug`, `bdk`, `rusqlite`, and `tokio`. Running the same addresses against `libldk_node.so` produced no matching symbol names.
23+
24+
The direct addresses are executable addresses in the `libbitkitcore.so` ELF. Subtracting the APK ZIP data offset maps the addresses into non-executable sections such as rodata/exception tables, so the direct address form is the usable symbolication path.
25+
26+
Conclusion: issue #982 is a bitkit-core native crash cluster, not an LDK-node crash cluster.
27+
28+
## Fix
29+
30+
Current `master` already consumes `bitkit-core-android 0.1.64`, moving production off the `0.1.56` artifact used by v2.2.0 build 181. A later `0.1.66` artifact was reviewed, but its release notes and commit range focus on the new on-chain watcher and do not provide evidence for this SIGABRT cluster. This branch therefore does not carry an unrelated `bitkit-core` bump.
31+
32+
Release builds also explicitly request full native debug symbols and the `just release` recipe verifies that `app/build/outputs/native-debug-symbols/mainnetRelease/native-debug-symbols.zip` exists after building.

0 commit comments

Comments
 (0)