Вызов собственного метода дважды из сторонней библиотеки в Activity приводит к закрытию приложения Android - программирование
Подтвердить что ты не робот

Вызов собственного метода дважды из сторонней библиотеки в Activity приводит к закрытию приложения Android

Я включил в свое приложение две родные библиотеки (.so). Библиотеки компилируются отлично, и я могу загрузить их и в приложение. В первый раз, когда я вызываю собственный метод библиотеки, он отлично работает, но если я снова вызову тот же метод в Activity, приложение отключится.

Проблема, с которой я столкнулась, точно такая же, как упоминалось здесь:
http://grokbase.com/t/gg/android-ndk/1226m68ydm/app-exit-on-second-native-call

Решением, которое работает, является вызов встроенного метода в другое действие и принудительное закрытие его с помощью System.exit(0). После статьи я попытался установить указатели на NULL вызываемого метода после успешной операции, но это тоже не помогло мне. Также невозможно выгрузить библиотеку после ее загрузки System.loadLibrary().

Я хочу называть собственные методы более одного раза без создания нового Activity. Любые идеи, как решить эту проблему?

(Я НАКОНЕЦ РЕШЕНИЯ... ЗДЕСЬ ЭТО)

Хорошо, я наконец нашел способ решить эту проблему. Решение на самом деле довольно просто. Создайте еще одну независимую собственную библиотеку (утилиту) для загрузки и выгрузки других библиотек. Нам нужно использовать dlopen() и dlclose() в собственном методе утилиты. Мы можем загрузить библиотеку утилиты, как раньше, через System.loadLibrary().

Итак, в собственном методе библиотеки утилиты нам нужно:

Используйте #include <dlfcn.h>//это необходимо для вызова функций dlopen() и dlclose().

Предоставить прототип обработчика и функции:

void *handle;
typedef int (*func)(int); // define function prototype
func myFunctionName; // some name for the function

Откройте библиотеку через dlopen():

handle = dlopen("/data/data/my.package.com/lib/somelibrary.so", RTLD_LAZY);

Получить и вызвать функцию библиотеки:

myFunctionName = (func)dlsym(handle, "actualFunctionNameInLibrary");
myFunctionName(1); // passing parameters if needed in the call

Теперь, когда вызов выполнен. Закройте его с помощью dlclose():

dlclose(handle);

Надеемся, что это поможет другим, сталкивающимся с одной и той же проблемой.

4b9b3361

Ответ 1

Итак... мое решение запускало сервис, который запускает код разделяемой библиотеки, эта служба имеет другое имя процесса (вы можете установить его в манифесте Android), так как это другой процесс, который вы можете его убить (используя Process.killProcess(Process.myPid()), когда он заканчивается, без какого-либо влияния на ваше приложение.

Работал очень хорошо для меня, надеюсь, что это поможет кому-то еще.

Ответ 2

Поскольку это самый популярный продукт для этой проблемы, и поскольку сама проблема все еще существует, кажется, что подход, который ZakiMak поделил с нами, по-прежнему остается самым популярным решением.

Для других, кто может захотеть его реализовать, и хотел бы получить более подробную информацию о последних выпусках Android, вот некоторые заметки, которые я сделал, когда я наткнулся на это:

  • Во-первых, есть решение, которое реализует этот подход на GitHub. Я не пробовал это лично, но я использовал его как ссылку. Очень полезно посмотреть, как структурирован файл Android.mk и как открывается библиотека, а также методы. Ссылка находится здесь: https://github.com/jhotovy/android-ffmpeg
  • Путь к папке с родной библиотекой изменяется по версиям Android, и он также меняется каждый раз при запуске приложения (хотя это может быть только в режиме отладки). В любом случае лучше всего пройти путь от вызывающего Java-метода, если это возможно. Например:

В классе оболочки Java:

import android.content.Context;
import android.util.Log;

public class FfmpegJNIWrapper {

    //This class provides a Java wrapper around the exposed JNI ffmpeg functions.

    static {
        //Load the 'first' or 'outer' JNI library so this activity can use it
        System.loadLibrary("ffmpeg_wraper_multi_invoke_jni");
    }

    public static int call_ffmpegWrapper(Context appContext, String[] ffmpegArgs) {
        //Get the native libary path
        String nativeLibPath = appContext.getApplicationInfo().nativeLibraryDir;

        //Call the method in the first or 'outer' library, passing it the
        //native library past as well as the original args
        return ffmpegWrapper(nativeLibPath, ffmpegArgs);
    }


    // Native methods for ffmpeg functions
    public static native int ffmpegWrapper(String nativeLibPath, String[] argv);

}

В "первой" или "внешней" исходной библиотеке:

JNIEXPORT jint JNICALL Java_com_yourpackage_androidffmpegwrapper_FfmpegJNIWrapper_ffmpegWrapper(JNIEnv *pEnv, jobject pObj, jstring nativeLibPath, jobjectArray javaArgv) {

    //Get the second or 'inner' native library path
    char* nativePathPassedIn = (char *)(*pEnv)->GetStringUTFChars(pEnv, nativeLibPath, NULL);
    char ourNativeLibraryPath[256];
    snprintf(ourNativeLibraryPath, sizeof (ourNativeLibraryPath), "%s%s", nativePathPassedIn, "/libffmpeg_wraper_jni.so"); //the name of your ffmpeg library

    //Open the so library
    void *handle;
    typedef int (*func)(JNIEnv*, jobject, jobjectArray);
    handle = dlopen(ourNativeLibraryPath, RTLD_LAZY);
    if (handle == NULL) {
        __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "could not open library: %s", dlerror());
        printf("Could not dlopen(\"libbar.so\"): %s\n", dlerror());
        return(-1);
    }

    //Call the ffmpeg wrapper functon in the second or 'inner' library
    func reenterable_ffmpegWrapperFunction;
    reenterable_ffmpegWrapperFunction = (func)dlsym(handle, "Java_com_yourpackage_androidffmpegwrapper_FfmpegJNIWrapper_ffmpegWrapper");
    reenterable_ffmpegWrapperFunction(pEnv, pObj, javaArgv); //the original arguments

    //Close the library
    dlclose(handle);

    // return
    return(1);
}
  • Файл Android.mk немного "flaky", чтобы выразить это вежливо. Поскольку вы создаете две отдельные библиотеки в одном файле Android.mk, это может быть немного сложнее, чем другие файлы NDK, поэтому, если вы получаете некоторые странные ошибки, выполните некоторые поиски, прежде чем вы начнете разделить свой проект. Например: fooobar.com/info/121283/...