Пример минимального запуска
Main.java
public class Main {
public native int square(int i);
public static void main(String[] args) {
System.loadLibrary("Main");
System.out.println(new Main().square(2));
}
}
Main.c
#include <jni.h>
#include "Main.h"
JNIEXPORT jint JNICALL Java_Main_square(
JNIEnv *env, jobject obj, jint i) {
return i * i;
}
Скомпилируйте и запустите:
sudo apt-get install build-essential openjdk-7-jdk
export JAVA_HOME='/usr/lib/jvm/java-7-openjdk-amd64'
javac Main.java
javah -jni Main
gcc -shared -fpic -o libMain.so -I${JAVA_HOME}/include \
-I${JAVA_HOME}/include/linux Main.c
java -Djava.library.path=. Main
Вывод:
4
Протестировано на Ubuntu 14.04 AMD64.Также работал с Oracle JDK 1.8.0_45.
Пример для GitHub , с которым вы можете играть.
Знак подчеркивания в именах пакетов / файлов Java должен быть экранирован с помощью _1
в имени функции C, как указано в: Вызов JNI-функций в имени пакета Android, содержащем подчеркивание
Интерпретация :
Позволяет:
- вызвать скомпилированную динамически загружаемую библиотеку (здесь написанную на C) с произвольным кодом сборки из Java
- и получить результаты обратно в Java
Это может бытьиспользуется для:
- более быстрого написания кода в критической секции с улучшенными инструкциями по сборке ЦП (не для переносимых ЦП)
- для прямых системных вызовов (не для переносимых ОС)
с компромиссом более низкой переносимости.
Вы также можете вызывать Java из C, но вы должны сначала создать JVM в C: Как вызывать функции Java из C ++?
Android NDK
Концепция в этом контексте точно такая же, за исключением того, что для ее настройки необходимо использовать шаблон Android.
Официальный репозиторий NDK содержит «канонические» примеры, такие как приложение hello-jni:
В вас unzip
an .apk
с NDK на Android O, вы можете увидеть предварительныескомпилированный .so
, который соответствует нативному коду в lib/arm64-v8a/libnative-lib.so
.
Подтверждение TODO: более того, file /data/app/com.android.appname-*/oat/arm64/base.odex
, говорит, что это разделяемая библиотека, которую я считаю предварительно скомпилированным .dex AOT, соответствующей Javaфайлы в ART, см. также: Что такое файлы ODEX в Android? Так что, может быть, Java на самом деле также запускается через интерфейс native
?
Пример в OpenJDK 8
Давайте найдем, где Object#clone
определено в jdk8u60-b27.
Мы заключим, что это реализовано с помощью вызова native
.
Сначала мынайти:
find . -name Object.java
, что приводит нас к jdk / src / share / classes / java / lang / Object.java # l212 :
protected native Object clone() throws CloneNotSupportedException;
Теперь самое сложное - найти, где находится клон среди всего косвенного.Вопрос, который мне помог, был:
find . -iname object.c
, который нашел бы файлы C или C ++, которые могли бы реализовать нативные методы Object.Это приводит нас к jdk / share / native / java / lang / Object.c # l47 :
static JNINativeMethod methods[] = {
...
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
(*env)->RegisterNatives(env, cls,
methods, sizeof(methods)/sizeof(methods[0]));
}
, что приводит нас к символу JVM_Clone
:
grep -R JVM_Clone
, что приводит нас к hotspot / src / share / vm / prims / jvm.cpp # l580 :
JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
JVMWrapper("JVM_Clone");
После расширения набора макросов мы переходим квывод, что это точка определения.