18

Shared libraries .so files are placed in lib/armeabi in an apk file.

I have read after installation the libs gets extracted to /data/data/application_package/lib

How can I get the exact path to this directory in my application at run time? Is this directory readable by the application? Or is only executeable access allowed? If it is readable - Is this still true for copy protected applications?

Zardos
  • 183
  • 1
  • 1
  • 5

6 Answers6

44

Added in API level 9

getContext().getApplicationInfo().nativeLibraryDir;

Crossle Song
  • 10,104
  • 2
  • 29
  • 38
14

You can get the exact path with:

String libraryPath = getContext().getApplicationInfo().dataDir + "/lib";

The directory and its files are readable by the application.

The unix permissions are set to rwxr-x--x. So applications with the same group can read the files.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Ralph Löwe
  • 415
  • 4
  • 10
4

And if you're using a native activity and C++:

void ANativeActivity_onCreate(ANativeActivity* app, void*, size_t) {
    const jclass contextClass = app->env->GetObjectClass(app->clazz);
    const jmethodID getApplicationContextMethod =
        app->env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;");
    const jobject contextObject =
        app->env->CallObjectMethod(app->clazz, getApplicationContextMethod);
    const jmethodID getApplicationInfoMethod = app->env->GetMethodID(
        contextClass, "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;");
    const jobject applicationInfoObject =
        app->env->CallObjectMethod(contextObject, getApplicationInfoMethod);
    const jfieldID nativeLibraryDirField = app->env->GetFieldID(
        app->env->GetObjectClass(applicationInfoObject), "nativeLibraryDir", "Ljava/lang/String;");
    const jobject nativeLibraryDirObject =
        app->env->GetObjectField(applicationInfoObject, nativeLibraryDirField);
    const jmethodID getBytesMethod = app->env->GetMethodID(
        app->env->GetObjectClass(nativeLibraryDirObject), "getBytes", "(Ljava/lang/String;)[B");
    const auto bytesObject = static_cast<jbyteArray>(app->env->CallObjectMethod(
        nativeLibraryDirObject, getBytesMethod, app->env->NewStringUTF("UTF-8")));
    const size_t length = app->env->GetArrayLength(bytesObject);
    const jbyte* const bytes = app->env->GetByteArrayElements(bytesObject, nullptr);
    const std::string libDir(reinterpret_cast<const char*>(bytes), length);
jhasse
  • 2,379
  • 1
  • 30
  • 40
2
String libpath = getApplicationInfo().nativeLibraryDir;

Class used: import android.content.pm.ApplicationInfo;

PYK
  • 3,674
  • 29
  • 17
0
String libraryPath = context.getFilesDir().getParentFile().getPath() + "/lib";

For better compatibility, use the following function:

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public static String getLibraryDirectory(Context context) {
    int sdk_level = android.os.Build.VERSION.SDK_INT;

    if (sdk_level >= Build.VERSION_CODES.GINGERBREAD) {
        return context.getApplicationInfo().nativeLibraryDir;
    } 
    else if (sdk_level >= Build.VERSION_CODES.DONUT) {
        return context.getApplicationInfo().dataDir + "/lib";
    }

    return "/data/data/" + context.getPackageName() + "/lib";
}
Verdigrass
  • 1,203
  • 12
  • 14
  • Are you certain you can load native libraries from this location? – lhunath Jul 07 '15 at 16:02
  • Yes, I have checked it in my app. What is the problem? – Verdigrass Jul 21 '15 at 09:25
  • Does not work on HTC M9+ running 5.1.1. The lib link is there, but does not point to the correct directory. Crossie's solution does ( getContext().getApplicationInfo().nativeLibraryDir; ) – kshepherd Feb 04 '16 at 14:58
  • Thanks for you comment. And, if you have the lib link you can also easily access the library, can't that meet you demand? @kshepherd – Verdigrass Feb 18 '16 at 11:33
0

Maybe a device support different CPU_ABIs, so it's better to get nativeRootLibraryDir which contain all sub lib directories:

public static String getNativeLibraryDirectory(Context context) {
    int sdk_level = android.os.Build.VERSION.SDK_INT;

    if (sdk_level >= Build.VERSION_CODES.GINGERBREAD) {
        try {
            String secondary = (String) ApplicationInfo.class.getField("nativeLibraryRootDir").get(context.getApplicationInfo());
            return secondary;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    else if (sdk_level >= Build.VERSION_CODES.DONUT) {
        return context.getApplicationInfo().dataDir + "/lib";
    }

    return "/data/data/" + context.getPackageName() + "/lib";
}
Ken
  • 1,303
  • 13
  • 15