Why do some Android phones cause our app to throw an java.lang.UnsatisfiedLinkError?

philipp

We're experiencing a java.lang.UnsatisfiedLinkError on some of the Android phones that are using our app in the market.

Problem description:

static
{
    System.loadLibrary("stlport_shared"); // C++ STL        
    System.loadLibrary("lib2"); 
    System.loadLibrary("lib3"); 
}

Crashes the app in on of the System.loadLibrary() lines with a java.lang.UnsatisfiedLinkError. java.lang.UnsatisfiedLinkError: Couldn't load stlport_shared from loader dalvik.system.PathClassLoader[dexPath=/data/app/app_id-2.apk,libraryPath=/data/app-lib/app_id-2]: findLibrary returned null

Solution approach

We started running some custom diagnostics on all our installs to check if every lib is unpacked in the /data/data/app_id/lib folder.

PackageManager m = context.getPackageManager();
String s = context.getPackageName();
PackageInfo p;
p = m.getPackageInfo(s, 0);
s = p.applicationInfo.dataDir;

File appDir = new File(s);
long freeSpace = appDir.getFreeSpace();

File[] appDirList = appDir.listFiles();
int numberOfLibFiles = 0;
boolean subFilesLarger0 = true;
for (int i = 0; i < appDirList.length; i++) {

    if(appDirList[i].getName().startsWith("lib")) {
        File[] subFile = appDirList[i].listFiles(FileFilters.FilterDirs);   
        numberOfLibFiles = subFile.length;
        for (int j = 0; j < subFile.length; j++) {
            if(subFile[j].length() <= 0) {
                subFilesLarger0 = false;
                break;
            }
        }
    }
}

On every test phone that we have numberOfLibFiles == 3 and subFilesLarger0 == true. We wanted to test if all libs are unpacked properly and are larger then 0 byte. In addition we're looking at freeSpace to see how much disk space is available. freeSpace matches the amount of memory that you can find in Settings --> Applications at the bottom of the screen. The thinking behind this approach was that when there is not enough space on the disk available that the installer might have problems unpacking the APK.

Real world scenario

Looking at the diagnostics, some of the devices out there do NOT have all 3 libs in the /data/data/app_id/lib folder but have plenty of free space. I'm wondering why the error message is looking for /data/app-lib/app_id-2. All our phones store their libs in /data/data/app_id/lib. Also the System.loadLibrary() should use a consistent path across installation and loading the libs? How can I know where the OS is looking for the libs?

Question

Anyone experiencing problems with installing native libs? What work arounds have been successful? Any experience with just downloading native libs over the internet when they are not existent and storing them manually? What could cause the problem in the first place?

EDIT

I now also have a user who runs into this problem after an application update. The previous version worked fine on his phone, an after an update the native libs seem missing. Copying the libs manually seem to cause trouble as well. He is on android 4.x with a non rooted phone without custom ROM.

EDIT 2 - Solution

After 2 years of spending time on this problem. We came up with a solution that works well for us now. We open sourced it: https://github.com/KeepSafe/ReLinker

gregko

I have the same trouble, and the UnsatisfiedLinkErrors comes on all versions of Android - over the past 6 months, for an app that currently has over 90000 active installs, I had:

Android 4.2     36  57.1%
Android 4.1     11  17.5%
Android 4.3     8   12.7%
Android 2.3.x   6   9.5%
Android 4.4     1   1.6%
Android 4.0.x   1   1.6%

and the users report that it usually happens just after the app update. This is for an app that gets around 200 - 500 new users per day.

I think I came up with a simpler work-around. I can find out where is the original apk of my app with this simple call:

    String apkFileName = context.getApplicationInfo().sourceDir;

this returns something like "/data/app/com.example.pkgname-3.apk", the exact file name of my app's APK file. This file is a regular ZIP file and it is readable without root. Therefore, if I catch the java.lang.UnsatisfiedLinkError, I can extract and copy my native library, from the inside of .apk (zip) lib/armeabi-v7a folder (or whatever architecture I'm on), to any directory where I can read/write/execute, and load it with System.load(full_path).

Edit: It seems to work

Update July 1, 2014 since releasing a version of my product with the code similar to the listed below, on June 23, 2014, did not have any Unsatisfied Link Errors from my native library.

Here is the code I used:

public static void initNativeLib(Context context) {
    try {
        // Try loading our native lib, see if it works...
        System.loadLibrary("MyNativeLibName");
    } catch (UnsatisfiedLinkError er) {
        ApplicationInfo appInfo = context.getApplicationInfo();
        String libName = "libMyNativeLibName.so";
        String destPath = context.getFilesDir().toString();
        try {
            String soName = destPath + File.separator + libName;
            new File(soName).delete();
            UnzipUtil.extractFile(appInfo.sourceDir, "lib/" + Build.CPU_ABI + "/" + libName, destPath);
            System.load(soName);
        } catch (IOException e) {
            // extractFile to app files dir did not work. Not enough space? Try elsewhere...
            destPath = context.getExternalCacheDir().toString();
            // Note: location on external memory is not secure, everyone can read/write it...
            // However we extract from a "secure" place (our apk) and instantly load it,
            // on each start of the app, this should make it safer.
            String soName = destPath + File.separator + libName;
            new File(soName).delete(); // this copy could be old, or altered by an attack
            try {
                UnzipUtil.extractFile(appInfo.sourceDir, "lib/" + Build.CPU_ABI + "/" + libName, destPath);
                System.load(soName);
            } catch (IOException e2) {
                Log.e(TAG "Exception in InstallInfo.init(): " + e);
                e.printStackTrace();
            }
        }
    }
}

Unfortunately, if a bad app update leaves an old version of the native library, or a copy somehow damaged, which we loaded with System.loadLibrary("MyNativeLibName"), there is no way to unload it. Upon finding out about such remnant defunct library lingering in the standard app native lib folder, e.g. by calling one of our native methods and finding out it's not there (UnsatisfiedLinkError again), we could store a preference to avoid calling the standard System.loadLibrary() altogether and relying on our own extraction and loading code upon next app startups.

For completeness, here is UnzipUtil class, that I copied and modified from this CodeJava UnzipUtility article:

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class UnzipUtil {
    /**
     * Size of the buffer to read/write data
     */

    private static final int BUFFER_SIZE = 4096;
    /**
     * Extracts a zip file specified by the zipFilePath to a directory specified by
     * destDirectory (will be created if does not exists)
     * @param zipFilePath
     * @param destDirectory
     * @throws java.io.IOException
     */
    public static void unzip(String zipFilePath, String destDirectory) throws IOException {
        File destDir = new File(destDirectory);
        if (!destDir.exists()) {
            destDir.mkdir();
        }
        ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath));
        ZipEntry entry = zipIn.getNextEntry();
        // iterates over entries in the zip file
        while (entry != null) {
            String filePath = destDirectory + File.separator + entry.getName();
            if (!entry.isDirectory()) {
                // if the entry is a file, extracts it
                extractFile(zipIn, filePath);
            } else {
                // if the entry is a directory, make the directory
                File dir = new File(filePath);
                dir.mkdir();
            }
            zipIn.closeEntry();
            entry = zipIn.getNextEntry();
        }
        zipIn.close();
    }

    /**
     * Extracts a file from a zip to specified destination directory.
     * The path of the file inside the zip is discarded, the file is
     * copied directly to the destDirectory.
     * @param zipFilePath - path and file name of a zip file
     * @param inZipFilePath - path and file name inside the zip
     * @param destDirectory - directory to which the file from zip should be extracted, the path part is discarded.
     * @throws java.io.IOException
     */
    public static void extractFile(String zipFilePath, String inZipFilePath, String destDirectory) throws IOException  {
        ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath));
        ZipEntry entry = zipIn.getNextEntry();
        // iterates over entries in the zip file
        while (entry != null) {
            if (!entry.isDirectory() && inZipFilePath.equals(entry.getName())) {
                String filePath = entry.getName();
                int separatorIndex = filePath.lastIndexOf(File.separator);
                if (separatorIndex > -1)
                    filePath = filePath.substring(separatorIndex + 1, filePath.length());
                filePath = destDirectory + File.separator + filePath;
                extractFile(zipIn, filePath);
                break;
            }
            zipIn.closeEntry();
            entry = zipIn.getNextEntry();
        }
        zipIn.close();
    }

    /**
     * Extracts a zip entry (file entry)
     * @param zipIn
     * @param filePath
     * @throws java.io.IOException
     */
    private static void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
        byte[] bytesIn = new byte[BUFFER_SIZE];
        int read = 0;
        while ((read = zipIn.read(bytesIn)) != -1) {
            bos.write(bytesIn, 0, read);
        }
        bos.close();
    }
}

Greg

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Android - Scandit - java.lang.UnsatisfiedLinkError

From Dev

java.lang.UnsatisfiedLinkError error in android

From Dev

java.lang.UnsatisfiedLinkError error in android

From Dev

Some of our Android in-app products are subscriptions, some are not, is this allowed?

From Dev

After some time barcode scanner throws java.lang.UnsatisfiedLinkError

From Dev

FATAL EXCEPTION: main java.lang.UnsatisfiedLinkError in Android Studio library

From Dev

Running android native code is causing java.lang.UnsatisfiedLinkError

From Dev

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

From Dev

java.lang.UnsatisfiedLinkError after updating to Android 5.0

From Dev

java.lang.UnsatisfiedLinkError - NDK in android studio gradle?

From Dev

java.lang.UnsatisfiedLinkError when using with android 5.0

From Dev

Android M crash java.lang.UnsatisfiedLinkError: dlopen failed:

From Dev

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

From Dev

Why does my app look smaller on High Resolution Android phones?

From Dev

Android - In App Purchase Testing - Do I Need 2 Phones?

From Dev

Why do I get java.lang.ExceptionInInitializerError when I start the android app which uses tes two OCR engine

From Dev

OpenCV java.lang.UnsatisfiedLinkError

From Dev

eclipse: java.lang.UnsatisfiedLinkError

From Dev

JNI java.lang.UnsatisfiedLinkError

From Dev

Why do some Facebook User Ids randomly throw a graph exception?

From Dev

Why "This app has been built with an incorrect configuration" error occured in some phones?

From Dev

Android - Declaring an App is Only for phones

From Dev

JavaFX - Why does this throw a java.lang.NullPointerException?

From Dev

DownloadManager in Android (xamarin) throw Java.Lang.IllegalArgumentException

From Dev

Do android phones sync with Ubuntu?

From Dev

Do android phones sync with Ubuntu?

From Dev

How to fix java.lang.UnsatisfiedLinkError in java

From Dev

Opencv Android: java.lang.UnsatisfiedLinkError: dlopen failed: could not load library "libopencv_java.so"

From Dev

Opencv Android: java.lang.UnsatisfiedLinkError: dlopen failed: could not load library "libopencv_java.so"

Related Related

  1. 1

    Android - Scandit - java.lang.UnsatisfiedLinkError

  2. 2

    java.lang.UnsatisfiedLinkError error in android

  3. 3

    java.lang.UnsatisfiedLinkError error in android

  4. 4

    Some of our Android in-app products are subscriptions, some are not, is this allowed?

  5. 5

    After some time barcode scanner throws java.lang.UnsatisfiedLinkError

  6. 6

    FATAL EXCEPTION: main java.lang.UnsatisfiedLinkError in Android Studio library

  7. 7

    Running android native code is causing java.lang.UnsatisfiedLinkError

  8. 8

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

  9. 9

    java.lang.UnsatisfiedLinkError after updating to Android 5.0

  10. 10

    java.lang.UnsatisfiedLinkError - NDK in android studio gradle?

  11. 11

    java.lang.UnsatisfiedLinkError when using with android 5.0

  12. 12

    Android M crash java.lang.UnsatisfiedLinkError: dlopen failed:

  13. 13

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

  14. 14

    Why does my app look smaller on High Resolution Android phones?

  15. 15

    Android - In App Purchase Testing - Do I Need 2 Phones?

  16. 16

    Why do I get java.lang.ExceptionInInitializerError when I start the android app which uses tes two OCR engine

  17. 17

    OpenCV java.lang.UnsatisfiedLinkError

  18. 18

    eclipse: java.lang.UnsatisfiedLinkError

  19. 19

    JNI java.lang.UnsatisfiedLinkError

  20. 20

    Why do some Facebook User Ids randomly throw a graph exception?

  21. 21

    Why "This app has been built with an incorrect configuration" error occured in some phones?

  22. 22

    Android - Declaring an App is Only for phones

  23. 23

    JavaFX - Why does this throw a java.lang.NullPointerException?

  24. 24

    DownloadManager in Android (xamarin) throw Java.Lang.IllegalArgumentException

  25. 25

    Do android phones sync with Ubuntu?

  26. 26

    Do android phones sync with Ubuntu?

  27. 27

    How to fix java.lang.UnsatisfiedLinkError in java

  28. 28

    Opencv Android: java.lang.UnsatisfiedLinkError: dlopen failed: could not load library "libopencv_java.so"

  29. 29

    Opencv Android: java.lang.UnsatisfiedLinkError: dlopen failed: could not load library "libopencv_java.so"

HotTag

Archive