2012-05-18 14 views
12

Mam zintegrowane dwie biblioteki natywne (.so) w mojej aplikacji. Biblioteki kompilują się dobrze i mogę je załadować również w mojej aplikacji. Za pierwszym razem, gdy wywoływam natywną metodę biblioteki, działa ona dobrze, ale jeśli ponownie wywołaję tę samą metodę w działaniu, aplikacja wyłączy się.Wywołanie natywnej metody dwukrotnie w bibliotece innej firmy w działaniu powoduje zamknięcie aplikacji Android.

Problem jestem stoi jest dokładnie taka sama, jak wspomniano tutaj:
http://grokbase.com/t/gg/android-ndk/1226m68ydm/app-exit-on-second-native-call

Rozwiązanie to działa jest do wywołania metody natywnej w innej działalności i mocno go zamknąć poprzez System.exit (0) . Po artykule próbowałem ustawić wskaźniki na NULL wywołanej metody po udanej operacji, ale to też nie pomogło mi. Nie można również wyładować biblioteki po załadowaniu jej przez System.loadLibrary().

Chcę wywoływać metody natywne więcej niż raz bez tworzenia nowej aktywności. Wszelkie pomysły, jak rozwiązać ten problem?

(I w końcu znalazłem rozwiązanie ... to jest tutaj)

Dobra, w końcu znalazł sposób na rozwiązanie tego problemu. Rozwiązanie jest naprawdę proste. Zbuduj inną niezależną bibliotekę natywną (bibliotekę narzędziową), aby załadować i wyładować inne biblioteki. Musimy użyć dlopen() i dlclose() w natywnej metodzie narzędzia. Możemy wczytać bibliotekę narzędzi jak wcześniej przez System.loadLibrary().

Więc w natywnej metody biblioteki użytkowego, co musimy zrobić, to: funkcje

Zastosowanie #include <dlfcn.h> // to jest wymagane, aby zadzwonić dlopen() i dlclose().

Zapewnienie przewodnika i function prototype:

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

otworzyć bibliotekę przez dlopen():

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

Uzyskaj i wywołać funkcję biblioteki:

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

Teraz, gdy połączenie jest zakończone. Zamknij go przez dlclose():

dlclose(handle); 

Mam nadzieję, że pomoże to innym osobom zmierzyć się z tym samym problemem.

+0

gdzie robisz dlclose (uchwyt)? Mam na myśli kod Aktywności lub JNI? –

+0

Jest to kod JNI. Jest to funkcja dostępna przez plik nagłówkowy dlfcn.h. – ZakiMak

+0

OK, widzę, że ładujesz i zwalniasz inne biblioteki w tej klasie c. Ale w jaki sposób powinienem połączyć go z moim kodem Java? –

Odpowiedz

5

Więc ... moim rozwiązaniem było uruchomienie usługi, która uruchamia kod biblioteki współużytkowanej, ta usługa ma inną nazwę procesu (można ją ustawić w Manifekcie Androida), ponieważ jest to inny proces, który można zabić (Korzystanie Process.killProcess (Process.myPid()), kiedy to kończy bieg, bez wpływu na stosowanie w jakikolwiek sposób.

bardzo dobrze dla mnie, mam nadzieję, że ktoś pomaga.

+0

Myślę, że to jest czyste rozwiązanie. To trudniejsze, ale lepsze. – ezefire

2

Ponieważ jest to top hit w tym przypadku, a sama kwestia nadal istnieje, wydaje się, że podejście, które dzieli z nami ZakiMak, jest nadal najbardziej popularnym rozwiązaniem.

dla innych, którzy mogą chcieć go wdrożyć i chcieliby trochę więcej szczegółów o najnowszych Android wydaniach, oto kilka uwag zrobiłem jak Natknąłem się przez ten:

  • Po pierwsze, nie jest to rozwiązanie, które wdraża to podejście teraz na GitHub. Nie próbowałem tego osobiście, ale użyłem go jako punktu odniesienia. Bardzo przydatne jest sprawdzenie struktury pliku Android.mk i sposobu otwarcia biblioteki oraz wywoływania metod. Link jest tutaj: https://github.com/jhotovy/android-ffmpeg
  • Ścieżka do folderu biblioteki macierzystej zmienia się w stosunku do wersji Androida i wydaje się, że zmienia się przy każdym uruchomieniu aplikacji (chociaż może to być tylko tryb debugowania). Tak czy inaczej najlepiej jest przekazać ścieżkę z wywołującej metody Java, jeśli to możliwe. Na przykład:

W klasie owijania 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); 

} 

W 'pierwszej' lub 'zewnętrznej' rodzimej biblioteki:

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); 
} 
  • Plik Android.mk jest trochę "niestabilne", żeby to powiedzieć grzecznie. Ponieważ budujesz dwie oddzielne biblioteki w jednym pliku Android.mk, może to być trochę bardziej skomplikowane niż inne pliki NDK, więc jeśli dostaniesz jakieś dziwne błędy, przeprowadź wyszukiwanie, zanim zaczniesz rozbierać projekt. Na przykład: https://stackoverflow.com/a/6243727/334402
Powiązane problemy