Я включил в свое приложение две родные библиотеки (.so). Библиотеки компилируются отлично, и я могу загрузить их и в приложение. В первый раз, когда я вызываю собственный метод библиотеки, он отлично работает, но если я снова вызову тот же метод в Activity, приложение отключится.
Проблема, с которой я столкнулась, точно такая же, как упоминалось здесь:
http://grokbase.com/t/gg/android-ndk/1226m68ydm/app-exit-on-second-native-call
Решение, которое работает, – это вызвать собственный метод в другом действии и принудительно закрыть его с помощью System.exit (0). После статьи я попытался установить указатели на NULL вызываемого метода после успешной операции, но это тоже не помогло мне. Также невозможно выгрузить библиотеку после ее загрузки System.loadLibrary ().
Я хочу вызывать собственные методы более одного раза, не создавая новое действие. Есть идеи, как решить эту проблему?
(Я НАКОНЕЦ НАДЕЕТСЯ РЕШЕНИЕ … ЗДЕСЬ ЭТО)
Хорошо, я наконец нашел способ решить эту проблему. Решение на самом деле довольно простое. Создайте другую независимую библиотеку (утилиту) для загрузки и выгрузки других библиотек. Нам нужно использовать 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);
Надеюсь, это поможет другим, столкнувшимся с одной и той же проблемой.
Итак … мое решение запускало сервис, который запускает код общей библиотеки, у этой службы есть другое имя процесса (вы можете установить его в манифесте Android), так как это другой процесс, который вы можете его убить (используя Process.killProcess (Process.myPid ()) при завершении работы без какого-либо влияния на ваше приложение.
Работал очень хорошо для меня, надеюсь, что это помогает кому-то другому.
Поскольку это самый популярный продукт для этой проблемы, и поскольку сама проблема по-прежнему существует, кажется, что подход, который ZakiMak поделил с нами, по-прежнему остается самым популярным решением.
Для других, которые могут захотеть реализовать его и хотели бы получить более подробную информацию о последних выпусках Android, вот некоторые заметки, которые я сделал, когда я наткнулся на это:
В классе оболочки 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); }