Weitere JNI-Typen

Werbung
JNI - Java Native Interface
SYSTEM SOFTWARE
1
Probleme bei nativem Code in Java
Methodenaufruf
 Wie kann man native Methoden aus Java-Code aufrufen?
 Wie kann man Java-Methoden aus nativem Code aufrufen?
Parameterübergabe und Rückgabewärte
 Wie werden Parameterwerte und Rückgabewerte übergeben
Zugriff auf Java Memory
 Wie kann man Daten in einem Java-Objekt oder Array lesen und schreiben?
 Wie kann man ein Java-Objekt anlegen?
Garbage Collection
 Wann kann ein Objekt freigegeben werden, das von nativem Code benutzt wird?
SYSTEM SOFTWARE
2
Beispiel: Native Methoden in Java-Code
Class Out definiert native Methode für Ausgabe
Implementierung erfolgt in einer externen Bibliothek
Laden der Library mit der nativen Implementierung vor dem ersten Aufruf
Lädt Library mit Implementierung
nativer Methoden
class Out {
static {
System.loadLibrary("libout");
}
public static native void print(String text);
}
SYSTEM SOFTWARE
Methode mit Keyword
native (wie abstract ,d.h.
keine Implementierung)
3
Workflow
Native Methoden in Java deklarieren (in Out.java)
 public static native void print(String text);
Java Klassen kompilieren (erzeugt Out.class)
 javac Out.java
Header Dateien generieren (erzeugt Out.h)
 javah Out
Header Dateien inkludieren und native Methoden implementieren (in out.c)
 #include "Out.h"
 JNIEXPORT void JNICALL Java_Out_print(JNIEnv* env, jclass clazz, jstring text) {...}
Nativen Code compilieren (erzeugt libout.so)
Windows: libout.dll
 gcc -shared -fPIC -I<path-to-jdk-install-dir>/include -o libout.so out.c
Programmstart mit Angabe des Pfads zur nativen Library
 java -Djava.library.path=. Out
Native Library vor dem ersten Aufruf einer native Methode laden (in Out.java)
 static { System.loadLibrary("libout"); }
SYSTEM SOFTWARE
4
JNI Headers
javah generiert Header-Dateien aus kompilierten Java-Dateien
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Out */
#ifndef _Included_Out
#define _Included_Out
Pro native Methode in Java gibt es eine Methode
#ifdef __cplusplus
im Header mit Namen:
extern "C" {
Java_<Klassenname>_<Methodenname>
#endif
/*
* Class:
Out
* Method:
print
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_Out_print (JNIEnv*, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
Macro für
Library-Export
Macro für
C++ Calling
conventions
Parameter der Methode:
Parameter werden in native
Typen übersetzt
JNI Environment: Schnittstelle
zur Virtuellen Maschine
Klasse der Methode (bei
nichtstatischen Methoden
jobject (this)
SYSTEM SOFTWARE
5
JNI Type-Mapping
Java Typ
JNI Typ
32-bit Typ
64-bit Typ
Signatur
void
void
void
void
V
byte
jbyte
signed char
signed char
B
short
jshort
short
short
S
int
jint
int
int
I
long
jlong
long long
long
J
float
jfloat
float
float
F
double
jdouble
double
double
D
boolean
jboolean
unsigned char
unsigned char
Z
char
jchar
unsigned short
unsigned short
C
java.lang.Object
jobject
*
*
Ljava/lang/Object;
java.lang.String
jstring
*
*
Ljava/lang/String;
java.lang.Class
jclass
*
*
Ljava/lang/Class;
*
*
Ljava/lang/Throwable;
java.lang.Object[]
jobjectArray *
*
[Ljava/lang/Object;
int[]
jintArray
*
*
[I
?
jobject
*
*
L<full-class-name>;
java.lang.Throwable jthrowable
SYSTEM SOFTWARE
6
Weitere JNI-Typen
JNI Typ
Verwendung
jsize
Array Längen
jweak
Weak References
jvalue
Basis für alle primitiven Typen
jfieldID
ID für Felder
jmethodID
ID für Methoden
JNIEnv
Interface zur Java VM
Typen:
 Typen sind definiert in jni.h
 Geänderte Semantik von Typen, z.B.:
 Precision von float und double
 gleiche oder größere Wertebereiche
 kein Java-Overflow
 tatsächliche Typen sind architekturabhängig!
 Vererbungshierarchien gleich zu Java, z.B. jstring erbt von jobject
SYSTEM SOFTWARE
7
Object Handles
Jedes Objekt (jobject, jstring, …) ist nur ein Handle für ein Java-Objekt
 Nativer Code bekommt nie Pointer in Java Memory
3 Arten von Handles mit unterschiedlichen Lebenszeiten
 local
 lebt bis der native Frame zerstört wird, in dem der Handle angelegt wurde
 Parameter von nativen Methoden sind immer local
 kann explizit mit
(*env)->DeleteLocalRef(env, obj)
zerstört werden
 global
 lebt über native Frame-Grenzen hinweg
 muss explizit erzeugt und zerstört werden (NewGlobalRef, DeleteGlobalRef)
 weak
 werden explizit erzeugt und zerstört (NewGlobalRef, DeleteGlobalRef)
 Lebenszeiten wie global
 aber wie WeakReferece  Objekt vom Garbage Collector freigegeben, wenn keine Referenzen in
Java VM existieren
Handle wird dann null
SYSTEM SOFTWARE
8
Beispiel Object Handle
void Java_Foo_bar(JNIEnv* env, jclass clazz, jobject obj) {
static jobject last_obj = NULL;
if(last_obj != NULL) {
(*env)->DeleteGlobalRef(env, last_obj);
}
last_obj = (*env)->NewGlobalRef(env, obj);
printf(“obj %s last_obj\n”, obj == last_obj ? “==” : “!=”);
printf(“obj is %s the same as last_obj\n”,
(*env)->IsSameObject(obj, last_obj) ? “indeed” : “not”);
}
Output:
obj != last_obj
obj is indeed the same as last_obj
SYSTEM SOFTWARE
9
Zugriff auf Java Memory: Felder
 Suche Klasse
jclass GetObjectClass(JNIEnv*, jobject obj)
jclass FindClass(JNIEnv*, char* name)
Ähnlich zu Reflection
 Suche Feld (mit Klasse und Name)
jfieldID GetFieldID(JNIEnv*, jclass clazz, char* name, char* sig)
 Lese / schreibe Feld
<T> Get<T>Field(JNIEnv*, jobject obj, jfieldID field);
void Set<T>Field(JNIEnv*, jobject obj, jfieldID field, <T> value);
<T> … für unterschiedliche Typen
JNIEnv* env = ...
jobject person = ...
jclass clazz = (*env)->GetObjectClass(env, person);
jfieldID field = (*env)->GetFieldID(env, clazz, "age", "I");
jint age = (*env)->GetIntField(env, person, field);
(*env)->SetIntField(env, person, field, age + 1);
(*env)->DeleteLocalRef(clazz);
SYSTEM SOFTWARE
10
Zugriff auf Java Memory: Array
<T> … für unterschiedliche Typen
3 Zugriffsarten
 Elementweiser Zugriff
<T> Get<T>ArrayElement(JNIEnv*, j<T>Array array, jsize index)
void set<T>ArrayElement(JNIEnv*, j<T>Array array, jsize index, <T> value)
 Regionsweiser Zugriff
Get<T>ArrayRegion(JNIEnv*, j<T>Array array, jsize start, jsize length, <T>* buffer)
Set<T>ArrayRegion(JNIEnv*, j<T>Array array, jsize start, jsize length, <T>* buffer)
 Arrayweiser Zugriff
<T>* get<T>ArrayElements(JNIEnv*, j<T>Array array)
void Release<T>ArrayElements(JNIEnv*, j<T>Array array, <T>* elems, jint mode)
0
kopiere Elemente in array und gib Buffer frei
JNI_COMMIT
kopiere Elemente in array und gib Buffer nicht frei
JNI_ABORT
kopiere Elemente nicht zurück und gib Buffer frei
SYSTEM SOFTWARE
11
Beispiele: Zugriff auf Arrays
JNIEnv* env = ...; jintArray array = …;
//Access each element individually
for(jsize i = 0; i < (*env)->GetArrayLength(env, array); i++) {
jint value = (*env)->GetIntArrayElement(env, array, i);
(*env)->SetIntArrayElement(env, array, i, value + 1);
}
//Access the entire array at once
jint* native_array = (*env)->GetIntArrayElements(env, array);
for(jsize i = 0; i < (*env)->GetArrayLength(env, array); i++) {
native_array[i]++;
}
(*env)->ReleaseIntArrayElements(env, array, native_array, 0);
//Access chunks of the array
jint* chunk = (jint*) calloc(16, sizeof(jint);
for(jsize i = 0; i < (*env)->GetArrayLength(env, array) / 16; i++) {
(*env)->GetIntArrayRegion(env, array, i*16, 16, chunk);
for(int i = 0; i < 16; i++) {
chunk[i]++;
}
(*env)->SetIntArrayRegion(env, array, i*16, 16, chunk);
}
free(chunk);
SYSTEM SOFTWARE
12
Zugriff auf Java Memory: Strings
Inhalt wird nicht
zurückgeschrieben!
Lesender Zugriff wie auf Arrays
jsize GetStringLength(JNIEnv*, jstring string)
jchar* GetStringChars(JNIEnv*, jstring string)
void ReleaseStringChars(JNIEnv*, jstring string, jchar* chars)
JNIEXPORT void JNICALL Java_Out_print(JNIEnv* env, jclass clazz, jstring text) {
if(text != NULL) {
jsize length = (*env)->GetStringLength(env, text);
jchar* characters = (*env)->GetStringChars(env, text);
char* native_characters = calloc(length + 1, sizeof(char));
for(jsize i = 0; i < length; i++) {
native_characters[i] = (char) characters[i]; //assume ASCII only
}
native_characters[length] = '\0';
(*env)->ReleaseStringChars(env, text, characters);
printf("%s", native_characters);
free(native_characters);
}
}
clazz und text sind local Handles
und müssen deswegen nicht
explizit gelöscht werden
SYSTEM SOFTWARE
13
Aufrufe von Java aus Native-Code
 Suche Klasse wie bei Feldzugriff
"(" ParamSig0 ParamSig1 … ")" ReturnSig
zB: "(JJ)Z"
 Suche Methode
jmethodID GetMethodID(JNIEnv*, jclass clazz, char* name, char* sig)
Parameters
 Aufruf
<T> Call<T>Method(JNIEnv*, jobject thiz, jmethodID method, ...)
<T> CallNonvirtual<T>Method(JNIEnv*, jobject thiz, jclass clazz,
jmethodID method, ...)
<T> CallStatic<T>Method(JNIEnv*, jclass clazz, jmethodID method, ...)
 Spezielle Funktionen zur Objekterzeugung
jobject NewObject(JNIEnv*, jclass clazz, jmethodID constructor, ...)
jstring NewString(JNIEnv*, jchar* chars, jsize length)
j<T>Array New<Type>Array(JNIEnv*, jsize length)
jobject AllocObject(JNIEnv*, jclass clazz)
SYSTEM SOFTWARE
Erzeugt Objekt ohne
Konstruktor aufzurufen!
14
Beispiel: Aufrufe von Java aus Native-Code
JNIEnv* env = ...;
jobject person1 = ...; jobject person2 = ...;
jclass object_class = (*env)->FindClass(env, " Ljava/lang/Object");
(Object): boolean
const char* sig = "(Ljava/lang/Object;)Z";
jmethodID equals_method = (*env)->GetMethodID(env, object_class, "equals", sig);
jboolean equals = (*env)->CallBooleanMethod(env, person1, equals_method, person2);
(*env)->DeleteLocalRef(env, object_class);
boolean equals(Object)
SYSTEM SOFTWARE
15
Exceptions
JNIEXPORT void JNICALL Java_Person_raiseSalary
(JNIEnv* env, jclass clazz, jobject person, jdouble factor) {
if(person == NULL) {
char* exception_name = "java/lang/NullPointerException";
jclass exception_class = (*env)->FindClass(env, exception_name);
(*env)->ThrowNew(env, exception_class, “person must not be null”);
return;
}
...
}
ThrowNew wirft Exception in Java VM erst, wenn die
native Methode beendet ist!
SYSTEM SOFTWARE
16
Weitere JNI-Methoden
Methode
Beschreibung
ExceptionOccurred
Prüft, ob der zuletzt ausgeführte Aufruf eine Exception
ausgelöst hat
ExceptionDescribe
Erzeugt einen String, der die Exception beschreibt
IsSameObject
Prüft Objekte auf Referenzgleichheit
IsInstanceOf
Prüft, ob ein Objekt von einem bestimmten Typ ist
http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html
SYSTEM SOFTWARE
17
Zusammenfassung
JNI ermöglich native Code in Java einzubinden
Für jeden Java-Typ gibt es einen nativen JNI-Typ
Nativer Code kann Java-Objekte benutzen und Java-Methoden aufrufen
 Nativer Code bekommt nie einen direkten Pointer auf Java Memory
 Manuelle Speicherverwaltung bei Java-Objekten (Gefahr von Memory Leaks!)
SYSTEM SOFTWARE
18
Herunterladen