CCJ
CCJ

Reputation: 1719

Android native libs disappearing once app is installed

After switching to Android Studio, I began seeing the dreaded

java.lang.UnsatisfiedLinkError: dlopen failed: library
'/data/app-lib/com.myapp.test-1/libmylib.so' not found 

error. When I unpack the apk, I can see libmylib.so along with all the other native libraries (libmyotherlib.so and libtest.so) under the lib/armeabi folder, so packaging shouldn't be the problem... I decided to root my test device and check out the actual contents of my app's folder under /data/app-lib, where its native libraries should be after install -- I found that one of my app's native libraries (libmylib.so) was missing after the app is installed on a device. libmylib.so and libmyotherlib.so are pre-built .so files placed in src/main/jniLibs, and libtest.so is compiled from test.c in src/main/jni.

This only started after I switched to Android Studio; I've verified that apks built from the same code in Eclipse ADT have all the required libraries present under /data/app-lib/com.myapp.test-1 after installation.

Relevant build.gradle for Android Studio build:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "com.myapp.test"
        minSdkVersion 17
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"

        ndk{

            moduleName "test"//testing ndk integration
        }

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
        }
    }

}

repositories {
    // You can also use jcenter if you prefer
    mavenCentral()
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'

    //android support libs etc.
    compile 'com.android.support:appcompat-v7:23.1.0'
    compile 'com.android.support:support-v13:23.1.0'

}

Relevant gradle.properties file

android.useDeprecatedNdk=true

Under src/main/jni I have only test.c

#include <jni.h>

int main(){

    return 0;
}

and under src/main/jniLibs/armeabi I have

libmylib.so
libmyotherlib.so

Relevant Android.mk for Eclipse ADT build:

include $(CLEAR_VARS)
LOCAL_MODULE    := test
LOCAL_SRC_FILES += test.c
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := myotherlib
LOCAL_SRC_FILES :=  $(TARGET_ARCH_ABI)/libmyotherlib.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := mylib
LOCAL_SRC_FILES :=  $(TARGET_ARCH_ABI)/libmylib.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

Relevant /data/app-lib contents after installing app built by Android Studio:

root@SOLONE SL-K40:/ # ls /data/app-lib/com.myapp.test-1               
libmyotherlib.so
libtest.so

Relevant /data/app-lib contents after installing app built by Eclipse ADT:

root@SOLONE SL-K40:/ # ls /data/app-lib/com.myapp.test-1               
libmylib.so
libmyotherlib.so
libtest.so

I accidentally found that by adding

sourceSets {
        main {
            jni.srcDirs = []
 }
}

to my build.gradle I can get libmylib.so to show up again after installation, but this precludes having any NDK source code in my project.

First Question: Any idea what might be going on here? Could it be that mylib was actually compiled for an abi other than armeabi and Android is discarding it because its actual abi doesn't match the folder it came in inside the apk (I don't have the source code for mylib)? My problem sounds similar to one discussed here, but that person seemed to see only one shared library in the final installed app; I'm seeing all but one of my shared libraries.

Second Question: What is the current correct way to include pre-built .so files in an Android Studio build? Clues around the 'net seem to vary wildly by Android Studio version (I'm using Android Studio 1.5, Gradle version 2.4, Android plugin version 1.3.0) Is there still a need to redirect the jniLibs.srcDir variable to src/main/libs?

Upvotes: 1

Views: 3180

Answers (1)

Alex Cohn
Alex Cohn

Reputation: 57163

Yes, the best approach is to define jniLibs.srcDir such that all prebuilt libraries can be copied from there.

Yes, the ABI is the most probable source of the problem. If the prebuilt library was built for armeabi but the device (as the vast majority of devices today) supports armeabi-v7a, then the installer will happily copy the …v7a versions of your not-prebuilt libraries to /data/app-lib/com.myapp.test-1, and the loader will later complain that libmylib.so is missing.

You should instruct Android Studio to only build one ABI. If you did not do something special in Eclipse build, then this is most likely armeabi.

The way to instruct AS depends on the version of gradle plugin.

For 'com.android.tools.build:gradle:1.5.0' plugin, I use something like

android {
    defaultConfig.ndk {
        …
        abiFilter 'armeabi'
    }

    splits {
        abi {
            enable true
            reset()
            include 'armeabi'
        }
    }
}

For …gradle-experimental:0.2.0, I use

model {
    android.ndk {
        …
        abiFilters += 'armeabi'
    }
}

I didn't have a need to enable splits on the experimental plugin, so I will not mislead you about the syntax changes there.

Upvotes: 2

Related Questions