1

I have an Android application using multiple native pthreads which I need to debug. The only sensible option I see is using android-ndk-profiler, which is based on gprof. However, gprof is known to not work properly with multithreading. Gladly, there is a work-around by Sam Hocevar available that wraps pthreads to allow gprof proper profiling on multi-threading applications.

Now, they suggest to use LD_PRELOAD to load the libgprofhelper.so before the library-to-profile. This does not work for me.

I decided to go with a very simple test, where I have one function in my library-to-profile, call it libtoProfile.so:

void printDummy()
{
    __android_log_print(ANDROID_LOG_FATAL, "SomeTag", "Hello World!");
}

I compile this for armeabi-v7a with the Android NDK r10d. objdump -T libtoProfile.so | grep printDummy says

00113cf9 g    DF .text  0000001c printDummy 

file libtoProfile.so says

libavNative.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /system/bin/linker, stripped

Now I create my library libgprofhelper.so, which should shadow the printDummy()-function in libtoProfile.so. It has very similar code:

void printDummy()
{
    __android_log_print(ANDROID_LOG_FATAL, "SomeTag", "Successfully overshadowed!");
}

It is built with exactly the same settings / flags / compilers and for the same architecture (armeabi-v7a).

libgprofhelper.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /system/bin/linker, stripped

objdump -T libgprofhelper.so | grep printDummy

 00000c39 g    DF .text  00000018 printDummy

So far, this seems fine for me.

I have a rooted HTC One M7 running Android 4.4.2. I use adb push libgprofhelper.so /data/libgprofhelper.so to get the library on my device.

I then manually install the application using libtoProfile.so, which has package name av.profiling.

I then issue

root@m7:/ # setprop wrap.av.profiling "LD_PRELOAD=/data/libgprofhelper.so"     

which creates the following entry

130|root@m7:/ # getprop | grep profiling
[wrap.av.profiling]: [LD_PRELOAD=/data/libgprofhelper.so]

However, when I start my app (via Launcher or via am start -n ...) I cannot see any sign in logcat that it tries to load libgprofhelper.so, neither is the desired output there. The app just says "Hello World!", which means the LD_PRELOAD has no effect at all.

Does anybody know if LD_PRELOAD works as desired on Android 4.4.2 or are there any different ways to trace where my error is? Of course, alternative ways to profile CPU-usage of multi native threads are welcome as well.

Community
  • 1
  • 1
  • 1
    If that is even a workable way to set this variable, then the fact that Android hardly ever exec()'s anything but merely forks off of zygote probably means it won't take effect until you restart zygote, for example by restarting the whole android layer by typing "stop ; start" at a root adb shell. – Chris Stratton Apr 13 '15 at 18:26
  • Having a function in a shared object isn't enough to get it called on load. ELF shared objects have an `.init` section that has code that gets run on load. Try using `__attribute__((constructor))` for your library function. Or use C++, create a static object, and have your function called in the object's constructor. (I'd post this as an answer but I have no experience using LD_PRELOAD on Android.) – Andrew Henle Apr 13 '15 at 20:16
  • According to [this often referenced source](https://cedricvb.be/post/intercepting-android-native-library-calls/) *setprop* is the way to set the variable. Further, with [this fopen tutorial](http://www.catonmat.net/blog/simple-ld-preload-tutorial/) there's a demonstration that no code has to be executed at library init time. (my printDummy method is called periodically by the GUI-thread of the app via JNI) – Thomas Bergmueller Apr 14 '15 at 04:04
  • I rebooted several times, also using *pkill zygote* (wrap.av.gprofhelper is persistent, checked that), no effect. Thanks for the comments! – Thomas Bergmueller Apr 14 '15 at 04:11
  • You can load libraries with `System.loadLibrary`. If you load the helper library before the one with your applicaiton, it will do the same as LD_PRELOAD. – StenSoft Apr 14 '15 at 14:44
  • @AndrewHenle - it looks to me like the intention is that the poster will call printDummy() at some point, and they expect the pre-empting version to execute instead of the original. Obviously they will have to explicitly make that call. Especially as the poster is working on a rooted device, entries in the /proc/### directory will probably be worth examining - one can see which shared libraries are loaded into a process, and there looks to be a file which gives the effective environment as well. Perhaps the LD_PRELOAD won't be listed. – Chris Stratton Apr 14 '15 at 14:57
  • Did you try removing the quotes? `setprop wrap.av.profiling LD_PRELOAD=/data/libgprofhelper.so`? See this [LD_PRELOAD on android](http://stackoverflow.com/questions/14426191/android-4-2-ld-preload-supported-or-not/24067626#24067626) and this [Cedric's blog on intercepting android native library calls](https://cedricvb.be/post/intercepting-android-native-library-calls/) – narayan Aug 06 '15 at 02:13
  • I see that you already have gone through that Cedric's blog :). I had tried pre-loading a method in a simple app that calculated factorial, and it worked as expected. – narayan Aug 06 '15 at 02:30

0 Answers0