Android NDK UnsatisfiedLinkError - a surprising reason
Asked Answered
P

3

12

Update 8/7/2013: The problem is solved now, but the reason for the error was quite unexpected, all the usual suspects for such errors were eliminated on start, and I have learned something new. See my answer below.


I'm pretty desperate here. Have an Android app with a native library, from where I call a method. No problem on all the systems I tested, and the program was out in Google Play without any trouble reports, used by thousands of users. Now, apparently a new ROM - Android version 4.2.2 - for HTC One phone is out. Users claim that it's the official build, upgraded form the official channel. When they try to start my app, it crashes, and the stack trace says:

java.lang.UnsatisfiedLinkError: Native method not found...

and the method name of which I know is there and worked fine a moment ago on the same device when they had Android 4.1 installed. I test it under Android 4.2.2 in emulators (don't have this particular device) and there is no problem. Also, the users tried uninstalling and reinstalling the app with the same result. Even sending them a private build, without any ProGuard/Dexguard protections does not help.

What else can cause java.lang.UnsatisfiedLinkError on Android? Or should I assume that this HTC ROM is simply buggy??? Did anyone else have similar problems on HTC One with Android 4.2.2?

Edit 7/24/2013

In the comments below another developer suggests that the system could have troubles finding my native library. I experimented on Genymotion 4.2.2 emulator by removing the native library file from the setup completely. The error message is different in this situation, got:

W/System.err: Caused by: java.lang.UnsatisfiedLinkError: Couldn't load cld from loader dalvik.system.PathClassLoader[dexPath=/data/app/com.hyperionics.avar-2.apk,libra‌​ryPath=/data/app-lib/com.hyperionics.avar-2]: findLibrary returned null

While in the stack trace messages I got from HTC One users with Android 4.2.2 I see this error message:

Caused by: java.lang.UnsatisfiedLinkError: Native method not found: com.hyperionics.avar.CldWrapper.detectLangNative:(Ljava/lang/String;)[Ljava/lang‌​/String;

To me it appears that the system finds the libcld.so file as needed, but does not find the method it needs there. Why??? I know the method is there, exported as needed, and every other device and system, also these running Android 4.2.2, finds it. Only HTC One with 4.2.2 fails there...

Update 7/25/2013

Started a bounty for 50 rep. points, as I don't have HTC One and am stuck. Will accept an answer that either points a way to solving the problem - and the answering person will test my code mod. to show it works - or proves that this is really a bug in the recent Android 4.2.2 ROM for HTC One. The app in question is https://play.google.com/store/apps/details?id=com.hyperionics.avar

Update 7/31/2013

The last day of the bounty and still no answers, no suggestions... So far, all such error reports I get come from Europe, reported brand is "htc_europe" or "vodafone_fr". Maybe the error is localized to Europe (France + Germany) only... If there is anyone out there with HTC One and Android updated to 4.2.2, I would be interested if the error happens in other countries or with other providers.

Greg

Protect answered 23/7, 2013 at 18:22 Comment(13)
Is the library compiled for armeabi-v7? Do you have any other libraries that run strictly on armeabi. System has a hard time deciding which library to load when you have 2 libraries compiled with armeabi and armeabi-v7. Try moving the library into suitable folder with respect to the armeabi version.Dhoti
@NikolaDespotoski - thank you for answering! In the APK, libs folder, I have sub-folders 'armeabi', 'armeabi-v7a' and 'x86'. Each contains libcld.so with the functions in question. ARM code was compiled in 'thumb' mode for the released code, in my new dev. builds I switched to 'arm' mode. Don't know what else to think of. The app in question is play.google.com/store/apps/details?id=com.hyperionics.avarProtect
As far as I know the system looks for /system/lib/ for shared libs, System.load("path to lib") instead System.loadLibrary("libName")) using Build.class from the SDK or System.getProperty("os.arch"); to get the CPU architecture. For your question I looked at the source code of Build.class and java.lan.Runtime. Here: grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… Basically, see how System.loadLibrary() works to find shared native libs. :)Dhoti
I hope there is way to directly specify the loading path of the lib like System.load("/system/lib/"+cpuArchitectureString+"/libName"); right after you get the cpu architecture and load proper library and spare the system deciding and getting confused which lib to load. I had similar problem, I moved armeabi lib to armeabi-v7a since armeabi is supported in v7 and the exception was gone (device: HTC One X)Dhoti
@NikolaDespotoski - it's supposed to be transparent to Android Java code - all I needed so far, on all versions of Android, in my C wrapper class in Java, was System.loadLibrary("cld"); for a library named libcld.so, and it's supposed to load what it needs... No idea why on this one device it's suddenly different. Maybe I should go and by HTC One myself to see what happens there...Protect
You are right, it should be simple and straight forward with System.loadLibrary(). I'm quite sure that HTC ROM gets confused when it comes from which folder to take your libcld. My gut says it is dilemma between taking the lib either from armeabi or taking armeabi-v7a. Try taking the Genymotion emulator running API level 17, it does shows all Dalvik log output, you can notice how the system looks on libraries and how it decides which one to load. " Also try loading the libs with full path with System.load("/system/lib/armabi/libcld.so"); after you find the architecture.Dhoti
@NikolaDespotoski thanks for mentioning Genymotion and prompting me to look it up. Never heard of it before.Peru
@NikolaDespotoski - yes, I did test on Genymotion (two different emulators with Android 4.2.2) and also on Google emulators with 4.2.2 - no problems there. None whatsoever, all works as it is supposed to. What's more, the system error message is different when the library is not there. I made a test run by removing it manually under 4.2.2, and got: W/System.err: Caused by: java.lang.UnsatisfiedLinkError: Couldn't load cld from loader dalvik.system.PathClassLoader[dexPath=/data/app/com.hyperionics.avar-2.apk,libraryPath=/data/app-lib/com.hyperionics.avar-2]: findLibrary returned nullProtect
@NikolaDespotoski - continuing from previous message, as I run out of space there: the error the users of HTC One report on the other hand is: Caused by: java.lang.UnsatisfiedLinkError: Native method not found: com.hyperionics.avar.CldWrapper.detectLangNative:(Ljava/lang/String;)[Ljava/lang/String; - it appears that they do find the .so library file, but no method needed in it.Protect
Thats necessarily the same cause. Method cannot be loaded because the library was found but not loaded. How about adding different names for the libraries and load them based on cpu architecture?Dhoti
But why? It worked perfectly on_the_same_device when it had Android 4.1.1, only upgrade to 4.2.2 causes the error. System upgrade does not change cpu architecture of a device. It also works fine on 4.2.2 on other devices, only not on HTC One. Darn!Protect
That's logically perfect and valid, CPU arch does not change. I cannot say, did you tried to contact HTC devs? Maybe if you address them directly, (twitter, mail, support site, maybe XDA developers can help you as well) might help you how can the upgrade cause issues loading native libs, particularly your case. They had similar situation with ICS bug.Dhoti
Thank you. Yes, I wrote to HTC through their support site. To me as well, it looks like a bug in their system update, but try to explain it to the users... Time will tell, I guess. Thank you for your support and good luck with everything you do.Protect
P
14

There was no satisfactory answer during the bounty period. I ordered the device and will have to debug what most likely is a system bug in the device ROM for Android 4.2.2 update...

Update 6/20/2014 Another reason for an occasional UnsatisfiedLinkError

It turns out that sometimes, when updating an app from Google Play, native libraries are not installed correctly. Maybe the installer runs out of space, or some other strange system bug kicks in. Please see also this SO question and answers.

Update 8/6/2013 - mystery solved!

My HTC One ordered from Google Play arrived, and... mystery solved! The same crash happened also on the original Android 4.2.2 from Google Play. The problem was my library name: cld, which produces a shared library named libcld.so. Apparently the system has another shared library with the same name, where the methods I expect are not present, of course... Probably some "plugin" loaded this other libcld.so into the process memory, and my own library was skipped. I renamed the native library and the program started working at once.

I was not aware of the possibility of such name clashes on different builds of Android... Did anyone reading this see a warning somewhere in NDK docs about it? I guess I'll prefix from now on all native libraries I create with my company name or something.

Protect answered 2/8, 2013 at 19:30 Comment(4)
Previously, bounties would not just vanish -- either a winner got it all, or it was split between the best answer and the OP (I think)...Cygnet
Hmm. This time my 50 pts. just vanished, the only other answer given by @Flotolk also was not awarded any points from this. Guess I recovered now though, with the up-votes I got on my Q & A.Protect
Well, a year ago I was surprized I did not get it back at least partially in the same situation (flagging gave nothing, and I did not bother to search / ask a question on meta). Or does this finally start to rot? :)Cygnet
I guess you were unlucky to get in trouble during the summer vacations. I believe that's why I missed your question in July. Quite often, bounties do their job.Jacquenette
S
1

You could try taking the method definition from your library, and rewriting it into one of your classes, giving the method a different name. This may be very tedious, but at least you can be certain that your program will be able to find the method...

Sinner answered 1/8, 2013 at 18:47 Comment(1)
thank you for trying to help! I actually got stack traces with two different method names listed as missing. But do you mean that I should re-write the C++ method in Java to make it work on the faulty device? Well, I had them in Java, the whole point of writing native libraries was to make the app faster. And it works on all devices but HTC One, and even on HTC One with older version of Android...Protect
A
1
defaultConfig {
    ...
    ndk {
        abiFilters "armeabi-v7a", "x86", "armeabi", "mips"
    }
}
Allard answered 4/11, 2016 at 10:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.