LD_LIBRARY_PATH ignored on Android sometimes

后端 未结 4 2043
有刺的猬
有刺的猬 2021-02-06 15:59

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 e

4条回答
  •  我在风中等你
    2021-02-06 16:15

    Here is a simple wrapper I wrote about:

    #include 
    #include 
    #include 
    #include 
    
    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 for this executable:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE    := wrapper
    LOCAL_SRC_FILES := wrapper/main.c
    LOCAL_LDLIBS    := -llog
    
    include $(BUILD_EXECUTABLE)
    

    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).

    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 
    

    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.

    Update

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

提交回复
热议问题