JNI : CからJavaを呼び出す方法について

4,288 views
Skip to first unread message

Koken

unread,
Apr 15, 2011, 5:07:44 AM4/15/11
to 日本Androidの会
初めまして。
Android初心者のKokenと申します。
現在、JNIを利用して CからJavaのメソッドを呼び出そうとしているのですが、CallIntMethod で落ちてしまい、原因が分からず困り
果てております。どなたか、お力をお貸し頂けないでしょうか?(JavaからCの呼び出しはうまく行ったことを確認しています)
<Java側のソース>
public class HelloJni extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
getStrFromJNI();
}

// Cから呼ばれるメソッド
public int printMes( int num ){
Log.d( ">> JNI", "Number from C = " + num );
return 100;
}
}

<C側のソース>
void Java_com_example_hellojni_HelloJni_getStrFromJNI( JNIEnv* env,
jobject thiz )
{
jclass jcCallback = (*env)-
>FindClass(env,"com.example.hellojni.HelloJni");
jmethodID mid = (*env)-
>GetMethodID(env,jcCallback,"printMes","(I)I");
int ret = (*env)->CallIntMethod( env, jcCallback, mid, 200 );
return;
}

Android SDK は、1.5 Android NDKがr5 を利用しています。
何卒、宜しくお願いします。

tueda

unread,
Apr 15, 2011, 7:43:32 AM4/15/11
to android-g...@googlegroups.com
こんにちは。

問題点は多分2つ。

×:(*env)->FindClass(env,"com.example.hellojni.HelloJni");
○:(*env)->FindClass(env,"com/example/hellojni/HelloJni");

×:(*env)->CallIntMethod( env, jcCallback, mid, 200 );
○:(*env)->CallIntMethod( env, thiz, mid, 200 );

あとFindClass()はシグネチャを間違えやすいので、
GetObjectClass()を使ったほうが良いと思います。
JNIについては1冊本が出ていてオススメです。
「JNI:Java Native Interfaceプログラミング―C/C++コードを用いたJavaアプリケーション開発
ロ ブ ゴードン (著), Rob Gordon (原著), 林 秀幸 (翻訳) 」
10年以上前の本ですが今でも十分役に立ちました(JNIが何も変わってない)。

tueda

unread,
Apr 15, 2011, 10:29:05 AM4/15/11
to android-g...@googlegroups.com
こんにちは、tuedaです。
> 他のサンプルでは、ピリオド指定になっていたので、ピリオドにしておりましたが、これは
> どこかのバージョンで仕様が変わったと認識すれば宜しいでしょうか?(NDK r5 だけでしょうか?)
>
本によれば区切りはプラットフォームにかかわらずスラッシュ('/')としか書か
れてないので、
ピリオド('.')は受け付けないはず。
私も正式な仕様書を読んだことがないのでこれ以上は知らないです。すみません。

あとGetMethoIDの引数はjclassを取るのでこれはダメです。

> jmethodID mid = (*env)->GetMethodID(env,thiz,"printMes","(I)I");


順番にjobject-->jclass-->jmethodIDの順番で探していかないと無理です。
ところで、今回のサンプルを作っていて疑問に思ったのですが、C側でグローバ
ル変数として確保した部分を、別々のタイミングで


> 呼び出したJNIのC関数の両方で利用していた場合、.so 型で呼び出されるこの hello-jni.so はグローバル変数を利用した、データ共
> 有
> は難しいと考え得た方が宜しいでしょうか?
>
すみません、ちょっと意味がよくわからないです。


私も今ちょうどC++の複数のライブラリからなる比較的大きなライブラリを
Javaから使えるようにバインダー書いてますが、結構色々大変ですね...
Ubuntu/Andoridでクロスプラットフォームしたいのでビルドが特に。

Koken

unread,
Apr 15, 2011, 8:25:16 AM4/15/11
to 日本Androidの会
tueda様
早速のお返事ありがとうございます!
ご指摘の通りの修正で、無事起動を確認できました。

その上で、何点かご質問させて頂いて宜しいでしょうか?

> ×:(*env)->FindClass(env,"com.example.hellojni.HelloJni");
> ○:(*env)->FindClass(env,"com/example/hellojni/HelloJni");
> あとFindClass()はシグネチャを間違えやすいので、
> GetObjectClass()を使ったほうが良いと思います。

他のサンプルでは、ピリオド指定になっていたので、ピリオドにしておりましたが、これは
どこかのバージョンで仕様が変わったと認識すれば宜しいでしょうか?(NDK r5 だけでしょうか?)

あとご推奨の GetObjectClassについては、これからテストしてみたいと思います。

> ×:(*env)->CallIntMethod( env, jcCallback, mid, 200 );
> ○:(*env)->CallIntMethod( env, thiz, mid, 200 );

この部分で疑問が生まれたのですが、Find クラスで取得した jcCallback 変数を、GetMethodIDで利用していますが、
CallIntMethod( env, thiz, mid, 200 ); の部分では 引数のthizを利用しています。ということは、下記のよ
うな表現は可能でしょうか?

// jclass jcCallback = (*env)->FindClass(env,"com/example/hellojni/
HelloJni"); // コメントアウトしています。
jmethodID mid = (*env)->GetMethodID(env,thiz,"printMes","(I)I");
int ret = (*env)->CallIntMethod( env, thiz, mid, 200 );

もしダメだとすれば、jobject 定義と jclass 定義は、クラス定義とそのインスタンスの違いという認識で、インスタンスからは、メソッド

は取得出来ず、またクラスからはメソッドを呼べないという認識で宜しいでしょうか?(Javaも初心者で申し訳ありません)
(インスタンスからメソッドを呼べないのは、VMを通じた取得をしていないと認識でしょうか)

もし的外れな理解で、ご不快にさせてしまったらすみません。後学の為にアドバイス頂ければ幸いです。

> JNIについては1冊本が出ていてオススメです。
> 「JNI:Java Native Interfaceプログラミング―C/C++コードを用いたJavaアプリ

ありがとうございます!早速、amazon で探してみます。

ところで、今回のサンプルを作っていて疑問に思ったのですが、C側でグローバル変数として確保した部分を、別々のタイミングで
呼び出したJNIのC関数の両方で利用していた場合、.so 型で呼び出されるこの hello-jni.so はグローバル変数を利用した、データ共

は難しいと考え得た方が宜しいでしょうか?
もし、難しい仕組みであるとすれば、別にスレッドを立てて質問をさせて頂くかも知れません。

お忙しいところ、丁寧なご回答ありがとうございます。

Koken

unread,
Apr 18, 2011, 2:15:25 PM4/18/11
to 日本Androidの会
tueda 様
ご回答ありがとうございます。

> ピリオド('.')は受け付けないはず。
> 私も正式な仕様書を読んだことがないのでこれ以上は知らないです。すみません。

なるほど、ネットでの拾ったサンプルに問題があったようです。
今後はしっかりと覚えておくように致します。


> あとGetMethoIDの引数はjclassを取るのでこれはダメです。
> > jmethodID mid = (*env)->GetMethodID(env,thiz,"printMes","(I)I");
> 順番にjobject-->jclass-->jmethodIDの順番で探していかないと無理です。

なるほど、やはりご指導頂いた手順でのみ動作すると認識ですね。
大変勉強になりました。ありがとうございます。


> > 呼び出したJNIのC関数の両方で利用していた場合、.so 型で呼び出されるこの hello-jni.so はグローバル変数を利用した、データ共
> > は難しいと考え得た方が宜しいでしょうか?
> すみません、ちょっと意味がよくわからないです。

あ、これは Java からロードした、JNIで作られた fogefoge.so が関数実行後に勝手に解放されて、fogefore.so内で利用
しているグローバル
変数が、同じfogefoge.so の他の関数を呼んだ時には、再起動されて初期化されてしまうのではというお話だったのですが、この説明でも
伝わってなかったりしますでしょうか?(汗


> 私も今ちょうどC++の複数のライブラリからなる比較的大きなライブラリを
> Javaから使えるようにバインダー書いてますが、結構色々大変ですね...
> Ubuntu/Andoridでクロスプラットフォームしたいのでビルドが特に。

うお-、僕には遙か先の頂のような会話なので、今後ついて行けるように継続して学習して参ります。
今後とも宜しくお願いします。

Reply all
Reply to author
Forward
0 new messages