LD_LIBRARY_PATH忽略了在Android有时 [英] LD_LIBRARY_PATH ignored on Android sometimes

查看:2140
本文介绍了LD_LIBRARY_PATH忽略了在Android有时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Android应用程序,它会生成与分发我的包库dinamically链接许多本地的可执行文件。 要启动这些二进制文件,我用的是PATH环境变量来使他们认识加载从库的地方,但在某些设备上,这并不在所有的工作中,LD_LIBRARY_PATH被正确更新,但二进制文件未找到库反正。 这不是我可以重现,因为在我的两个设备(Galaxy Nexus的&放大器;的Nexus 7与股票的ROM)。它只是正常工作

i have an android app which spawns many native executables dinamically linked with libraries i distribute with the package. To launch those binaries, i use the LD_LIBRARY_PATH environment variable to make them aware of the place to load the libraries from, but on some devices this doesn't work at all, the LD_LIBRARY_PATH is correctly updated but the binary fails to find the library anyway. This is not something i can reproduce because on my two devices ( Galaxy Nexus & Nexus 7 with stock roms ) it just works fine.

我尝试过很多办法,比如我产卵:

I tried many ways, for instance i spawn:

LD_LIBRARY_PATH=/my/package/custom/libs:$LD_LIBRARY_PATH && cd /binary/directory && ./binary

    String[] envp = { "LD_LIBRARY_PATH=" + libPath + ":$LD_LIBRARY_PATH" };

    Process process = Runtime.getRuntime().exec( "su", envp );

    writer = new DataOutputStream( process.getOutputStream() );
    reader = new BufferedReader( new InputStreamReader( process.getInputStream() ) );

    writer.writeBytes( "export LD_LIBRARY_PATH=" + libPath + ":$LD_LIBRARY_PATH\n" );
    writer.flush();

不过,在这些设备上似乎没有什么工作...所以我开始认为这是一个内核相关的问题,有些内核(像我)使用LD_LIBRARY_PATH,其它内核没有(简单地忽略它,或他们用这一点被设置在应用程序启动的LD_LIBRARY_PATH,因此没有办法在运行时改变它)。

But on those devices nothing seemed to work ... so i'm starting to think that this is a kernel related issue, some kernels ( like mine ) use the LD_LIBRARY_PATH, other kernels don't ( simply ignore it, or they're using just the LD_LIBRARY_PATH that was set on application startup, therefore there's no way to change it at runtime ).

我还试图用System.load,但它没有工作,可能是因为这些库不是JNI ......是不是我开始考虑使用静态链接的二进制文件之前,可以尝试?

I also tried to use System.load but it didn't work, probably because those libs are not JNI ... is there something i could try before starting to think about using statically linked binaries ?

推荐答案

下面是一个简单的包装我写的:

Here is a simple wrapper I wrote about:

#include <android/log.h>
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>

typedef int (*main_t)(int argc, char** argv);

static int help(const char* argv0)
{
    printf("%s: simple wrapper to work around LD_LIBRARY_PATH\n\n", argv0);
    printf("Args: executable, list all the libraries you need to load in dependency order, executable again, optional parameters\n");
    printf("example: %s /data/local/ttte /data/data/app/com.testwrapper/lib/ttt.so /data/local/ttte 12345\n", argv0);
    printf("Note: the executable should be built with CFLAGS=\"-fPIC -pie\", LDFLAGS=\"-rdynamic\"\n");

    return -1;
}

int main(int argc, char** argv)
{
    int rc, nlibs;
    void *dl_handle;

    if (argc < 2)
    {
        return help(argv[0]);
    }

    __android_log_print(ANDROID_LOG_DEBUG, "wrapper", "running '%s'", argv[1]);

    for (nlibs = 2; ; nlibs++)
    {
        if (nlibs >= argc)
        {
            return help(argv[0]);
        }

        __android_log_print(ANDROID_LOG_DEBUG, "wrapper", "loading '%s'", argv[nlibs]);
        dl_handle = dlopen(argv[nlibs], 0); // do not keep the handle, except for the last
        __android_log_print(ANDROID_LOG_DEBUG, "wrapper", "loaded '%s' -> %p", argv[nlibs], dl_handle);
        if (strcmp(argv[1], argv[nlibs]) == 0)
        {
            break;
        }
    }

    main_t pmain = (main_t)dlsym(dl_handle, "main");
    __android_log_print(ANDROID_LOG_DEBUG, "wrapper", "found '%s' -> %p", "main", pmain);
    rc = pmain(argc - nlibs, argv + nlibs);

//   we are exiting the process anyway, don't need to clean the handles actually

//   __android_log_print(3, "wrapper", "closing '%s'", argv[1]);
//   dlclose(dl_handle);

    return 0;
}

要保持它的可读性,我把大部分的错误处理的特殊情况下,非必要的清理和处理。

To keep it readable, I drop most of error handling, unessential cleanup, and handling of special cases.

Android.mk 这个可执行文件:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := wrapper
LOCAL_SRC_FILES := wrapper/main.c
LOCAL_LDLIBS    := -llog

include $(BUILD_EXECUTABLE)

请注意,你必须照顾部署:包装此包装进入APK,提取到一些本地路径(永不USB存储或 / SD卡!),将其标记为可执行文件(搭配chmod 777 )。

Note that you must take care of deployment: packaging this wrapper into the APK, extraction to some local path (never to USB storage or to /sdcard!), marking it as executable (chmod 777).

这些都是当你建立你通过包装运行可执行文件,你必须提供额外的参数。如果你使用 NDK建造来构建它们,它看起来如下:

These are the additional parameters you must supply when you build the executables you run through the wrapper. If you use ndk-build to build them, it looks as follows:

LOCAL_C_FLAGS   += -fPIC -pie
LOCAL_LDFLAGS   += -rdynamic 

请注意,你并不需要搭配chmod 对这些可执行程序了。另一个窍门:你可以建立的二次的可执行文件到共享库,同样的包装将继续努力!这样可以节省部署这些二进制文件的麻烦。 NDK和Android版本将提供他们安全地通过库/ armeabi的APK中,自动将您的应用程序的lib目录。

Note that you don't need to chmod for these executables anymore. Another trick: you can build the secondary executables into shared libraries, and the same wrapper will continue to work! This saves the trouble of deployment of these binaries. NDK and Android build will deliver them safely through libs/armeabi of the APK to your app's lib directory automagically.

更新

似乎有一个更简单的解决方案,使用 的ProcessBuilder 与修改后的环境。 http://stackoverflow.com/a/8962189/192373

There seems to be a much easier solution, using the ProcessBuilder with modified environment: http://stackoverflow.com/a/8962189/192373.

这篇关于LD_LIBRARY_PATH忽略了在Android有时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆