Skip to content

fix: add Android ELF build IDs #95

Description

@jvsena42

Summary

The published libldk_node.so has no .note.gnu.build-id. Google Play matches an uploaded native debug symbol file to the crashing library by ELF build-id, so Play cannot symbolicate a single ldk-node frame — every production report arrives as raw program counters and has to be symbolicated by hand.

Linking release artifacts with -Wl,--build-id=sha1 would make Play Vitals reports readable directly.

Split out of #94, where the missing build-id was what forced manual symbolication of a production SIGABRT.

Evidence

Checked with llvm-readelf -n against com.synonym:ldk-node-android:0.7.0-rc.52, both the .so packaged in the AAR and the .so in the native-debug-symbols classifier artifact:

library NT_GNU_BUILD_ID
libldk_node.so (packaged and symbols) absent
libbitkitcore.so (packaged and symbols) absent
libvss_rust_client_ffi.so absent
libjnidispatch.so (JNA, third party) present

The contrast with JNA is visible in the production reports themselves: debuggerd prints (BuildId: …) next to a frame only when the ELF carries the note. In Bitkit's Play crash and ANR reports, the only frames that ever show a BuildId are the libjnidispatch ones.

Impact

  • native-debug-symbols-<versionCode>.zip is inert for ldk-node no matter how correctly it is built and uploaded to Play Console. The downstream Android app already sets debugSymbolLevel = "FULL", merges the upstream symbol artifacts, and uploads the archive per release — none of it helps.
  • The only names Play resolves for this library come from the exported .dynsym. That yields the occasional UniFFI entry point (e.g. uniffi_ldk_node_fn_method_node_list_balances+68 in [Bug]: Node.listBalances ANR in receive flow bitkit-android#1036) and nothing else; all internal Rust/tokio frames stay as bare addresses.
  • Every production crash therefore needs the manual route: fetch the native-debug-symbols artifact for the exact dependency version, confirm the unstripped .so matches the packaged one by .text vaddr/size, work out which library a PC belongs to from .text ranges, then run llvm-symbolizer. That was required to root-cause SIGABRT: owned tokio Runtime dropped from its own worker thread during chain sync teardown #94 and is not something Play triage can do at scale.

Suggested fix

Add the build-id note when linking the Android release artifacts, e.g. via RUSTFLAGS / .cargo/config.toml for the Android targets:

[target.aarch64-linux-android]
rustflags = ["-C", "link-arg=-Wl,--build-id=sha1"]

(same for armv7-linux-androideabi, x86_64-linux-android)

Requirements for it to actually work end to end:

  1. The note must survive stripping — the packaged .so and the native-debug-symbols .so must carry the same build-id, otherwise Play still cannot pair them.
  2. Worth asserting in CI: fail the release job if llvm-readelf -n reports no NT_GNU_BUILD_ID for any published ABI, or if the packaged and symbol libraries disagree.

The same gap exists in synonymdev/bitkit-core and synonymdev/vss-rust-client-ffi; happy to open matching issues there.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions