2013-10-17 4 views
19

私は自分のjniソースを作成しようとしています。いくつかのNDKのサンプルを見てみると、私は、彼らは多くの場合、私はそれをグーグルが、私は理解できないときには、このAndroid NDKでJNIEXPORTとJNICALLを使用するタイミングは?

JNIEXPORT void JNICALL Java_com_example_plasma_PlasmaView_renderPlasma(JNIEnv * env, jobject obj, jobject bitmap, jlong time_ms)

のようなJavaパッケージの名前でfollewedこれらのマクロJNIEXPORTとJNICALLを使用することがわかっこれらを使用する方法マクロ

答えて

23

JNIEXPORTとJNICALLは、NDK_ROOT/platforms/android-9/arch-arm/usr/include/jni.hで定義されています。設定によっては、このパスは異なりますが、ほとんど同じです。

#define JNIIMPORT 
#define JNIEXPORT __attribute__ ((visibility ("default"))) 
#define JNICALL 

JNIEXPORTは、ネイティブ関数が構築されたバイナリ(* .soというファイル)の動的テーブルに表示させるために使用されます。それらは「隠し」または「デフォルト」(詳細はhere)に設定することができます。これらの関数が動的テーブルにない場合、JNIはそれらを呼び出す関数を見つけることができないため、実行時にRegisterNatives呼び出しが失敗するようになります。

すべての関数はデフォルトでダイナミックテーブルになりますので、誰でも簡単にネイティブコードを逆コンパイルすることができます。 JNIがそれを見つける必要がある場合に備えて、すべての関数呼び出しがバイナリに組み込まれています。これは、コンパイラオプション-fvisibilityを使用して変更できます。私は誰もがこれを-fvisibility=hiddenに設定してコードを安全に保ち、JNIEXPORTを使用して外部可視性を持つ関数にフラグを立てることを推奨します。

stripコマンドを使用すると、デバッグシンボルが削除されるだけで、動的テーブルは分離されます。あなたの.soファイルからどれくらいの人が出ることができるかを見るために、objdumpで遊んでください。

最近、私たちはこれでうまくやってきました。これが誰かを助けてくれることを願っています。

編集:カスタムビルドシステムを使用しているため、他のビルド設定では表示オプションがデフォルトで設定されている可能性があります。詳細はthis SO answerでご覧になれます。簡単に言えば

+0

JNICALLの意味は? – Lealo

+1

JNICALLはアンドロイド上の空の定義です(上記と同じですが、プラットフォームの互換性のためにそこにあります)。 Windowsでは、JDK JNICALLは '__stdcall'(https://msdn.microsoft.com/en-us/library/zxk0tw93.aspx)として定義されています。 –

0

ネイティブクラスで 'javah'を実行し、生成するものを使用してください。あなたは100%の信頼性でそれを作り出すことができるツールを持っているとき、これのinsとoutsを知る必要はありません。

+0

このコマンドについてはわかりません。私はndk-buildの前に使っていますか? – nawara

+0

私はndk-buildについてのアイデアはありませんが、私は15年間JNIをやっており、javahとjavapなしではどこにも行きません。あなたはいつでもそれを見ることができます。 – EJP

4

これらのマクロの定義は、JNIのマシン依存部分(通常は$JAVA_HOME/include/<arch>/jni-md.h)にあります。

簡潔に言えば、JNIEXPORTには、指定された関数が正しくエクスポートされるために必要なコンパイラ指令が含まれています。アンドロイド(および他のLinuxベースのシステム)では、空になります。

JNICALLには、指定された関数が適切な呼び出し規約で確実に処理されるために必要なコンパイラ指令が含まれています。 Androidでもおそらく空です(w32では__stdcallです)。

一般に、空の場合でも入力してください。#define

+1

Androidの一部のアーキテクチャでJNICALLが空ではありません。 JNICALLは常に使用する必要があります。 registerNativesファミリの関数を使用していない場合は、JNIEXPORTを使用する必要があります。 –

0

  • JNIEXPORTあなたは、あなたがJNIEXPORTを使用してはならない機能のregisterNativesファミリを使用する必要があります。さもなければそれを使用しなければなりません。
  • JNICALLは常に使用する必要があります。

JNIEXPORTは、関数がシンボルテーブルで確実に表示されるようにします。 JNICALLは、関数が正しい呼び出し規約を使用することを保証します。 AndroidではJNICALLのアーキテクチャーに基づいて異なる価値があります。 ARMは空であり、あなたがそれを含まないようにするかもしれません。しかし、JNICALLを使用する必要があります。

registerNativesを使用すると、関数をプログラマチックにJNI_onLoadにリンクすることも、いつか将来リンクすることもできます。 registerNativesは誤った関数名を先にキャッチすることを可能にしており、このルートをお勧めします。

関連する問題