2013年2月28日木曜日

Java Native Interface (JNI)

JNI (Java Native Interface)は、Java仮想マシンとネイティブアプリケーションを組み合わせるための標準プログラミングインタフェースです。

Java VM の動作に影響を及ぼすので、JNI関数の中ではシグナルハンドラを設定してはいけません。J2SDK v1.4からシグナル連鎖機能がサポートされ、シグナルハンドラが使用できるようになった。

Javaから呼び出されているネイティブライブラリをデバッガで動作させる

Javaから呼び出されているネイティブライブラリをデバッガで動作させるには、環境変数DEBUG_PROGにデバッガを定義します。そしてJavaを実行させるとデバッガが起動されますので、stop dlopenコマンドでデバッグするライブラリのパスを指定します。runコマンドで実行すると、libxxx.soが呼び出されると停止するので、ブレークポイントを設定して実行を継続します。

$ setenv DEBUG_PROG dbx
$ java
(dbx) stop dlopenn ライブラリのパス
(dbx) run Test.Test_0
(dbx) file operate.c
(dbx) stop at 行番号
(dbx) cont

JNIを使ってC言語からJavaのメソッドを呼ぶ

JNIを使うと、ネイティブ・コード(C言語やC++など)からJavaのクラスを利用したり、メソッドを呼ぶことができる。

C言語のサンプル・コードを次に示す。

include "jni.h"    int main()  {      JNIEnv  *env;      JavaVM  *jvm;      int     res;      jclass  clazz;      jmethodID mid;        JavaVMOption options[3];      options[0].optionString = "-Xmx128m";      options[1].optionString = "-verbose:gc";      options[2].optionString = "-Djava.class.path=/home/yajima/class";        JavaVMInitArgs vm_args;      vm_args.version = JNI_VERSION_1_6;      vm_args.options = options;      vm_args.nOptions = 3;        /* Java VM の作成 */      res = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);      if (res < 0) {          fprintf(stderr, "JNI_CreateJavaVM error\n");          return -1;      }        /* Javaクラスの検索 */      clazz = (*env)->FindClass(env, "Hello");      if (clazz == 0) {          fprintf(stderr, "FindClass error\n");          return -1;      }        /* メソッド識別子の取得 */      mid = (*env)->GetStaticMethodID(env, clazz, "main",          "([Ljava/lang/String;)V");      if (mid == 0) {          fprintf(stderr, "GetStaticMethodID error\n");          return -1;      }        /* Hello#main の呼び出し */      (*env)->CallStaticVoidMethod(env, clazz, mid, NULL);        /* Java VM の破棄 */      (*jvm)->DestroyJavaVM(jvm);        return 0;  }  

C言語から呼び出されるJavaのサンプル・コードを次に示す。

public class Hello {      public static void main(String args[]) {          System.out.println("Hello!");      }  }  

jni.h のインクルード

C言語/C++ のプログラムで、ヘッダファイル jni.h をインクルードする必要がある。jni.h は JDK_HOME/include ディレクトリに含まれているので、このディレクトリをインクルードファイルのディレクトリとしてコンパイラに指定する。

jni.h の中では jni_md.h をインクルードしている。jni_md.h にはプラットフォームに依存する内容が含まれている。そのため、jni_md.h が存在するディレクトリはプラットフォームにより異なる。このディレクトリもインクルードファイルのディレクトリとしてコンパイラに指定する。

jni_md.h が存在するディレクトリの一例を次に示す。

jni_md.hのディレクトリ
OS パス
Windows include\win32
Linux include/linux
Solaris include/solaris

JNI変数型のマッピング

Javaとネイティブ変数型(C言語)のマッピングを次の表に示す。

JNI変数型のマッピング
Java変数型 ネイティブ変数型
jboolean unsigned char
jbyte signed char
jchar unsigned short
jshort short
jnit int
jlong long long __int64
jfloat float
jdouble double

Java VMの生成

Java VMをロードして初期化するには、JNI_CreateJavaVM()関数を呼び出す。

_JNI_IMPORT_OR_EXPORT_ jint JNICALL
JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args);

引数pvmには、呼び出しAPI関数テーブルのポインタ (JavaVM *) を格納する領域へのポインタを渡す。

呼び出しAPI関数テーブルには、次に示す関数へのポインタが格納される。

  • DestroyJavaVM
  • AttachCurrentThread
  • DetachCurrentThread
  • GetEnv
  • AttachCurrentThreadAsDaemon

引数argsには、JavaVMInitArgs構造体を参照するポインタを指定する。

JavaVM型

JavaVM は、JNIInvokeInterface_ 構造体へのポインタ型である。

#ifdef __cplusplus  typedef JavaVM_ JavaVM;  #else  typedef const struct JNIInvokeInterface_ *JavaVM;  

0 件のコメント:

コメントを投稿