Native Activity with shared library

1,070 views
Skip to first unread message

Dan

unread,
Dec 10, 2011, 3:44:15 PM12/10/11
to android-ndk
Hello,
Is there anyway to link a shared library with a native activity?
I have the following Android.mk:

# Android.mk
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES := test.c
include $(BUILD_SHARED_LIBRARY)

# Native activity
main
include $(CLEAR_VARS)
LOCAL_MODULE := native-activity
LOCAL_SRC_FILES := main.c
LOCAL_LDLIBS := -llog -landroid
LOCAL_SHARED_LIBRARIES := test
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/native_app_glue)

The generated apk fails to load the libnative-activity.so,
with logcat output:

E/AndroidRuntime( 5038): java.lang.RuntimeException: Unable to start
activity ComponentInfo{com.example.luanative/
android.app.NativeActivity}: java.lang.IllegalArgumentException:
Unable to load native library: /data/data/com.example.luanative/lib/
libnative-activity.so

Everything works all right if test is built and linked as a
STATIC_LIBRARY.
I really don't want to link statically--my final application has a
number
of interlinked libraries which are quite large if all statically
linked against
each other. Surely, there must be a way to have a native activity use
a shared library...

Tor Lillqvist

unread,
Dec 10, 2011, 5:49:47 PM12/10/11
to andro...@googlegroups.com
This was discussed recently here. The Android dynamic linker is much simpler than the GNU/Linux one. I hope my reply in that thread will be useful:

You need to handle loading of dependent shared libraries yourself, *before* a shared library that depends on them is loaded. For example code, see the lo_dlopen() function in http://cgit.freedesktop.org/libreoffice/core/tree/sal/android/lo-bootstrap.c. Using that function I successfully load dozens of interdependent shared libraries used by LibreOffice code (don't get too excited, just some unit tests for now).

What that lo_dlopen() function does is:

- Searches where the shared object in question is. It searches a set of directories passed to it by the Java code. The Java code looks at LD_LIBRARY_PATH and adds the app's lib directory to that.
- Opens the found shared object file and reads the ELF structures in it . Not all, but just enough to find out what shared objects it needs (the DT_NEEDED ones as displayed by arm-linux-androideabi-readelf -d). It calls itself recursively on the needed shared objects.
- Only after that, i.e. after making sure that all needed other shared objects have been loaded, it calls the real dlopen() on the found full pathname to the shared object.

A few gotchas that the code handles:

- You should not call dlopen() unless you are sure it will succeed. The Bionic dynamic linker "helpfully" remembers if a dlopen() call has failed and refuses to even try again dlopening the same library a second time, even if you after the first attempt have loaded the required dependencies that caused the failure the first time. I.e. it is not a good idea to just try dlopen() first and if it fails, parse the dlerror() message...

- The wrapper needs to remember what libraries it already has loaded to avoid infinitely looping when libraries have circular dependencies (which they do have).

--tml

Dan

unread,
Dec 10, 2011, 7:33:04 PM12/10/11
to android-ndk
Thanks, nice trick to manually resolve dependencies!
But I would like to call a function in a shared library
from within my native activity code. The native activity
code is itself an .so, which seems to get loaded by Android.
It looks like they are internally doing a RTLD_NOW dlopen
on the native activity .so, so if you have any calls to
a custom shared library, there is no opportunity for your
code to do a dlopen before everything crashes.


On Dec 10, 5:49 pm, Tor Lillqvist <t...@iki.fi> wrote:
> This was discussed recently here. The Android dynamic linker is much
> simpler than the GNU/Linux one. I hope my reply in that thread will be
> useful:
>
> You need to handle loading of dependent shared libraries yourself, *before*
> a shared library that depends on them is loaded. For example code, see the

> lo_dlopen() function inhttp://cgit.freedesktop.org/libreoffice/core/tree/sal/android/lo-boot....

Tor Lillqvist

unread,
Dec 10, 2011, 7:43:48 PM12/10/11
to andro...@googlegroups.com

It looks like they are internally doing a RTLD_NOW dlopen
on the native activity .so, so if you have any calls to
a custom shared library, there is no opportunity for your
code to do a dlopen before everything crashes.
 
That's why you need to have a very minimal native library as the one dlopened by the NativeActivity class, and that minimal library then actually dlopens all the "real"  shared libraries you need, in order from bottom to top in the dependency tree.

--tml

Dan

unread,
Dec 11, 2011, 9:52:37 AM12/11/11
to android-ndk
Thanks for the info! For now, I'm just getting things
to work by compiling and linking bloated static libraries.
Reply all
Reply to author
Forward
0 new messages