Подтвердить что ты не робот

Какой метод в конечном итоге вызывает JNI_OnLoad

Я пытался выяснить, как JNI_OnLoad вызывается внутри. В конце концов, я понял, что это ниже, но он не проливает свет на то, что часть кода на самом деле вызывает JNI_OnLoad в качестве внутреннего вызова функции. Помогите мне найти функцию связи, которая явно вызывает JNI_OnLoad. Я заметил, что System.loadLibrary вызывает 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.

Изменить. Моя трассировка файла на основе ответа @Code Painters ниже:

       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 не вызвана. Пожалуйста, поправьте меня, если я ошибаюсь.

4b9b3361

Ответ 1

Для Android вы должны изучить dalvik/vm/Native.c, который определяет интерфейс JNI.

Наиболее подходящей функцией является следующая:

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

Это место, где библиотека dlopen() -ed. И самая интересная его часть:

    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, ничего действительно захватывающее.

Я считаю, что он должен выглядеть примерно так же для других виртуальных машин - так что просто grep для dlopen() и dlsym() - ведь это просто обычная загрузка библиотеки и разрешение символа.

Изменить: Говоря о конкретном файле, который вы упомянули, Android.mk в том же каталоге компилирует и связывает этот файл с libandroid_servers разделяемой библиотекой. Grepping around для этого имени библиотеки показывает services/java/com/android/server/SystemServer.java.

Что важно:

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

Таким образом, загрузка библиотеки (и, следовательно, вызов JNI_OnLoad() в onload.cpp) выполняется в контексте запуска системной службы Android. Если вы хотите узнать больше о том, как/когда загружается системный сервис, я рекомендую эту презентацию.