16

JNI_OnLoadが内部でどのように呼び出されるかを理解しようとしていました。私は最終的に以下のチュートリアルを理解しましたが、内部関数呼び出しとして実際にJNI_OnLoadを呼び出すコード部分については何もわかりません。JNI_OnLoadを明示的に呼び出すリンク関数を見つけるのを手伝ってください。System.loadLibraryがRuntimeを呼び出し、Runtimeが再びClassloaderを呼び出すことを確認しました。しかし、それでもネイティブリンクを見つけることができませんでした。

特にOnLoad.cpp(android / platform_frameworks_base / blob / master / services / jni / onload.cpp)にあるものに興味がありました。

JNI_OnLoad

jint JNI_OnLoad(JavaVM *vm, void *reserved);

The VM calls JNI_OnLoad when the native library is loaded (for example, through 
System.loadLibrary). JNI_OnLoad must return the JNI version needed by the native library.
In order to use any of the new JNI functions, a native library must export a JNI_OnLoad function that returns JNI_VERSION_1_2. If the native library does not export a JNI_OnLoad function, the VM assumes that the library only requires JNI version JNI_VERSION_1_1. If the VM does not recognize the version number returned by JNI_OnLoad, the native library cannot be loaded.

編集:@CodePaintersの応答に基づく私のファイルトレースは以下のとおりです。

       System.loadLibrary("android_servers");
            |
            |The call System.loadLibrary(name) is effectively equivalent
            |  to the call
            |
            V
        Runtime.getRuntime().loadLibrary(name)
            |
            |public static Runtime getRuntime() {
            |        return currentRuntime;}
            |
            | // Here, also,Classloader.loadlibrary is called, 
            | but this is over-ridden (?)
            | by the Native function of Runtime.java below
            V
        /dalvik/vm/native/java_lang_Runtime.cpp (The jni native
        implementation of Runtime.java):
        /*
         * static String nativeLoad(String filename, ClassLoader loader)
         *
         * Load the specified full path as a dynamic library filled with
         * JNI-compatible methods. Returns null on success, or a failure
         * message on failure.
         */
        static void Dalvik_java_lang_Runtime_nativeLoad{
        //
        success = dvmLoadNativeCode(fileName, classLoader, &reason);
        }

これで、Runtime.loadlibraryがDalvik_java_lang_Runtime_nativeLoadネイティブ関数でオーバーロードされ、 Classloader.loadlibraryが呼び出されないことがわかりました。私が間違っている場合は訂正してください。

4

1 に答える 1

24

Android の場合、JNI インターフェースを定義するdalvik/vm/Native.cを調べる必要があります。

最も関連性の高い関数は次のとおりです。

bool dvmLoadNativeCode(const char* pathName, Object* classLoader);

これは、ライブラリが編集されている場所dlopen()です。そして、その最も興味深い部分は次のとおりです。

    vonLoad = dlsym(handle, "JNI_OnLoad");
    if (vonLoad == NULL) {
        LOGD("No JNI_OnLoad found in %s %p\n", pathName, classLoader);
    } else {
        /*
         * Call JNI_OnLoad.  We have to override the current class
         * loader, which will always be "null" since the stuff at the
         * top of the stack is around Runtime.loadLibrary().  (See
         * the comments in the JNI FindClass function.)
         */
        OnLoadFunc func = vonLoad;
        Object* prevOverride = self->classLoaderOverride;

        self->classLoaderOverride = classLoader;
        oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
        LOGV("+++ calling JNI_OnLoad(%s)\n", pathName);
        version = (*func)(gDvm.vmList, NULL);
        dvmChangeStatus(self, oldStatus);
        self->classLoaderOverride = prevOverride;

ご覧のとおり、JNI_OnLoadは単純に解決されdlsym()、返されたポインターを使用して呼び出されます。このコード部分の残りの部分は、 から返された値をチェックしていますが、特にJNI_OnLoad興味深いことはありません。

他の VM でもほぼ同じように見えるはずです。したがって、dlopen()and をgrep するだけdlsym()です。結局のところ、単純な共有ライブラリの読み込みとシンボルの解決にすぎません。

編集:あなたが言及した正確なファイルについて言えばAndroid.mk、同じディレクトリで、このファイルをコンパイルしてlibandroid_servers共有ライブラリにリンクします。このライブラリ名を探し回ると、services/java/com/android/server/SystemServer.javaが表示されます。

関連するもの:

public static void main(String[] args) {
    // ...
    System.loadLibrary("android_servers");
    // ...
}

そのため、ライブラリのロード (およびJNI_OnLoad()inの呼び出しonload.cpp) は、Android のシステム サービスの起動のコンテキストで実行されます。システム サービスがいつどのように読み込まれるかについて詳しく知りたい場合は、このプレゼンテーションをお勧めします。

于 2013-02-27T08:36:58.587 に答える