Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und...

31
Java Native Interface Eine Einführung

Transcript of Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und...

Page 1: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

Java Native Interface

Eine Einführung

Page 2: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

2

Motivation

Java: abstrahiert von Hardware und Betriebssystem+ hohe Portabilität+ hohe Sicherheit (Sandbox-Prinzip)- verminderte Performanz

(mit heutigen JIT-Compilern i.A. kein Problem mehr)- kein direkter Zugriff auf Hardware-/Betriebssystem

C/C++: Programmiersprache für OS-Entwicklung (UNIX)+ maschinennah, hohe Performanz+ alt, weit verbreitet, umfangreiche Sammlung von Legacy-Code- Programmierung möglicherweise umständlich (GUI in C?)- hohe Anforderungen an Programmierer

Page 3: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

3

Das Java Native Interface (JNI)

Schnittstelle, um C/C++ -Code in Java einzubindenund umgekehrt

Beispiele - C/C++ in Java: Treiber, Betriebssystemfunktionen ansprechen

(SWT) Vorhandene Bibliotheken einbinden Zeitkritische Funktionen in C oder Assembler

einbinden Möglicherweise Verlust der Portabilität!

Beispiel – Java in C/C++: Browser, der Applets ausführt

Page 4: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

4

JNI - Architektur

Schnittstelle definiert Datentypen und Funktionen… zum Aufruf nativer Funktionen in Java zur Abbildung von Java-Datentypen in

C/C++ zur Erzeugung und Mani-

pulation von Java-Objekten in C/C++ (OO in C?)

zum Aufruf einer JVM aus C/C++ heraus

Page 5: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

5

C in Java : Hallo Welt

Minimal-Beispiel: Aufruf einer nativen Methode, die „Hallo Welt!“ auf der Konsole ausgibt.

Prinzipielles Vorgehen (immer gleich):

Page 6: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

6

Hallo Welt – Java-Code

Definition einer nativen Methode ohne Rumpf

Dynamisches Laden der Bibliothek, die Methode bereitstellt

Kompilieren mit: javac HelloWorld.java

class HelloWorld {

private native void print(); public static void main(String[] args) { new HelloWorld().print(); }

static { System.loadLibrary("HelloWorld"); }}

Page 7: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

7

Hallo Welt – C/C++-Header

Die C-Methode, die in HelloWorld aufgerufen wird, muss gewisse Konventionen erfüllen

javah –jni HelloWorld.class erzeugt Header-Datei HelloWorld.h mit Prototypen aller nativen Methoden:

Methoden-Name muss in C eindeutig sein, daher:Java_packageName_className_methodName

Parameterlose Funktion print() erhält in C zwei Parameter !?

include <jni.h> […]

JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *env, jobject); […]

Page 8: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

8

Hallo Welt – C-Code

Implementierung der in Header-Datei definierten Funktion in Datei HelloWorld.c:

Übersetzen in gemeinsam genutzte Bibliothekgcc -fPIC -c HelloWorld.c

ld -shared -soname libHelloWorld.so.l -o libHelloWorld.so HelloWorld.o

#include "HelloWorld.h"#include <stdio.h>

JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *env, jobject obj){ printf("Hallo Welt!\n");}

Page 9: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

9

Hallo Welt - Finale

Ausführen des Java-Programms: java HelloWorld java.lang.UnsatisfiedLinkError: no HelloWorld in library path

at java.lang.Runtime.loadLibrary(Runtime.java)at java.lang.System.loadLibrary(System.java)at HelloWorld.main(HelloWorld.java)

Pfad zur Bibliothek noch unbekannt! Entweder1. Bibliothek in /usr/lib verschieben (root-Rechte!),2. setenv LD_LIBRARY_PATH .:${LD_LIBRARY_PATH},3. oder Bibliothekpfad explizit an Java übergeben:

java –Djava.library.path=. HelloWorld

Page 10: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

10

Abbildung der Datentypen

Bisher: kein Datenaustausch zwischen Java und C

Datentypen in Java: Primitive Datentypen, Klassen, Objekte, Arrays

Unterschiede Java vs. C: Java: Einheitliche Spezifikation primitiver

Datentypen auf allen Plattformen C: plattformabhängig (z.B. 2Byte int, 4Byte int)

Java: ObjektorientierungC: keine Objekte, aber strukturierte Datentypen und Funktionszeiger

Page 11: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

11

Abbildung primitiver Datentypen

Java-Typ Nativer Typ Beschreibung

boolean jboolean 8 Bit ohne Vorzeichen

byte jbyte 8 Bit mit Vorzeichen

char jchar 16 Bit ohne Vorzeichen

short jshort 16 Bit mit Vorzeichen

int jint 32 Bit mit Vorzeichen

long jlong 64 Bit mit Vorzeichen

float jfloat 32 Bit

double jdouble 64 Bit

void void

Page 12: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

12

Abb. primitiver Datentypen – Beispiel

public class Sum{ static{ System.loadLibrary("Sum"); } public static native int sum(int a, int b); public static void main(String[] args){ System.out.println("sum(3,4)=" + sum(3,4));

}}

#include <jni.h> […]

JNIEXPORT jint JNICALL Java_Sum_sum (JNIEnv *env, jclass, jint, jint); […]

JNIEXPORT jint JNICALL Java_Sum_sum(JNIEnv *env, jclass cl, jint a, jint b){ jint result = a + b; return result;}

Page 13: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

13

Abbildung von Referenz-Datentypen

Objekte, Klassen und Arrays werden in Java über Referenzen angesprochen

An C wird ein „transparenter“ Pointer übergeben, der auf die Objekte in der JVM zeigt.

Zugriff auf die Objekte erfolgt immer über die JNIEnv-Umgebung, die jeder nativen Methode übergeben wird:

Page 14: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

14

Abb. von Referenztypen – z.B. Arrays

import java.util.Random;public class Sort{

static{ System.loadLibrary("QSort"); } public static native void sort(double[] arr); public static void main(String[] args){ […] double[] arr = new double[Integer.parseInt(args[0])]; Random r = new Random(); for(int i=0; i< arr.length; arr[i++] = r.nextInt(10000)); long s = System.currentTimeMillis(); sort(arr); long e = System.currentTimeMillis(); System.out.println("Sortierung dauerte "+(e-s)+"ms"); }}

Page 15: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

15

Abb. von Referenztypen – z.B. Arrays

Prototyp:

Zugriff auf Array-Elemente:

JNIEXPORT void JNICALL Java_Sort_sort (JNIEnv *env, jclass, jdoubleArray);

JNIEXPORT void JNICALLJava_Sort_sort (JNIEnv *env, jclass cl, jdoubleArray arr){

jdouble *cArray = (jdouble*) arr; // FALSCH!!!// arr ist lediglich ein Pointer auf eine JVM-// Datenstruktur. Der Zugriff auf die Array-Elemente// muss über die JNIEnv Umgebung erfolgen![…]

}

Page 16: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

16

Abb. von Referenztypen – z.B. Arrays

int compare(const void *a, const void *b){return *((jdouble*) a) < *((jdouble*) b) ? -1 : +1;

}

JNIEXPORT void JNICALLJava_Sort_sort (JNIEnv *env, jclass cl, jdoubleArray arr){

jboolean isCopy;jdouble* cArray = (*env)->GetDoubleArrayElements(env, arr,

isCopy);jint length = (*env)->GetArrayLength(env, array);

qsort(cArray, length, sizeof(jdouble), &compare); if(isCopy) (*env)->ReleaseDoubleArrayElements(env, array, cArray, 0);}

Page 17: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

17

Array-Zugriffsmethoden

Get<Type>ArrayRegion, Set<Type>ArrayRegion Kopiert Bereich aus oder in ein Array mit

primitivem Datentyp Get<Type>ArrayElements,

Release<Type>ArrayElements Erhält einen Pointer auf ein Array (ggf. auch

Kopie) und gibt ihn wieder frei (ansonsten Speicherleck!)

GetArrayLength Ermittelt die Länge eines Arrays

New<Type>Array Legt ein neues Array an

Nur auf primitive Arrays anwendbar!

Page 18: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

18

Zugriff auf Objekt-Arrays

Beispiel: String[] strArray; int[][] intArray; Object[] objArray;

Unmöglich, gesamtes Array abzufragen Lediglich einzelne Einträge zugreifbar

GetObjectArrayElement SetObjectArrayElement

Page 19: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

19

Beispiel: Anlegen eines 2D-Feldes

Zuerst: Anweisung an JVM, ein int[] array anzulegen:

private static native int[][] initInt2DArray(int size);

JNIEXPORT jobjectArray JNICALLJava_ObjectArrayTest_initInt2DArray(JNIEnv *env, jclass c, int s){ jobjectArray result; int i; jclass intArrCls = (*env)->FindClass(env, "[I"); if (intArrCls == NULL) return NULL; /* exception thrown */ result = (*env)->NewObjectArray(env, size, intArrCls, NULL); if (result == NULL) return NULL; /* out of memory error thrown */

Page 20: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

20

Beispiel: Anlegen eines 2D-Feldes

Dann: Für jeden Eintrag des int[] Arrays ein primitives int[] Array anlegen

…for (i = 0; i < size; i++) {

jint tmp[256]; /* make sure it is large enough! */ int j; jintArray iarr = (*env)->NewIntArray(env, size); if (iarr == NULL) return NULL; /* out of memory error */ for (j = 0; j < size; j++) tmp[j] = i + j; (*env)->SetIntArrayRegion(env, iarr, 0, size, tmp); (*env)->SetObjectArrayElement(env, result, i, iarr); (*env)->DeleteLocalRef(env, iarr); } return result;}

Page 21: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

21

Beispiel: Anlegen eines 2D-Feldes

Dann: Für jeden Eintrag des int[] Arrays ein primitives int[] Array anlegen

…for (i = 0; i < size; i++) {

jint tmp[256]; /* make sure it is large enough! */ int j; jintArray iarr = (*env)->NewIntArray(env, size); if (iarr == NULL) return NULL; /* out of memory error */ for (j = 0; j < size; j++) tmp[j] = i + j; (*env)->SetIntArrayRegion(env, iarr, 0, size, tmp); (*env)->SetObjectArrayElement(env, result, i, iarr); (*env)->DeleteLocalRef(env, iarr); } return result;}

Inhalt von tmp nach iarr kopieren

Page 22: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

22

Beispiel: Anlegen eines 2D-Feldes

Dann: Für jeden Eintrag des int[] Arrays ein primitives int[] Array anlegen

…for (i = 0; i < size; i++) {

jint tmp[256]; /* make sure it is large enough! */ int j; jintArray iarr = (*env)->NewIntArray(env, size); if (iarr == NULL) return NULL; /* out of memory error */ for (j = 0; j < size; j++) tmp[j] = i + j; (*env)->SetIntArrayRegion(env, iarr, 0, size, tmp); (*env)->SetObjectArrayElement(env, result, i, iarr); (*env)->DeleteLocalRef(env, iarr); } return result;}

Array an übergeordnetes Objekt-Array result übergeben

Page 23: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

23

Beispiel: Anlegen eines 2D-Feldes

Dann: Für jeden Eintrag des int[] Arrays ein primitives int[] Array anlegen

…for (i = 0; i < size; i++) {

jint tmp[256]; /* make sure it is large enough! */ int j; jintArray iarr = (*env)->NewIntArray(env, size); if (iarr == NULL) return NULL; /* out of memory error */ for (j = 0; j < size; j++) tmp[j] = i + j; (*env)->SetIntArrayRegion(env, iarr, 0, size, tmp); (*env)->SetObjectArrayElement(env, result, i, iarr); (*env)->DeleteLocalRef(env, iarr); } return result;}

Kontrolle über iarr an JVM geben

Page 24: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

24

Arbeiten mit Strings

Java Strings sind Unicode-Codiert, C-Strings sind ASCII-codiert

Anbindung über UTF-8 (kann beide Codierungen abbilden) GetStringChars, ReleaseStringChars GetStringUTFChars, ReleaseStringUTFChar GetStringLength, GetStringUTFLength NewString, NewStringUTF GetStringRegion, SetStringRegion GetStringUTFRegion, SetStringUTFRegion

Anbindung sehr umständlich, Java im Umgang mit Strings komfortabler, daher wenig Relevanz

Page 25: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

25

Zugriff auf Objekt-Felder und -Methoden

Bei komplexen Klassen-Instanzen kann aus C heraus auf die Felder und Methoden der Instanz zugegriffen werden.

Mechanismus erscheint relativ umständlich, daher hier nur exemplarisch dargestellt. Für nähere Infos siehe JNI-Referenz

Page 26: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

26

Zugriff auf Static-Feld

Java-Klasse mit statischem Feld si si soll in nativer Methode manipuliert

werdenclass StaticFieldAccess { private static int si; private native void accessField(); public static void main(String args[]) { StaticFieldAccess c = new StaticFieldAccess(); StaticFieldAccess.si = 100; c.accessField(); System.out.println("In Java:"); System.out.println(" StaticFieldAccess.si = " + si); } static { System.loadLibrary("StaticFieldAccess"); }}

Page 27: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

27

Zugriff auf Static-Feld

JNIEXPORT void JNICALLJava_StaticFieldAccess_accessField(JNIEnv *env, jobject obj){ jfieldID fid; /* store the field ID */ jint si; /* Get a reference to obj’s class */ jclass cls = (*env)->GetObjectClass(env, obj);

/* Look for the static field si in cls */ fid = (*env)->GetStaticFieldID(env, cls, "si", "I"); if (fid == NULL) return; /* field not found */ /* Access the static field si */ si = (*env)->GetStaticIntField(env, cls, fid); printf(" StaticFieldAccess.si = %d\n", si); (*env)->SetStaticIntField(env, cls, fid, 200);}

Page 28: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

28

Zugriff auf Instanz-Methode

Methode callback() soll in nativeMethod() gerufen werden

class InstanceMethodCall { private native void nativeMethod(); private void callback() { System.out.println("In Java"); } public static void main(String args[]) { InstanceMethodCall c = new InstanceMethodCall(); c.nativeMethod(); } static { System.loadLibrary("InstanceMethodCall"); }}

Page 29: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

29

Zugriff auf Instanz-Methode

JNIEXPORT void JNICALLJava_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj){ jclass cls = (*env)->GetObjectClass(env, obj); jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V"); if (mid == NULL) return; /* method not found */ printf("In C\n"); (*env)->CallVoidMethod(env, obj, mid);}

Page 30: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

30

Das war erst der Anfang...

JNI bietet noch mehr: Erzeugen von Objekten, Aufruf von

Konstruktoren Caching von Methoden-/Feld-Ids Exception-Handling …

Diese Themen werden dem geneigten Hörer zum Selbststudium überlassen

Page 31: Java Native Interface Eine Einführung. 2 Motivation Java: abstrahiert von Hardware und Betriebssystem + hohe Portabilität + hohe Sicherheit (Sandbox-Prinzip)

31

Fazit

Enorme Möglichkeiten, positive Aspekte von C, C++ und Java zu integrieren

Aufwand allerdings nicht unerheblich, daher sollten immer auch Alternativen in Betracht gezogen werden

Für Standardaufgaben ist Einsatz von JNI aufgrund des stetig abnehmenden Performanz-Vorsprungs von C/C++ (wahrscheinlich) nicht lohnend