libshop.so + 0x398 into cart_total in shop.c:13,
inlined frames included, with that library’s debug information. See
Android native code for what is symbolicated.
Native crash reports come from Android 12 and later. The stack of a native crash on older
versions is not available to apps.
With the Gradle plugin
The Apsio Gradle plugin (io.apsio.gradle) does it on every release build. Its
nativeSymbols option is on by default:
- Release build types get
ndk.debugSymbolLevel = "FULL"unless they set it, so AGP keeps each library’s debug information in a separate.so.dbgfile. The libraries in the app are still stripped. - After the build, the plugin uploads those files with
apsio upload ndk, under the build id it writes into the manifest, next to the R8 mapping. It uses the token inAPSIO_TOKEN, as for the mapping.
With the CLI
From a build script or CI, after the build:- The directory (here
native-debug-symbols) holds one subdirectory per ABI,arm64-v8a,armeabi-v7a,x86,x86_64andriscv64, with the libraries’ ELF files that have debug information: the.so.dbgfiles ofdebugSymbolLevel = "FULL"(AGP also zips them, in this layout, intoapp/build/outputs/native-debug-symbols/<variant>/native-debug-symbols.zipfor Google Play: unzip it and pass the folder), or unstripped.sofiles. - Each file is uploaded under its GNU build id, the id native crashes carry, with its ABI and the library’s name. A file that is not ELF, has no build id, has no symbols (a stripped library) or belongs to another ABI is skipped with a warning.
--build-idis the build id in the app’s manifest, the one its R8 mapping uses (see Give the build an id). Apsio records which libraries that build ships.- A library Apsio already has is not sent again: a library you did not change keeps its
build id across builds.
--forceuploads everything again.--dry-runchecks the files without a token or an upload, and--jsonprints a report. - The command succeeds when every library was uploaded or Apsio had it already. When any upload fails it exits with an error (4 when the server rejected the files, 1 for network or server errors), after uploading the others, so a build that treats upload errors as failures stops.
-Wl,--build-id). A library without one cannot be matched to its crashes.
When a native crash stays unsymbolicated
- The build’s debug files were never uploaded, or come from another build: a rebuild of the same code can produce other build ids.
- The library was linked without a build id.
- The frame is in a library of the system (
libc.so,libart.so): those keep the function name the device gives and are never listed as missing.