Search code examples
androidandroid-ndkjava-native-interface

java.lang.UnsatisfiedLinkError when loading native library in Android 5.0


I am loading my native library by:

try {
       System.loadLibrary("myNative");
} catch (UnsatisfiedLinkError e) {
       //java.lang.UnsatisfiedLinkError here
       System.load("/data/data/com.my.app/app_native/libmyNative.so");
}

The above code is finally packaged to a Jar file.

In another project, I load the above Jar with DexClassLoader:

DexClassLoader dexClassLoader = new DexClassLoader(jarPath,
                    optJarPath,
                    getDir("native", Context.MODE_PRIVATE),
                    getClassLoader());

Notice that when constructing this dexClassLoader instance, I have specified the path where the native code is located, that's getDir("native", Context.MODE_PRIVATE).

(I am using NDK release 10 to generate the native library. When the native code file libmyNative.so is generated, my java code (which packaged to final Jar) checks the CPU architecture type & copy the right one to getDir("native", Context.MODE_PRIVATE).)

The above code works fine on other devices except Android 5.0 Lollipop. When run on Android 5.0 Lollipop device, I constantly get the following error:

java.lang.UnsatisfiedLinkError: dlopen failed: "/data/data/com.my.app/app_native/libmyNative.so" is 32-bit instead of 64-bit
at java.lang.Runtime.load(Runtime.java:331)
at java.lang.System.load(System.java:982)

How to solve this problem?


Solution

  • You appear to be attempting to use a 32-bit library on a 64-bit target. If you can't provide a 64-bit one, you will have to convince Android to fallback to 32-bit mode to accommodate the library.

    Apparently, compatibility mode (the source seems to call it an ABI override) is normally set at install time, by the installer discovering that only 32-bit (and not 64-bit) libraries are available. But in your case, the library is not visible at install time, so that won't work.

    If you place a "dummy" 32-bit lib in the apk that is the closest match for the 64-bit device's needs, then the system will hopefully configure your app to run in 32-bit compatibility mode so that later loading your real 32-bit lib will actually work.

    I don't know if the 32-bit lib would need to be a real one vs. an empty file with the correct location and plausible name, but the hello-jni project from the ndk samples folder's libhello-jni.so should should work. You won't need any corresponding java code, just to have a native library the installer can discover (however, calling into it as a test might not be a bad idea).

    It is possible there may be some other way(s) to trigger this, such as something in the manifest (though nothing is mentioned in the documentation). I'd be less likely to suspect that any measures at runtime will work, since this mode may already be firmly set before any of your code runs (it looks like you may actually end up with two instances of zygote running on such a system, one 64 bit and the other 32, with the idea being that apps get launched by whichever one is believed to be appropriate).