Java Native Interface Eine Einführung anhand eines praktischen Beispiels Fachseminar WS 09 Cornelius Zühl Jeder verwendet JNI 1 (der Java Programme nutzt) Initialisieren der VM Windows Unix Jeder verwendet JNI 2 (der Java Programme schreibt) Methoden des Java-Frameworks, z.B. aus „System“ verwenden JNI Das Schlüsselwort „native“, aber warum kann ICH es verwenden? 1 Ein „echter“ und ein „scheinbarer“ Grund Grund 1 Steigerung der Geschwindigkeit Einige Aufgaben der Java-Release werden nicht in derselben Weise wie optimierte C-Programme ausgeführt Konkret Kritische Stellen (z.B. innere Schleifen) auslagern und in einer Java-Shell wrappen um so den „Trick“ vor dem Benutzer zu verbergen Das Schlüsselwort „native“, aber warum kann ICH es verwenden? 2 Ein „echter“ und ein „scheinbarer“ Grund Grund 2 Ermöglicht Zugang zu speziellen Fähigkeiten des Rechners / Betriebssystem (BS) Anschluss an neue Peripheriegeräte / Steckkarten Zugriff auf verschiedene Netztypen Verwendung eines eindeutigen Merkmals des BS Konkret Erfassen von Echtzeitton über Mikrofon Das Schlüsselwort „native“, aber warum kann ICH es verwenden? 3 Ein „echter“ und ein „scheinbarer“ Grund Grund – Performancesteigerung Grund – Spezielle Eigenheiten des BS verwenden Performancesteigerung als scheinbarer Grund Wer echtzeitkritisch will, wird Alternativen verwenden Viele zeitkritische Probleme ohnehin schon in der JVM nativ gelöst Besser Energie auf gutes Design von Klassen und Methoden verwenden Abstrakt und wieder verwendbar Geschwindigkeit als letzter Schritt Nativ spricht Java Erzeugen, untersuchen und ändern von Java Objekten (einschließlich Arrays und Strings) Java Methoden aufrufen Exceptions werfen und fangen Klassen und Klasseninformationen laden Typprüfung zur Laufzeit Auch erzeugen einer VM über Invocation API möglich Ein Blick hinter die Kulissen 1 Aufruf nativ JVM über Interface Pointer IP = Zeiger auf Zeiger auf Array von Funktionszeigern Pro (Java)Aufruf-Thread ist IP garantiert gleich Funktionszeiger an Vordefinierte Stellen im Array, genannt JNI Funktionen Ein Blick hinter die Kulissen 2 struct JNINativeInterface_ { void *reserved0; void *reserved1; void *reserved2; void *reserved3; ... jfieldID (JNICALL *GetStaticFieldID) (JNIEnv *env, jclass clazz, const char *name, const char *sig); … } struct JNIEnv_ { const struct JNINativeInterface_ *functions; ... jfieldID GetStaticFieldID(jclass clazz, const char *name, const char *sig) { return functions->GetStaticFieldID(this,clazz,name,sig); } … } Ein Blick hinter die Kulissen 3 Spezielle Namenskonvention für externe d.h. native deklarierte „Java“ Methoden Auf nicht Java Seite erhalten Methoden immer zwei zusätzliche Argumente Argument eins ist der JNI Interface Pointer Argument zwei ist bei static native Methoden Zeiger auf Java-Klasse in JVM Argument zwei ist bei nonstatic native Methoden Zeiger auf Java-Objekt („this“) in JVM Ein Blick hinter die Kulissen 4 Was macht der Garbage Collector auf der nativen Seite? Primitive werden kopiert Java-Objekte „by reference“ übergeben Unterteilung in lokale / globale Referenzen Lokale Referenzen leben im Scope ihres erzeugendem Stack-Frame und Thread gelöscht ab „return“ (Vorsicht, JVM hat begrenzten Speicher um sich lokale Referenzen zu merken!) Globale Referenzen leben bis sie explizit freigegeben werden Lokale Referenzen können in globale umgewandelt werden JNI Funktionen geben lokale Referenzen zurück Ein Blick hinter die Kulissen 5 Wohin mit Fehlern? JNI Funktionen geben Fehlercodes Können mit ExceptionOccoured() abgefragt werden Zwei Arten des Exceptionhandlings Die native Methode kehrt zurück Exception wird im Javacode geworfen Die native Methode ruft ExceptionClear() auf und kümmert sich selbst um das Exceptionhandling Der Weg zur Verwendung 1 Voraussetzungen um native Methoden zu nutzen Deklaration – auf Java Seite Implementierung – als externe Einstiegspunkte in binären Bibliotheken JNI stellt die Möglichkeit eines „call back“ auf die aufrufende JVM bereit Laden – der Bibliothek (typischerweise im „static initializer“ der Java Klasse die „native“ verwendet) System.load(…) oder System.loadLibrary(…) Der Weg zur Verwendung 2 Deklaration – auf Java Seite Vorbereitung zum Erstellen der Headerdatei für native Seite set JAVA_HOME=C:\Programme\Java\jdk1.6.0_XX set PATH=%PATH%;%JAVA_HOME%\bin C:\PROJECT_PATH\bin>javap -private -s de.package.jni.Klasse Der Weg zur Verwendung 3 Implementierung – auf native Seite Inkludieren der Headerdatei „<jni.h>“ Gemäß der Namenskonvention muss eine Funktionsdeklaration geschrieben werden JNIEXPORT jboolean JNICALL Java_de_paket_jni_Klasse_callNative (JNIEnv *, jobject, jint); Geht’s auch einfacher?? Der Weg zur Verwendung 4 Implementierung – auf native Seite Kommandozeilentool zum Erzeugen der Headerdatei set JAVA_HOME=C:\Programme\Java\jdk1.6.0_XX set PATH=%PATH%;%JAVA_HOME%\bin C:\PROJECT_PATH\bin>javah de.package.jni.Klasse Der Weg zur Verwendung 5 Laden – der Bibliothek DEMO Quellen IBM Understanding the Java Native Interface Native Methoden und Bibliotheken (1997) http://olymp.idle.at/~apollo/books/Java%20in%2021%20Tagen/kap20.htm JNI 1.1 Specification ff. http://publib.boulder.ibm.com/infocenter/javasdk/v6r0/topic/com.ibm.java.doc.diagnostics.60/html/jni.html#jni http://java.sun.com/j2se/1.4.2/docs/guide/jni/ Gute Übersicht für den Praktischen Einsatz http://www.haertfelder.com/jni.html