I am writing a game, and I have huge native library, I am trying to load my native library in my main activity like
static {
try {
System.loadLibrary("mylib");
} catch (UnsatisfiedLinkError e) {
Log.d(TAG, "Unsatisfied Link error: " + e.toString());
}
}
I have tested this code on many devices in house, I don't get this error. but from my published I do get logs with "Caused by: java.lang.UnsatisfiedLinkError: Cannot load library". NOTE: This crash is not universal, only few people are getting this crash
Is it problem where the library is put in exported apk ? I have now library put into /libs/armabi/libmylib.so automatically by eclipse?
Is it some thing to do with version of android ? I am supporting android versions since 2.3 (API level 9)
or do I need to load library from different place?
or am I missing something very important
Is it problem with whole app being installed on SDCARD ?
More Info on crash is : load_segments: 68 failed to map segment from mylib.so
Considering that your app works correctly on most of the devices and only sometimes gives you the error, it's safe to assume that the library is packaged correctly in the APK and that its size/memory footprint is also acceptable.
As such, I'll go on the whim and suggest that the problem is with the build/compile architecture of the library. Most newer Android devices use ARM7 processor. It's quite likely that your library is compiled against ARM7 architecture as well. Some older devices, especially those running Android 2.3, use ARM6 processor (I have one such device that I use for testing - LG GT540 running Android 2.3.3), which is not forward-compatible with ARM7 architecture. I have seen a crash with error similar to the one you indicated (load_segments: 68 failed to map segment from mylib.so) when I attempted to run an app designed for ARM7 on my old ARM6 phone.
There are three ways of going around this issue:
Compile the library against both architectures and include two separate .so files into the apk. Then at runtime determine the type of processor and load the correct one. Frankly, I don't know if this is even possible.
Create two separate apk files - one for ARM6 and one for ARM7 - then use filters in the manifest to specify the corresponding architecture. You can upload both of them to google play for the same app - and filters in the manifest will control which one is downloaded to which device.
Only support ARM7 architecture by specifying device requirements in your manifest. You will loose some customer audience, but will have less work for yourself maintaining the two versions of the app.
EDIT: According to NDK documentation, it can produce multiple libraries for different architectures in one go. You can control specifically which CPUs you want to target by adding the following line into the Application.mk file:
APP_ABI := arch1 arch2 arch3 ...
for example,
APP_ABI := armeabi armeabi-v7a mips
Then the build process will create different versions of the native library. These versions will need to be placed in the final apk in directory
lib/<abi>/lib<name>.so
where is the name of the architecture. You will then load the library with
System.loadLibrary("<name>");
Alternatively you can build separate apk files for each architecture then use multi-apk functionality on google play.
You can find all the information on architecture targeting in file CPU-ARCH-ABIS.html file in the docs subdirectory of the NDK.
Related
I have developed android project using android studio.
It uses android native library which other developer built for speech recognization.
The APK works perfectly when i install on android devices.
I need to put this APK into AOSP because I am going to make android device only for our system. (I have already customized AOSP)
But after adding the APK into AOSP, the APK can not load library.
Error log:
java.lang.UnsatisfiedLinkError: dlopen failed: can't protect segments for "../libsengine.so": Permission denied
Please help me to fix this problem.
If you add your apk into AOSP system/app/ path as a prebuilt app, this might be of help:
Error adding prebuilt apk with shared libraries to AOSP
http://blog.csdn.net/a462533587/article/details/46380795
The problem is the shared library packaged in your apk has never been extracted to /data/app-lib directory, so it can't be linked.
It seems that the library you are using is utilizing some sort of dynamic code loading that is strictly prohibided on Android 26+ (Writable and Executable Segments Enforced for API level >= 26) .
You can read more about the security risk of TEXTREL on the following blog.
I assume that the reason the code works when compiling with Android Studio is because your build.gradle defines a minSdkVersion/targetSdkVersion that does not enforce the TEXTREL check. When compiling via the AOSP make, targetSdkVersion is most probably defined to be the 'current' version where the TEXTREL check is enforced.
These are only assumptions, so I guess you could check or alternatively provide more information such as the platform you are building and the Android.mk + build.gradle files.
I Think This is related to Marshmallow switching from OpenSSL to BoringSSL.
Your exception is occurring in the referenced library code. Contact the vendor for a fix or manually include the OpenSSL libraries to avoid the issue.
You can see this link: https://sourcedna.com/blog/20150806/predicting-app-crashes-on-android-m.html
Assume we have a jni folder structure below.
armeabi
a.so
b.so
armeabi-v7a
a.so
On a ARMv7-based device, I want to load b.so, but the there is no b.so under folder "armeabi-v7a", so will the system report a not found library error or use the b.so under folder "armeabi"?
And even more, what order does system look for a so file among armeabi,armeabi-v7a,arm64-v8a,x86,x86_64? For example, on a x86_64-based device, system look for the so file in folder x86_64 first, but if not found, will system continue to look for the file in x86,arm64-v8a,armeabi-v7a,armeabi in sequence?
Have you seen: http://developer.android.com/ndk/guides/abis.html#am
I believe it answers your questions:
Both the Play Store and Package Manager expect to find NDK-generated
libraries on filepaths inside the APK matching the following pattern:
/lib/<abi>/lib<name>.so
If the system does not find the native shared libraries where it expects
them, it cannot use them. In such a case, the app itself has to copy the
libraries over, and then perform dlopen().
Further down the page is this particular bit:
Automatic extraction of native code at install time
When installing an application, the package manager service scans the APK, and looks for any shared libraries of the form:
lib/<primary-abi>/lib<name>.so
If none is found, and you have defined a secondary ABI, the service scans for shared libraries of the form:
lib/<secondary-abi>/lib<name>.so
When it finds the libraries that it's looking for, the package manager copies them to /lib/lib.so, under the application's data directory (data/data//lib/).
If there is no shared-object file at all, the application builds and installs, but crashes at runtime.
So in your case if you are on a armeabi-v7a architecture, you'll have to copy the lib/armeabi/libb.so file over and use dlopen() as the PackageManager knows nothing of what needs to be loaded in your app but did find something in the lib/armeabi-v7a directory.
In addition to Morrison Chang's answer, one could always consider dropping the armeabi part altogether (so you don't need two copies of the lib, which I guess is large). In practice, there are very few modern devices (running Android 4.0 or newer) that support armeabi but not armeabi-v7a (and none since Android 4.4). See https://stackoverflow.com/a/30924571/3115956, https://stackoverflow.com/a/28926267/3115956 for a few cases of that. That will reduce the file size without losing support for any significant part of your target userbase, assuming that you require Android 4.0. If you still target older versions, it's more of a reason to keep armeabi though.
This question already has an answer here:
UnsatisfiedLinkError on Android 5.0 Lollipop
(1 answer)
Closed 7 years ago.
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?
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).
My project includes native libraries compiled only for ARMv7. When I try to install it on Samsung Galaxy Y (which has ARMv6), I get INSTALL_FAILED_CPU_ABI_INCOMPATIBLE error.
However, I want to make my application deployable for every devices, no matter they have ARMv7 or not. If target device is an ARMv7, using native library will be a plus. That's it. For the rest of devices, application will do its job without calling native methods. (Because of libary has a large .so file, I don't want to include compilations for other architectures).
Any ideas to overcome this error ? How can I tell Android to ignore native libraries compiled for different architectures and make my APK deployable ?
PS. I'm seeking soultions rather than "creating mutiple APKs"
Thanks
So, by looking trough the NDK documentation I found this interesting hint (look inside the NDK folder in docs/Programmers_Guide/html/md_3__key__topics__c_p_u__support__chapter_1-section_8__a_b_is.html):
put your library inside assets folder
at runtime detect the cpu architecture using this java call: String arch = System.getProperty("os.arch");
If the result is something like "armv71" copy the lib from your assets to your data directory in the lib subdir: /data/data/<package_name>/lib/
Now you can safely call System.loadLibrary(...)
Should/does NDK9 work with android API19? (though it was released with API18).
Full story:
I was building an Android App using kivy, python-for-android and buildozer.
compiling with MDK9 (ie 9d) and api19 result in error:
E/AndroidRuntime( 1773): java.lang.UnsatisfiedLinkError: Cannot load library: soinfo_relocate(linker.cpp:975): cannot locate symbol "wait4" referenced by "libpython2.7.so"...
compiling with NDK9 (ie 9d) and API18 works. :)
Just in case anyone stumbles across this. I had the same issue, but building python from scratch using the platform tools, and with NDK r10 and r10b.
It's because google removed an inline wait4() declaration in the NDK platform android-19. The original problem was that wait4() was exposed in the headers but not declared anywhere, so if you tried to use wait4 on older NDKs, you'd probably crash (like you do now).
So they went in and added it to libc.so in API 18 I believe, but libc.so is shipped with the O/S, so devices with O/S older than 18 would not have wait4, so they patched it by adding an inlined wait4() method in NDK platforms up through android-18, then took it out in android-19 I'm not fully sure why yet, seems like it could have made more sense to leave it alone at that point, especially since it's considered an obsolete function. I was told I should not build against android-19 if I wanted the app to run on devices older than API 18, but others say to always use the latest NDK to match your build target. Here is a link to the problem.
https://code.google.com/p/android/issues/detail?id=19854
In my case, I went into the cpython Modules/posixmodule.c file, and added:
#if defined(__ANDROID__)
#undef HAVE_WAIT4
#endif
And in my case that's fine, because none of my python modules use wait4. Indeed, Linux deems the wait4 command obsolete (http://linux.die.net/man/2/wait4). You should instead use the waitpid.
So, even if you download some 3rd party python module that does use wait4, you have 2 options. 1) change that module to use waitpid, or 2) update the Modules/posixmodule.c file inside the "ifdef HAVE_WAIT4" section, and replace the wait4 call with waitpid. The downside is you lose the returned resource usage information, which waitpid doesn't provide, so then if your module needs that, you'd have to add something to retrieve resource usage for that pid separately.
Alternatively, you could remove "wait4" from your configure script if you never plan to use it, and any modules you add that needed it would break, at which point the new engineer working on the problem would have to rediscover all of this over again.
Android SDK are released more often that NDK. It happened more than once that if you use a too recent SDK, the NDK will not have the .h for it. Now i'm not sure this would be related to your issue at all.