ClassyShark supports native code browsing
If your Android app doesn’t have any native dependencies, you can stop reading this article now (but I would suggest you don’t).
From my days in Samsung and Redbend, native code misbehaviour was always a challenge. Native code is code written in compiled language such as C or C++ and targeted to a specific platform. The major use cases are computation intensive libraries (image/signal processing, compression, security …), access to specific hardware and legacy code. Native code is glued to Java code via JNI.
When we develop in C or C++ we lose the great Java features that we take for granted: garbage collection, cross platform support, friendly IDEs and rich ecosystem.
And then your app’s native code crashes … Unlike a Java crash which provides a nice trace, when the native code crashes you only see a core dump which provides a lot of cryptic info. As an Android developer, it is likely that the last time you thought about this stuff was long time ago … you look at the crash, the crash looks at you. In many cases the crash doesn’t come from your native code, but comes from your dependency.
Usually the native crash analysis involves printing logs and using objdump (a tool that creates a map of the native library, solar system size). All these tools and methods were designed and developed way before Android. I found it cumbersome and inconvenient to use these tools while analysing Android native code misbehaviour.
Native comes to ClassyShark
So I added native support to ClassyShark. ClassyShark reads your APK and for each internal .so file encoded with ELF format, emits the following:
- Native dependencies
- Dynamic symbols
As you can see in the image below, what happens when you click on any native library from the list
You see the libraries which your app is dependent on. The native dependencies are either provided by the platform (such as libc) or by you as an app developer (such as your own image processing). Based on this info you can understand the picture better, some causes for the native misbehaviour could be:
- Missing native dependency. Say you want to use library x, with ClassyShark you can see what that library actually depends, then you have to check of the platform provides these libs (libc, libstl, etc’), if the platform doesn’t provide them, you have to include them in your build.
- Wrong version dependency (old versions of OpenGL)
ClassyShark prints out the dynamic symbols from ELFs. Dynamic symbols are pointers to external symbols, the important note about dynamic symbols that they are loaded in run time and not in compile time. Knowing which dynamic symbols each binary has, will help you to narrow down the possible crash cases. Either the problem comes from the dynamic symbol, thus you have to look for solution in other libraries, or to look inside the specific library.
A problem well stated is a problem half solved!