for dlopen, what is the correct path, where should the files be in the package?

4,592 views
Skip to first unread message

Progman3K

unread,
Jul 27, 2012, 6:04:00 PM7/27/12
to andro...@googlegroups.com
What is the proper way of calling dlopen on android?

No matter what I do, dlopen can never open any .so files.

In all cases, I get variations of

Cannot load library: load_library[1105]: Library 'lib/armeabi/libsimplelib.so' not found

to

Cannot load library: load_library[1105]: Library 'simplelib' not found


Here's my question, what is the proper way of referring to the library?

Here's the layout of the package

   adding: META-INF/MANIFEST.MF
   adding: META-INF/.SF
   adding: META-INF/.RSA
  signing: AndroidManifest.xml
  signing: resources.arsc
  signing: lib/armeabi/libsimplelib.so
  signing: lib/armeabi/libnative-activity.so
Verification succesful

The android_main function in libnative-activity.so executes this

    void * handle;
   
    handle  = dlopen( "lib/armeabi/libsimplelib.so.", RTLD_NOW );
    if ( NULL == handle ) LOGW( "couldn't open: %s", dlerror() );
   
    handle = dlopen( "lib/armeabi/libsimplelib.so", RTLD_NOW );
    if ( NULL == handle ) LOGW( "couldn't open: %s", dlerror() );
   
    handle = dlopen( "lib/armeabi/simplelib.so.", RTLD_NOW );
    if ( NULL == handle ) LOGW( "couldn't open: %s", dlerror() );
   
    handle = dlopen( "lib/armeabi/simplelib.so", RTLD_NOW );
    if ( NULL == handle ) LOGW( "couldn't open: %s", dlerror() );
   
    handle = dlopen( "lib/armeabi/simplelib", RTLD_NOW );
    if ( NULL == handle ) LOGW( "couldn't open: %s", dlerror() );

    handle  = dlopen( "libsimplelib.so.", RTLD_NOW );
    if ( NULL == handle ) LOGW( "couldn't open: %s", dlerror() );
   
    handle = dlopen( "libsimplelib.so", RTLD_NOW );
    if ( NULL == handle ) LOGW( "couldn't open: %s", dlerror() );
   
    handle = dlopen( "simplelib.so.", RTLD_NOW );
    if ( NULL == handle ) LOGW( "couldn't open: %s", dlerror() );
   
    handle = dlopen( "simplelib.so", RTLD_NOW );
    if ( NULL == handle ) LOGW( "couldn't open: %s", dlerror() );
   
    handle = dlopen( "simplelib", RTLD_NOW );
    if ( NULL == handle ) LOGW( "couldn't open: %s", dlerror() );

The system log displays this

W/native-activity( 4921): couldn't open: Cannot load library: load_library[1105]: Library 'lib/armeabi/libsimplelib.so.' not found
W/native-activity( 4921): couldn't open: Cannot load library: load_library[1105]: Library 'lib/armeabi/libsimplelib.so' not found
W/native-activity( 4921): couldn't open: Cannot load library: load_library[1105]: Library 'lib/armeabi/simplelib.so.' not found
W/native-activity( 4921): couldn't open: Cannot load library: load_library[1105]: Library 'lib/armeabi/simplelib.so' not found
W/native-activity( 4921): couldn't open: Cannot load library: load_library[1105]: Library 'lib/armeabi/simplelib' not found
W/native-activity( 5322): couldn't open: Cannot load library: load_library[1105]: Library 'libsimplelib.so.' not found
W/native-activity( 5322): couldn't open: Cannot load library: load_library[1105]: Library 'libsimplelib.so' not found
W/native-activity( 5322): couldn't open: Cannot load library: load_library[1105]: Library 'simplelib.so.' not found
W/native-activity( 5322): couldn't open: Cannot load library: load_library[1105]: Library 'simplelib.so' not found
W/native-activity( 5322): couldn't open: Cannot load library: load_library[1105]: Library 'simplelib' not found


But if you look at the library,

arm-linux-androideabi-readelf -d libsimplelib.so

Dynamic section at offset 0x220c contains 25 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libstdc++.so]
 0x00000001 (NEEDED)                     Shared library: [libm.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so]
 0x00000001 (NEEDED)                     Shared library: [libdl.so]
 0x0000000e (SONAME)                     Library soname: [libsimplelib.so]
 0x00000010 (SYMBOLIC)                   0x0
 0x00000019 (INIT_ARRAY)                 0x31f8
 0x0000001b (INIT_ARRAYSZ)               8 (bytes)
 0x0000001a (FINI_ARRAY)                 0x3200
 0x0000001c (FINI_ARRAYSZ)               12 (bytes)
 0x00000004 (HASH)                       0xd4
 0x00000005 (STRTAB)                     0x698
 0x00000006 (SYMTAB)                     0x278
 0x0000000a (STRSZ)                      1156 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000003 (PLTGOT)                     0x32f4
 0x00000002 (PLTRELSZ)                   48 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0xb64
 0x00000011 (REL)                        0xb1c
 0x00000012 (RELSZ)                      72 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x00000016 (TEXTREL)                    0x0
 0x6ffffffa (RELCOUNT)                   7
 0x00000000 (NULL)                       0x0

I assume libstdc++.so libm.so libc.so libdl.so are already present on the host system because libnative-activity.so (the one executing the dlopens) depends on them -

arm-linux-androideabi-readelf -d libs/armeabi/libnative-activity.so

Dynamic section at offset 0x4930 contains 29 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [liblog.so]
 0x00000001 (NEEDED)                     Shared library: [libandroid.so]
 0x00000001 (NEEDED)                     Shared library: [libEGL.so]
 0x00000001 (NEEDED)                     Shared library: [libGLESv1_CM.so]
 0x00000001 (NEEDED)                     Shared library: [libdl.so]
 0x00000001 (NEEDED)                     Shared library: [libstdc++.so]
 0x00000001 (NEEDED)                     Shared library: [libm.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so]
 0x0000000e (SONAME)                     Library soname: [libnative-activity.so]
 0x00000010 (SYMBOLIC)                   0x0
 0x00000019 (INIT_ARRAY)                 0x591c
 0x0000001b (INIT_ARRAYSZ)               8 (bytes)
 0x0000001a (FINI_ARRAY)                 0x5924
 0x0000001c (FINI_ARRAYSZ)               12 (bytes)
 0x00000004 (HASH)                       0xd4
 0x00000005 (STRTAB)                     0xedc
 0x00000006 (SYMTAB)                     0x54c
 0x0000000a (STRSZ)                      2675 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000003 (PLTGOT)                     0x5a38
 0x00000002 (PLTRELSZ)                   552 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x1998
 0x00000011 (REL)                        0x1950
 0x00000012 (RELSZ)                      72 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x00000016 (TEXTREL)                    0x0
 0x6ffffffa (RELCOUNT)                   7
 0x00000000 (NULL)                       0x0

Both the native-activity and simplelib libraries are built with the same NDK.

Why can't I open the shared library? Is it because I must supply a different path? What path should I use?

Tor Lillqvist

unread,
Jul 28, 2012, 2:22:23 AM7/28/12
to andro...@googlegroups.com

What is the proper way of calling dlopen on android?
 
Very carefully.

You need to pass in the full path to the library.  (That's easy to find out in your Java code, write a JNI-callable function to receive abd store that information.) You need to make sure that all dependent shared libraries have already been loaded.

And if your reaction is "what, Java, JNI, I am writing a pure native app!", stop right there. There are no "pure native" apps in Android. Even "purely" NDK-based apps have some amount of (system-provided) Java in them when running, you don't lose any "performance" if you have a bit of Java of your own, too. (For instance by subclassing NativeActivity.)

--tml
 

Progman3K

unread,
Jul 28, 2012, 5:20:15 PM7/28/12
to andro...@googlegroups.com
Tor,
Thank you very much for taking the time to explain it to me.

Some background: I have simply copied the native-activity sample from the NDK and am building it this way -


ndk-build NDK_DEBUG=0 V=1
cp ../simplesharedlib/lib/libs/armeabi/libsimplelib.so libs/armeabi/

android update project -p . --target 1 --subprojects
ant release
jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 bin/*-release-unsigned.apk
zipalign -v 4 bin/*-release-unsigned.apk bin/output.apk


As you can see, I manually copy the shared-library libsimplelib.so (that is built separately but with the same tools) to the libs/armeabi/ folder of the native-activity project and then run the packaging tools.

The foreign shared-library (simplelib) is present in the .apk file, in the same folder as libnative-activity.so

Verifying alignment of bin/output.apk (4)...
      50 META-INF/MANIFEST.MF (OK - compressed)
     470 META-INF/.SF (OK - compressed)
     957 META-INF/.RSA (OK - compressed)
    4443 AndroidManifest.xml (OK - compressed)
    5160 resources.arsc (OK)
  133139 lib/armeabi/libsimplelib.so (OK - compressed)
  138378 lib/armeabi/libnative-activity.so (OK - compressed)
Verification succesful

So when the package installs, where does the libsimplelib.so file wind up?

I suppose the problem is that I must not be stating the path of the package-included binary correctly, because by all considerations both the shared library calling dlopen (native-activity) and the shared library it is trying to open (simplelib) are built with the same tools and have equivalent dependencies.

simplelib is even simpler, containing only the function

extern "C int simplecall( int i ) {

    return 3 + i;

}

Since simplelib depends on the same shared libraries as native-activity, it can't be failing because a dependency is not present, can it?

It has to be the pathname parameter I pass to dlopen that is incorrect.

So my question is:

For an anonymous (not implicitly linked to the project) shared library that has been included in the application's package, what is the path it will be extracted to when the application runs?

There is no reference anywhere in the project, it is a binary included in native-activity's package, so what is the proper way of referring to it with dlopen?

Thanks in advance|

J

Chris Stratton

unread,
Jul 29, 2012, 12:47:17 AM7/29/12
to android-ndk
On Jul 28, 5:20 pm, Progman3K <progma...@gmail.com> wrote:

> For an anonymous (not implicitly linked to the project) shared library that
> has been included in the application's package, what is the path it will be
> extracted to when the application runs?

Presumably in the same place as the native library which is calling
dlopen()....

You were already given a java solution, which sounds good.

If you really want to avoid that, I suppose you can troll your own
maps and figure out where you were loaded from.

Another possibility is that this extra library is not getting
installed, perhaps because it is not a compatible ABI (was it even
built for android?). It might be worth building a debuggable apk so
you can use the run-as command in the adb shell to get a shell as the
app userid and look around in it's private files to see what libs
actually did get unpacked.

Progman3K

unread,
Jul 29, 2012, 1:57:14 AM7/29/12
to andro...@googlegroups.com
telyThank you very much, Chris!


Presumably in the same place as the native library which is calling
dlopen()....

This was my initial thought too, but dlopen fails to open the library if I use "simplelib" or "./libsimplelib.so" or just about any variation you can think up...

You were already given a java solution, which sounds good.

I have a c++ application I wish to run, although I understand that a native-activity inherits a java vm instance; this might lead to a solution if I can figure out how to use its properties.

If you really want to avoid that, I suppose you can troll your own
maps and figure out where you were loaded from.

I believe you are correct: I'll add some code to the native-activity library to probe the filesystem.
 
Another possibility is that this extra library is not getting
installed,

Your hypothesis fits the experimental data. Although I know for a fact that libsimplelib.so winds up in the package,  does it actually get installed? I will write more code to see.
 
perhaps because it is not a compatible ABI

It is, both modules are built compatibly:

The application (libnative-activity.so) is built for ARM android-9 and runs correctly.

It then it tries to dlopen libsimplelib.so which is built for ARM android-3


Here are the compile and link phases for native-activity:
/opt/android-ndk-r8/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc -MMD -MP -MF ./obj/local/armeabi/objs/native-activity/main.o.d -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__  -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I/opt/android-ndk-r8/sources/android/native_app_glue -Ijni -DANDROID  -Wa,--noexecstack -O2 -DNDEBUG -g -I/opt/android-ndk-r8/platforms/android-9/arch-arm/usr/include -c  jni/main.c -o ./obj/local/armeabi/objs/native-activity/main.o
/opt/android-ndk-r8/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-g++  -Wl,-soname,libnative-activity.so -shared --sysroot=/opt/android-ndk-r8/platforms/android-9/arch-arm ./obj/local/armeabi/objs/native-activity/main.o ./obj/local/armeabi/libandroid_native_app_glue.a   -Wl,--no-undefined -Wl,-z,noexecstack -L/opt/android-ndk-r8/platforms/android-9/arch-arm/usr/lib -llog -landroid -lEGL -lGLESv1_CM -ldl -llog -lc -lm -o obj/local/armeabi/libnative-activity.so




For simplelib:
/opt/android-ndk-r8/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc -MMD -MP -MF ./obj/local/armeabi/objs/simplelib/__/src/libmain.o.d -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__  -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -Ijni/../inc -I../include -Ijni -DANDROID  -Wa,--noexecstack -O2 -DNDEBUG -g -I/opt/android-ndk-r8/platforms/android-3/arch-arm/usr/include -c  jni/../src/libmain.c -o ./obj/local/armeabi/objs/simplelib/__/src/libmain.o
/opt/android-ndk-r8/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-g++  -Wl,-soname,libsimplelib.so -shared --sysroot=/opt/android-ndk-r8/platforms/android-3/arch-arm ./obj/local/armeabi/objs/simplelib/__/src/libmain.o   -Wl,--no-undefined -Wl,-z,noexecstack  -lc -lm -o obj/local/armeabi/libsimplelib.so


They are identical except for the ABI, but since the running ABI is 9, it should work, right?
 
It might be worth building a debuggable apk so

Noted! Since I am a command-line user it'll probably be very interesting getting that working ;-)
I normally use DDD, I hope I can use it here.
 
you can use the run-as command in the adb shell to get a shell as the
app userid and look around in it's private files to see what libs
actually did get unpacked.

I did not know about this facility. I will read. Thank you!


Reply all
Reply to author
Forward
0 new messages