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

12

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

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

Решение, которое работает, заключается в том, чтобы вызвать собственный метод в другом Activity и принудительно завершить его через 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);

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

Вам нужно будет знать о NDK.link - этот урок покажет вам, как сделать все это шаг за шагом. Вкратце, как только ваша среда NDK будет готова: 1. Вам нужно написать файл C. 2. Напишите свой файл Android.mk для создания .so - разделяемой библиотеки. 3. Создайте .so файл, используя ndk. 4. Напишите класс Java, в котором вы будете демонстрировать нативные методы, а также загрузите библиотеку через System.loadLibrary в статическом блоке. ZakiMak
где ты делаешь dlclose (ручку)? Я имею в виду в коде активности или JNI? Arif Nadeem
Это в коде JNI. Это функция, доступная через заголовочный файл dlfcn.h. ZakiMak
Хорошо, понял, я вижу, что вы загружаете и выгружаете другие библиотеки в этом классе C. Но как мне связать его с моим Java-кодом? Arif Nadeem
Интересно, как вы заставили dlclose работать, в ndk-документации ясно сказано, что «статические деструкторы никогда не вызываются в данный момент, ни при выходе из программы, ни при вызове dlclose ()». ПОЖАЛУЙСТА, ОБРАТИТЕСЬ К папке NDK (где ndk разархивирован в вашей системе и обратитесь к SYSTEM-ISSUES.html) Arif Nadeem

Ваш Ответ

2   ответа
5

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

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

Error: User Rate Limit Exceeded
2

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

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

Firstly, there is a solution which implements this approach on GitHub now. I have not tried it personally, but I have used it as a reference. It is very useful to see how the Android.mk file is structured and how the library is opened and methods called. Link is here: https://github.com/jhotovy/android-ffmpeg The path to the native library folder changes over Android releases and it also appears to change every time you run the app (although this may be just in debug mode). Either way, it is best to pass the path in from the calling Java method if possible. For example:

В классе упаковки 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);
}
The Android.mk file is a little 'flaky' to put it politely. Because you are building two separate libraries in one Android.mk file, this may be a little more complex that other NDK make files so if you get some strange errors do some searching before you start taking your project apart. For example: https://stackoverflow.com/a/6243727/334402

Похожие вопросы