12

アプリケーションに 2 つのネイティブ ライブラリ (.so) を統合しました。ライブラリは正常にコンパイルされ、アプリケーションにもロードできます。ライブラリのネイティブ メソッドを初めて呼び出すときは正常に動作しますが、アクティビティで同じメソッドを再度呼び出すと、アプリケーションがシャットダウンします。

私が直面している問題は、ここで言及されているものとまったく同じです:
http://grokbase.com/t/gg/android-ndk/1226m68ydm/app-exit-on-second-native-call

有効な解決策は、別のアクティビティでネイティブ メソッドを呼び出し、System.exit(0) を介して強制的にシャットダウンすることです。記事に従って、操作が成功した後、呼び出されたメソッドのポインターを NULL に設定しようとしましたが、これも役に立ちませんでした。また、System.loadLibrary() によってロードされたライブラリをアンロードすることはできません。

新しいアクティビティを作成せずにネイティブ メソッドを複数回呼び出したい。この問題を解決する方法はありますか?

(私は最終的に解決策を見つけました...ここにあります)

さて、私はついにこの問題を解決する方法を見つけました。解決策は実際には非常に簡単です。別の独立したネイティブ ライブラリ (ユーティリティ ライブラリ) を構築して、他のライブラリをロードおよびアンロードします。必要なことは、ユーティリティのネイティブ メソッドで dlopen() と dlclose() を使用することです。以前のように、System.loadLibrary() を介してユーティリティ ライブラリをロードできます。

したがって、ユーティリティ ライブラリのネイティブ メソッドでは、次のことを行う必要があります。

// これは、dlopen() およびdlclose #include <dlfcn.h>() 関数を呼び出すために必要です。

ハンドラーと関数のプロトタイプを提供します。

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

これが同じ問題に直面している他の人に役立つことを願っています。

4

2 に答える 2

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 ファイルは、丁寧に言うと少し不安定です。1 つの Android.mk ファイルで 2 つの別個のライブラリをビルドしているため、これは他の NDK の make ファイルよりも少し複雑になる可能性があるため、奇妙なエラーが発生した場合は、プロジェクトを分解する前に検索を行ってください。例: https://stackoverflow.com/a/6243727/334402
于 2015-02-26T20:32:16.997 に答える