1

I can use System.loadLibrary(lib); In android java to load my shared library and use it. The problem with this current approach is that I can actually have two instances of my android application running.

Having two instances of my application with one shared library doesn't. I need two instances of my shared library. The good new is that from java I can find out if I am running either instance A or instance B. Sometimes I'll be running in instance A but still have to load instance B; doing this totally messes up the first instance.

What i've done so far is find out which instance I am running in and pass that to JNI then inside my .c file I load the .so with dlopen, now I have a handle to my shared library.

The java side:

        if(preview)
        {
            for (String lib : getLibraries()) {
                   nativeInitPreview(lib);
                }
        }
        else
        {
            for (String lib : getLibraries()) {
                nativeInitLive(lib);
                }
        }

the c code side:

static void *mainHandleLive = NULL;
static void *SDLHandleLive = NULL;

JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInitLive(JNIEnv* env, jobject instance, jstring lib)
{
    const char *libString = (*env)->GetStringUTFChars(env, lib, NULL);
    __android_log_print(ANDROID_LOG_INFO, "SDL", "Java_org_libsdl_app_SDLActivity_nativeInitLive %s", libString);
    (*env)->ReleaseStringUTFChars(env, lib, libString);

    mainHandleLive = dlopen("/data/app-lib/org.libsdl.app-1/libmain.so", RTLD_NOW | RTLD_LOCAL);
    if (mainHandleLive == 0)
    {
        __android_log_print(ANDROID_LOG_INFO, "SDL", "/data/app-lib/org.libsdl.app-1/libmain.so failed to open");
    }
    SDLHandleLive = dlopen("/data/app-lib/org.libsdl.app-1/libSDL2.so", RTLD_NOW | RTLD_LOCAL);
    if (SDLHandleLive == 0)
    {
        __android_log_print(ANDROID_LOG_INFO, "SDL", "/data/app-lib/org.libsdl.app-1/libSDL2.so failed to open");
    }

}

I have two questions, the initial post that lead me to this idea used a function prototype like this:

dlmopen(LM_ID_NEWLM, "path/to/lib", RTLD_NOW | RTLD_LOCAL);

on android compiling with LM_ID_NEWLM throws an LM_ID_NEWLM undeclared (first use in this function).

So I tried to use RTLD_LOCAL based on this question

I don't currently get any errors when compiling this project.

My question now is, how do I actually use these libs once they have been loaded from c code?

Community
  • 1
  • 1
user1610950
  • 1,837
  • 5
  • 33
  • 49
  • `if (lib == 0)`? Shouldn't that be `if (mainHandle == NULL)` or `if (sdlHandle == NULL)`? And will loading it twice help? Per http://man7.org/linux/man-pages/man3/dlopen.3.html: "If the same shared object is loaded again with dlopen(), the same object handle is returned." – Andrew Henle Sep 25 '15 at 10:18
  • libe == 0 was a type when I was pasting over some code. As per the link that you provided the flag RTLD_LOCAL "Symbols defined in this shared object are not made available to resolve references in subsequently loaded shared objects." which basically treats the shared library as a static per call, unless I am mistaken, which I could be. – user1610950 Sep 25 '15 at 11:45
  • It's still not clear to me what you're trying to accomplish. If there are two instances of your app running, in separate processes, they can both load the same library and will not interfere with each other. Using `dlopen()` directly doesn't really do anything different from `loadLibrary()`. Are you trying to have two distinct copies of the same shared library *in a single process*? If so... why? Is it a poorly-designed library with lots of globals? – fadden Sep 25 '15 at 16:04
  • I would like to have two distinct copies of the shared lib for two instances of the same application. It's not the same process but if one process is already loaded then another process opens up that accesses those libs, this causes a lot of trouble. – user1610950 Sep 25 '15 at 16:44
  • Simply opening the same library in two separate processes should not cause any trouble. Every process in the system has various libraries open (e.g.libc). The only way you should be having problems is if the library requires exclusive access to some global resource, in which case it doesn't matter what games you play with dlopen(). – fadden Sep 25 '15 at 22:44
  • It's causing issues for me. If I load the .so in the applications onCreate() function for instance A. Then launch a different instance B, when onCreate() is called, instead of loading a new copy of the shared object the logcat output shows that, /data/app-lib/org.libsdl.app-1/libSDL2.so already loaded at address: 0x42495a50 and returns that one, at which point both instances of the application get messed up. – user1610950 Sep 26 '15 at 10:03

1 Answers1

0

No you cannot use JNI if you don't use System.loadLibrary() or equivalent.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • Is it possible to write a loader library, load that with system.loadlibrary; then based on some runtime variables from java use that lib to do the dlopen and have possibly two instances of the required library at runtime? – user1610950 Sep 25 '15 at 13:48
  • Yes it is possible. You are looking for a way to keep some global variables separate? They may get obscured by one another – Alex Cohn Sep 25 '15 at 16:07
  • Yes, since they are two distinct processes, there should be a way to load the .so so that they don't collide. I am now loading a wrapper lib, then writing some code to create two handles, that are opened with this command: dlopen("/data/app-lib/app.name/libWantedLib.so", RTLD_NOW); I am not sure if this will be the same as calling system.loadlibrary() and I was hoping to get some insight before going too far down this path only to end up where I started. Not only that, it seems that androids dlopen() doesn't support that many flags. – user1610950 Sep 25 '15 at 17:04
  • 1
    If you use a lib in two separate [processes](http://www.tldp.org/LDP/tlk/kernel/processes.html), you don't have what to worry about to begin with: each can load it own library with `System.load()` or `ldopen()` and be completely isolated from the other. – Alex Cohn Sep 25 '15 at 18:20
  • On the other hand `RTLD_GROUP` is not supported on Android, therefore you cannot use two libraries with exported symbols that have same names. – Alex Cohn Sep 25 '15 at 18:30
  • I should've wrote this down here. The problem that I am facing is that I load a .so library in my onCreate(); function. For the first instance of the service I see the typical loading lib: Trying to load lib /data/app-lib/org.libsdl.app-1/libSDL2.so 0x42495a50 | Added shared lib /data/app-lib/org.libsdl.app-1/libSDL2.so 0x42495a50, etc... On the seconds instance of the service, in the onCreate function instead of loading the lib again it says already found ..../libSDL2.so at address 0x...... and returns that one. At which point my app breaks. Any possible solution? – user1610950 Sep 26 '15 at 10:08
  • Your app breaks - how exactly? Do you get a crash? One possible problem could be that the same Java objects are accessed from two different threads. You can try to put such variables in thread local storage. – Alex Cohn Sep 26 '15 at 14:14
  • I'd like to avoid this: loading library SDL2 Trying to load lib /data/app-lib/org.libsdl.app-1/libSDL2.so 0x428b4ee8 Shared lib '/data/app-lib/org.libsdl.app-1/libSDL2.so' already loaded in same CL 0x428b4ee8 As you can see when the service loads the shared library on the first launch everything is fine. When the service is launched again, the shared library is already loaded and it gets linked. That's where the trouble happens. – user1610950 Sep 26 '15 at 14:23
  • What is not clear to me why "is already loaded" is wrong for you. But maybe you want to start two services as separate processes? – Alex Cohn Sep 26 '15 at 15:21
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/90694/discussion-between-user1610950-and-alex-cohn). – user1610950 Sep 26 '15 at 17:39