Vous êtes sur la page 1sur 32

The Java Native Interface (JNI)

Exécuter du code écrit dans un autre langage (C/C++)


(C/C )

Pourquoi ?
Comment ?
Un exemple

 “Au
Au coeur de Java 2 : Fonctions avancées”,
avancées ,
C.S.Horstmann & G.Cornell, Campus Press, Pearson
Education,, 2002

F. Mallet – EPU Électronique 6-1


Pourquoi ?

On dispose
p de beaucoupp de code non jjava
 On veut le réutiliser
 Les transformations automatiques sont impossibles
 On ne veut pas le « porter » à la main
Accès à des unités ou fonctions systèmes
 Fastidieux (java.lang.System
java lang System) ou impossible en java
 e.g., Ports série ou parallèle, etc.
La vitesse
i d'exécution
d' é i est déterminante
dé i
 On veut écrire des bouts en assembleur/c/c++
 Peu plausible avec les performances de JIT et HotSpot
 Goulot d'étranglement souvent ailleurs (e.g.,
(e g E/S,
E/S réseau)
F. Mallet – EPU Électronique 6-2
Mises En Garde

Perte de portabilité
 Il faut fournir des bibliothèques partagées pour chaque
plate-forme
l f ainsi
i i que des
d instructions
i i pour l'installation
l'i ll i
Problèmes de sécurité
 Pas de protection par la sandbox java
 Il est facile d'écrire du code C/C++ qui corrompt la
machine virtuelle java
C, C++ ou autre
 La
L liaison
li i avec n'importe
'i t quell langage
l estt possible
ibl
 JNI ne supporte que le lien avec C

F. Mallet – EPU Électronique 6-3


Comment ?

Appeler une fonction C/C++ à partir du code java


 Écrire le code java et le compiler : mot clé native
 Générer un fichier .h : javah
 Écrire ll'implémentation
implémentation native en C/C++
 Créer une bibliothèque partagée (e.g., DLL)
 Exécuter le programme java qui utilise la bibliothèque
Appeler du code java à partir de C/C++
 Invoquer la machine virtuelle
 Compiler le Java en code natif (e.g., gcj)

F. Mallet – EPU Électronique 6-4


Écrire Le Code Java

Les méthodes natives sont précédées du mot clé native


La méthode statique
q loadLibrary de la classe System
 Permet le chargement de bibliothèques partagées
 System.loadLibrary("essai");
S t l dLib (" i")
● Charge essai.dll sous Windows, libessai.so sous Unix
A quel moment utiliser cette instruction ?
 Constructeur ? Méthode ?
 Les blocs statiques sont des blocs exécutés lorsque la classe à
l
laquelle
ll ils
il appartiennent
i est chargée
h é par lel ClassLoader.
l d
 C'est le seul code en dehors d'une méthode.

F. Mallet – EPU Électronique 6-5


Exemple

public class Exemple {


static {
System.loadLibrary("essai");
}
int etat = 0 ;
p blic int add(int
public dd(int x, int y)
) {
return x + y + etat ;
}
public native void message();
}
La méthode message
g doit être définie dans essai.dll
Pas de restrictions sur la signature Java de message
 statique ou non, publique ou non, avec ou sans paramètres
F. Mallet – EPU Électronique 6-6
Compilation et Exécution
Ce code Java compile
 javac
ja ac E Exemple.java
emple ja a
 Produit le fichier Exemple.class
 La classe Exemple est utilisée normalement
L de
Lors d l'exécution
l' é ti
 Erreur de lien si essai.dll n'est p
pas trouvé
Exception in thread "main" java.lang.UnsatisfiedLinkError: no essai
in java.library.path
at java.lang.ClassLoader.loadLibrary(Unknown Source)
at java.lang.Runtime.loadLibrary0(Unknown
java lang Runtime loadLibrary0(Unknown Source)
at java.lang.System.loadLibrary(Unknown Source)
at Exemple.<clinit>(Exemple.java:3)
F. Mallet – EPU Électronique 6-7
La signature C de message

void Java_Exemple_message(JNIEnv *, jobject);


Utiliser le nom complet de la méthode : Exemple.message
 Si la classe appartient à un paquetage,
paquetage ajouter son nom
Transformer les caractères non ASCII ('_', '$', etc.) par
_0xxxx où xxxx est l'unicode en hexadécimal
Remplacer les points '.' par des soulignés '_'
 Exemple_message
Faire précéder de Java_
Méthodes
Méth d statiques
t ti : jobject estt remplacé
l é par jclass
Le jobject passé en paramètre représente this
F. Mallet – EPU Électronique 6-8
L'outil javah

Transformation automatique : javah Exemple


 Génère le fichier Exemple.h
#include <jni.h>

#ifndef _Included_Exemple
Included Exemple
#define _Included_Exemple
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT void JNICALL Java_Exemple_message (JNIEnv*, jobject);

#ifdef __cplusplus
}
#endif
#endif

F. Mallet – EPU Électronique 6-9


Paramètres et type de retour

 En C, les types
yp (int,
( long)
g) dépendent
p du compilateur
p
 JNI définit des types C équivalents aux types Java

Langage Java Langage C Octets


JNI_TRUE=1
boolean jboolean 1
JNI_FALSE=0
byte jbyte 1
char jchar 2
short jshort 2
int jint 4
long jlong 8
float jfloat 4
double jdouble 8
void void

F. Mallet – EPU Électronique 6-10


Exemple avec des paramètres

La méthode print de la classe mypackage.Exemple


mypackage Exemple
public native int print(int, int, double);
Devient en C
jint Java
Java_mypackage_Exemple_print(JNIEnv
mypackage Exemple print(JNIEnv *,
jobject, jint, jint, jdouble);
Les types JNIEnv, jobject, jint sont définis dans jni.h
jni h
L'équivalence n'est possible qu'avec les types de base
 Sinon : jstring, jobject, jarray, jthrowable, etc.
 Pas
P dde vérification
é ifi i stricte
i ded type (pas
( du
d C++)
C )

F. Mallet – EPU Électronique 6-11


Notes personnelles

F. Mallet – EPU Électronique 6-12


Les chaînes de caractères

jstring

F. Mallet – EPU Électronique 6-13


Utiliser des jstring en C

Calculer la taille :
jsize GetStringLength(JNIEnv* e, jstring s);
Manipuler les caractères : tableau de jchar
const jchar * GetStringChars(JNIEnv
GetStringChars(JNIEnv* env, env
jstring s, jboolean *isCopy);
 On
O peutt utiliser
tili ce tableau,
t bl il ne faut
f t pas le
l modifier
difi (const)
( t)
● le compilateur C ne vérifie pas les const
 isCopy vaut JNI_TRUE si le tableau est une copie
Avertir le g
garbage
g collector q
qu'on n'utilise pplus le j
jstring
g
void ReleaseStringChars(JNIEnv* e,
j t i
jstring s, const
t j
jchar
h []
[]c);
)
F. Mallet – EPU Électronique 6-14
Créer des jstring

jstring NewString(JNIEnv*, const jchar[], jsize);

Le tableau de jchar peut être désalloué (e.g. mémoire


statique)
La méthode renvoie NULL si la création est impossible

2 utilisations équivalentes (traduction inline)


 A la C : (*env)->GetStringLength(env, s);
 A la C++ : env->GetStringLength(s);

F. Mallet – EPU Électronique 6-15


UTF et unicode

Les méthodes présentées fonctionnent avec des


jchar : unicode
tableaux de j
Si on utilise des tableaux d'octets (jbyte) alors :
 GetStringUTFLength
 GetStringUTFChars
 ReleaseStringUTFChars
 NewStringUTF
i

F. Mallet – EPU Électronique 6-16


Les objets
j

jobject

F. Mallet – EPU Électronique 6-17


Lecture et modification des attributs

 Lecture
jint GetIntField(JNIENV*, jobject, jfieldID) ;
ji t GetStaticIntField(JNIENV*,
jint G tSt ti I tFi ld(JNIENV* jclass,jfieldID);
j l jfi ldID)

 Modification
SetIntField(JNIENV*, jobject, jfieldID, jint) ;
SetStaticIntField(JNIENV*, jclass,jfieldID,jint);

 Généralisation
Gé é li i
 Il faut remplacer
p Int/jint
j ppar le type
yp adéquat
q
 Boolean/jboolean, Byte/jbyte, Char/jchar, Short/jshort, Long/jlong,
j , Double/jdouble,
Float/jfloat, j , Object/jobject
j j j

F. Mallet – EPU Électronique 6-18


Les identificateurs d'attributs

jfieldID GetFieldID(JNIEnv *env,


env, jclass cl, const
char nom[], const char sig[]);
jfieldID GetStaticFieldID(JNIEnv *env
env, jclass cl
cl,
const char nom[], const char sig[]);
L signature
La i t textuelle
t t ll d'un
d' attribut
tt ib t estt codée
dé par
 B(byte),
( y ), C(char),
( ), D(double),
( ), F(float),
( ), I(int),
( ), J(long),
( g), S(short),
( ),
V (void), Z (boolean), LnomClasse; (classe), [ (tableau)
 [[F code le type float [][]
 [Ljava/lang/String; code String[]
Pour connaître la signature on peut utiliser javap -s

F. Mallet – EPU Électronique 6-19


Notes personnelles

F. Mallet – EPU Électronique 6-20


jclass

Les identificateurs s'obtiennent à partir de la jclass


Pour les méthodes statiques la jclass est disponible
directement
Pour les méthode d'instances on a un jobject
jclass GetObjectClass(JNIENV
j j ( *,
, j
jobject);
j );
On peut trouver la jclass à partir du nom de la classe
jclass FindClass(JNIENV *, const char []);
 e.g.
g ((*env)->FindClass(env,
) ( , “java/lang/String”);
j g g )

F. Mallet – EPU Électronique 6-21


Invoquer une méthode java

M th d d'i
Methodes d'instances
t
xxx CallXXXMethod(JNIENV*, jobject, jmethodID,
...) ;
Méthodes statiques
xxx CallStaticXXXMethod(JNIENV*, jclass,
jmethodID ...)
jmethodID, ) ;
Comme pour les attributs, le XXX/xxx doit être remplacé
en fonction du type de retour de la méthode concernée
 ee.g.
g CallVoidMethod si pas de retour,
retour CallIntMethod si le type
de retour est jint

F. Mallet – EPU Électronique 6-22


Les identificateurs de méthodes

jmethodID GetMethodID(JNIEnv *env, jclass cl,


const char
h nom[],
[] const char
h sig[]);
i [])
jmethodID GetStaticMethodID(JNIEnv *env, jclass
cl, const char nom[], const char sig[]);
La signature textuelle d
d'une
une méthode est codée :
 double add(int, float) par (IF)D
 void print(String, short[]) par (Ljava/lang/String;[S)V
Comme pour les attributs on peut utiliser javap -s

F. Mallet – EPU Électronique 6-23


javap –s Exemple
Compiled from "Exemple.java"
public class Exemple extends java
java.lang.Object{
lang Object{
int etat;
Signature: I
public Exemple();
Signature: ()V
public int add(int,int);
Signature: (II)I
public
bli native
ti void
id message();
()
Signature: ()V
static {};
Signature: ()V
}
F. Mallet – EPU Électronique 6-24
Invoquer un constructeur

jobject NewObject(JNIENV*,
NewObject(JNIENV , jclass, jmethodID,
...) ;
La signature textuelle d'un constructeur est obtenue
comme pour une méthode qui retourne void

F. Mallet – EPU Électronique 6-25


Les tableaux - jarray

Type Java Type C


boolean [] jbooleanArray
y []
byte[] jjbyteArray
y y
char[] jcharArray
int[] jintArray
short[]
h t[] j h tA
jshortArray
long[] jlongArray
float[] jfloatArray
double[] jdoubleArray
j []
Object[] jjobjectArray
j y

En C, tous ces types sont synonymes de jarray


En C++, une hiérarchie de classes est conservée

F. Mallet – EPU Électronique 6-26


Utiliser en C des tableaux Java

Connaître sa taille
jint getArrayLength(JNIENV
getArrayLength(JNIENV*, jarray);
Pour les tableaux d'objets, on accède aux éléments 1 à 1
jobject getObjectArrayElement(JNIENV *,
jobjectArray, jsize);
setObjectArrayElement(JNIENV *, jobjectArray,
jsize,
j , j
jobject);
j );

F. Mallet – EPU Électronique 6-27


Notes personnelles

F. Mallet – EPU Électronique 6-28


Pour les autres tableaux

O récupère
On é è un pointeur
i t sur le
l premier
i élément
élé t
xxx* GetXXXArrayElements(JNIENV*, jxxxArray,
jboolean *isCopy);
 isCopy = JNI_TRUE
JNI TRUE si une copie est effectuée
On autorise le ramasse miettes à libérer la mémoire
ReleaseXXXArrayElements(JNIENV *, jxxxArray, jint
mode);
 mode = 0 : libère et met à jour le tableau Java
 mode = JNI
JNI_COMMIT
COMMIT : ne libère pas,
pas mais met à jour
 mode = JNI_ABORT : libère et ne met pas à jour

F. Mallet – EPU Électronique 6-29


Références locales et globales

L de
Lors d l'appel
l' l d'une
d' méthode
éth d native
ti
 des références locales sont créées ppar défaut
● e.g. jclass, jobject, jfieldID, jmethodID, jarray, ...
 Ces références ne sont plus valides après ll'appel
appel de la méthode,
méthode
on NE DOIT PAS les stocker pour les utiliser plus tard
On peut en revanche demander la création et la
destruction de références globales
g
clsGlob = (*env)->NewGlobalRef(env, cls);
(*env) >DeleteGlobalRef(env cls);
(*env)->DeleteGlobalRef(env,

F. Mallet – EPU Électronique 6-30


Compilation du code C

 Avec VisualC++ sous Windows (vcvars32.bat):


cl -I%JAVA_HOME%\include
-I%JAVA_HOME%\include\win32
-LD Exemple
Exemple.c
c -o essai
essai.dll
dll
 Avec gcc sous Linux
gcc -c -fPIC -I$JAVA_HOME\include
-I$JAVA_HOME\include\linux Exemple.c
gcc -shared -o libessai.so Exemple.o
 Avec cygwin
yg ou MinGW sous Windows
gcc -c -I$JAVA_HOME\include
-I$JAVA_HOME\include\win32 Exemple.c
p
dllwrap –-add-stdcall-alias -o essai.dll Exemple.o

F. Mallet – EPU Électronique 6-31


Compilation Sous MAC sans XCode

 Fichier objet
cc -c –I/System/Library/Frameworks/JavaVM.framework/Headers
Exemple.c
 Bibliothèque dynamique (libXXX.jnilib)
cc –dynamiclib
y -o libessai.jnilib
j Exemple.o
p
–framework JavaVM

F. Mallet – EPU Électronique 6-32