3

I have a.so which defines void a() and b.so which defines void b(). They are both put in the .apk so they are available to the Android application.

Now suppose that I'm calling a() through JNI. Is it possible to call b() from a() while completely bypassing JNI?

Can I do it this way in Android (the code is only for illustration, so it might have some errors)?

void a() {
    void *handle = dlopen("b.so", RTLD_LAZY);
    void (*b)() = dlsym(handle, "b");
    b();
}

Would I need to add the fully qualified path, or is b.so already in LD_LIBRARY_PATH for the app?

sashoalm
  • 75,001
  • 122
  • 434
  • 781

2 Answers2

1

You can do it this way on Android, though take care of where the shared library has been put in Android folders. It can change from a version to another. On api 17 for example, it remains in /data/app-lib/. You can hardwrite it, but the best is to make calls to Java (through JNI) to know where the libraries should be. We're doing something like this in our project :

JNIEnv* env;
const char* temp;

jobject oActivity = state->activity->clazz;
jclass cActivity = env->GetObjectClass(oActivity);

// get the path to where android extracts native libraries to
jmethodID midActivityGetApplicationInfo = env->GetMethodID(cActivity, "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;");
jobject oApplicationInfo = env->CallObjectMethod(oActivity, midActivityGetApplicationInfo);
jclass cApplicationInfo = env->GetObjectClass(oApplicationInfo);
jfieldID fidApplicationInfoNativeLibraryDir = env->GetFieldID(cApplicationInfo, "nativeLibraryDir", "Ljava/lang/String;");
jstring sNativeLibraryDir = (jstring)env->GetObjectField(oApplicationInfo, fidApplicationInfoNativeLibraryDir);
temp = env->GetStringUTFChars(sNativeLibraryDir, NULL);
strcpy(libpath, temp);
strcat(libpath, "/");

Then you push your dlopen + dlsym combo in the fight and it should work.

brainsandwich
  • 472
  • 3
  • 10
0

As mentioned here : How do I load a shared object in C++?

There are two ways of loading shared objects in C++

For either of these methods you would always need the header file for the object you want to use. The header will contain the definitions of the classes or objects you want to use in your code.

#include "blah.h"
int main()
{
  ClassFromBlah a;
  a.DoSomething();
}

gcc yourfile.cpp -lblah

Dynamically (In Linux):

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **argv) {
    void *handle;
    double (*cosine)(double);
    char *error;
    handle = dlopen ("libm.so", RTLD_LAZY);
    if (!handle) {
        fprintf (stderr, "%s\n", dlerror());
        exit(1);
    }
    dlerror();    /* Clear any existing error */
    cosine = dlsym(handle, "cos");
    if ((error = dlerror()) != NULL)  {
        fprintf (stderr, "%s\n", error);
        exit(1);
    }
    printf ("%f\n", (*cosine)(2.0));
    dlclose(handle);
    return 0;
}

PS : for the dynamic approach, it depends on platform : on Linux, you use dlopen, on windows, you use LoadLibrary.

Community
  • 1
  • 1
Fouad Wahabi
  • 804
  • 7
  • 16
  • 1
    My code is neither Linux nor Windows - it's Android, as I've pointed out in my question. I'm not interested in those other OSes. – sashoalm May 21 '15 at 13:16
  • @sashoalm what's the error you've encountered when using `dlopen` ? – Fouad Wahabi May 21 '15 at 13:25
  • Sorry for any misunderstandings. There is no error, my code is for illustration only, I ask how it's done in the first place, and give an example asking if it'll work in an Android app. I'll get around to testing it eventually and if my code works, I'll post it as an answer. – sashoalm May 21 '15 at 13:42
  • so I'm not sure exactly if using `dlopen` works correctly with Android system but I think there's no reason that makes it don't work , I'll just try it soon – Fouad Wahabi May 21 '15 at 13:44
  • 1
    Thanks. Creating the test project itself is a difficulty for me, that's part of why I asked it :) – sashoalm May 21 '15 at 13:48