… we gave a mouse an NDK
some non android developers'
experience with NDK
Bruno Garcia
Senior Software Engineer, Sentry
@brungarc
Armin Ronacher
Director of Engineering, Sentry
@mitsuhiko
Slide 2
Slide 2 text
our NDK experience was a bit of
an unexpected rabbit hole
Slide 3
Slide 3 text
No content
Slide 4
Slide 4 text
let's talk about us
Slide 5
Slide 5 text
we're a stack trace company
Slide 6
Slide 6 text
No content
Slide 7
Slide 7 text
Armin
Ronacher
Director of Engineering
@mitsuhiko
Python & Rust Developer
Slide 8
Slide 8 text
Bruno
Garcia
Senior Software Engineer
@brungarc
.NET Developer
Slide 9
Slide 9 text
No content
Slide 10
Slide 10 text
what do we have to do with
Android anyways?
Slide 11
Slide 11 text
You probably know Android
better than we do
Slide 12
Slide 12 text
But we know quite a few things
about crash reporting
Slide 13
Slide 13 text
The goal: stack traces for C, C+
+, Java, Kotlin, …
Slide 14
Slide 14 text
NDK
Slide 15
Slide 15 text
// Optional footer, delete it if you do not need it
15
CONFIDENTIAL
What NDK is
NDK gives us native (C/C++/etc.) code on Android
It interacts heavily with the JVM (ART) via JNI
Android NDK's environment is Linux-ish
Slide 16
Slide 16 text
// Optional footer, delete it if you do not need it
16
CONFIDENTIAL
NDK Components
What's it based on:
Bionic for libc
some hand picked common libraries (zlib)
Slide 17
Slide 17 text
we already did Java, we already
did C++, …
but we didn't do NDK.
Slide 18
Slide 18 text
Production
Crash Reporting
Slide 19
Slide 19 text
Production Crash Reporting
is Fighting a Paradigm
Slide 20
Slide 20 text
// Optional footer, delete it if you do not need it
20
CONFIDENTIAL
Production Crash
Reporting
Performance and debuggability are often at odds
The lower level the language, the higher the disparity
between debug and production build performance
The performance gains come at cost of debuggability
Slide 21
Slide 21 text
production is all that matters
(for us)
Slide 22
Slide 22 text
Production on Android
Slide 23
Slide 23 text
The Runtimes
Slide 24
Slide 24 text
“Java Runtime”
&
“C Runtime”
Slide 25
Slide 25 text
// Optional footer, delete it if you do not need it
25
CONFIDENTIAL
Java Runtime
Android Runtime
Runs via some layers of indirection Java bytecode.
Resembles mostly what you get on a traditional JVM.
Specifically you get stack traces from the runtime
system from every exception thrown
Slide 26
Slide 26 text
// Optional footer, delete it if you do not need it
26
CONFIDENTIAL
C Runtime
Very low level, bare minimums.
Interactions with Java via JNI
No native support for producing useful stack
traces, dozens of different unwinders for Android
non built-in that are good.
Slide 27
Slide 27 text
Stack Traces
Slide 28
Slide 28 text
// Optional footer, delete it if you do not need it
28
CONFIDENTIAL
Readable Java
Stack Traces
Proguard/R8 obfuscation make stack traces
unreadable
Mapping files can be used to resolve method
names in stack traces back to the original names.
Slide 29
Slide 29 text
// Optional footer, delete it if you do not need it
29
CONFIDENTIAL
Readable C Stack
Traces
A whole different ballpark.
DWARF information is generally used to restore
location information and method names in stack
traces once we have them
To get them in the first place is tricky
Slide 30
Slide 30 text
turning numbers and funny strings
into stuff humans can comprehend
// Optional footer, delete it if you do not need it
50
CONFIDENTIAL
stackwalkers
libcorkscrew
deprecated, 32bit only
libunwind
deprecated, google provides android patches
libunwindstack
C++ monstrosity, actively maintained
Slide 51
Slide 51 text
// Optional footer, delete it if you do not need it
51
CONFIDENTIAL
libunwindstack
requires custom patches to compile with NDK
requires large sigaltstack to not overflow the stack
in the signal handler
development in android master deviated from
most NDK compatible forks
Slide 52
Slide 52 text
// Optional footer, delete it if you do not need it
52
CONFIDENTIAL
gief stackwalker
android can already stackwalk (see ndk-stack)
why is the stack walker not exposed to us?
Slide 53
Slide 53 text
// Optional footer, delete it if you do not need it
53
CONFIDENTIAL
build id and image
addresses
now we need the GNU build id and the image offset for
each loaded executable / dynamic library
normally one would use dl_iterate_phdr
this one is missing on older NDKs,
Workaround: parse /proc/self/maps
// Optional footer, delete it if you do not need it
59
CONFIDENTIAL
NDK side
sentry-native
> SDK hooks signal handler
> enumerate loaded images
> dump state to disk before crash
- stack walk with libunwindstack
Slide 60
Slide 60 text
// Optional footer, delete it if you do not need it
60
CONFIDENTIAL
SDK side
sentry-android
> watches file system for new events
> deserializes them, enhances them and uploads
Slide 61
Slide 61 text
// Optional footer, delete it if you do not need it
61
CONFIDENTIAL
Server side
> process crash reports
- symbolicate native stacks on symbolicator
- check for well known symbols in our buckets
- resolve proguard for java stacks
> store
Slide 62
Slide 62 text
Shipping It
Slide 63
Slide 63 text
Android Gradle Plugin :'(
Slide 64
Slide 64 text
// Optional footer, delete it if you do not need it
64
CONFIDENTIAL
Structure
> cmake builds libraries per platform
- these end up in folders for each architecture
where do the headers go?
how do we link to the libraries?
Slide 65
Slide 65 text
// Optional footer, delete it if you do not need it
65
CONFIDENTIAL
Do The Ugly
Dance
> needs a gradle plugin to
- copy header libs out of AAR :(
- so that code can link against the native lib
github.com/android/ndk-samples/issues/261
https://github.com/android/ndk/issues/916
Slide 66
Slide 66 text
Improving It
Slide 67
Slide 67 text
// Optional footer, delete it if you do not need it
67
CONFIDENTIAL
NDK asks
> a maintained and included stack walker
> make ucontext_t/getcontext available
> add support for shipping libs/headers in AARs
> Have OEMs/Google provide symbol servers