↩ home



A Journey to learn android ABI folders

25 Jul 2016

One day, by testing a video player feature on my app, I got this exception which I never had before :

java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.myfox.android.mss.debug-2/base.apk"],nativeLibraryDirectories=[/data/app/com.myfox.android.mss.debug-2/lib/arm64, /data/app/com.myfox.android.mss.debug-2/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]]] couldn't find "libcrypto.so"

Here the story of how I resolved it.

 

The library folder and ABI selection


I opened my APK file with my usual ZIP extractor and all video-related libraries (in which libcrypto.so) are in the armeabi folder. Other ABI are supported by only one other library, uCrop (image cropper - https://github.com/Yalantis/uCrop/tree/master/ucrop/src/main/jniLibs).

arm64-v8a/  
armeabi-v7a/  
x86/  
x86_64/  
armeabi/  

Hum...

When I read deeper into the exception, only /lib/arm64 and /lib/arm64-v8a are used to search libcrypto.so. For sure it will never find it...

After documenting myself about ABI folders I find that Android only looks into two folders: primary ABI and secondary ABI. If you want to know which ABI your device would use, you can execute :

adb shell getprop | grep abi

Which give on my Galaxy S7 :

[ro.product.cpu.abi]: [arm64-v8a]
[ro.product.cpu.abilist]: [arm64-v8a,armeabi-v7a,armeabi]
[ro.product.cpu.abilist32]: [armeabi-v7a,armeabi]
[ro.product.cpu.abilist64]: [arm64-v8a]

Interesting... my device supports armeabi. But it chooses to use only 64-bits ABI.

 

Too much ABI ?


Android is only capable to search in only two ABI folders. So when it finds at first load a 64-bits ABI folder, he thinks "Okay this app supports 64-bits libraries" and this is a definitive decision for every library you have.

Let's do a test : I remove manually x86 and 64-bits supports by uCrop, I keep only armeabi-v7a/ and armeabi/.

Execute. Yes, it works!

 

Solution : you only must keep ABI folders supported by every native library


But how to integrate this rule to gradle ? Because I don't want to fork uCrop and remove manually unwanted ABI folders.

abiFilters will do the job. You can specify one or more ABI to keep in a productFlavor.

flavorDimensions "abi"

armeabi {
   dimension "abi"
   ndk {
      abiFilters "armeabi-v7a"
   }
}

It seems you can chose more than one ABI with :

abiFilters.add("armeabi")
abiFilters.add("armeabi-v7a")
abiFilters.add("x86")

But I did not tested it.



Top