NVIDIA Nsight Tegra がすごい その3

今回はNDKの開発で、割と使われるJNIProxyという手法で Nshight Tegra のデバッグブレーク機能は有効になるか?を確かめてみたいと思います。

このJniProxyという方法は、Android上ではアプリケーションの実行体イメージがメモリ上にまだ存在する場合、再利用してアプリケーションが動く、という挙動に対して解決する方法の1種です。
C/C++ネイティブ開発者の間では、.so 内のグローバル変数が初期化されずにアプリケーションが起動したように見えます。

詳しくはこちら(ホイール欲しい ハンドル欲しい: Android NDKの初期化とdllの分離)で説明されている内容です。

Java – JniProxy.so — Application.so というように、
JavaからはJniProxy.soを操作し、JniProxyが本当の意味のアプリであるApplication.soをロード・アンロードします。

Nsight Tegraを導入した Visual Studioでこのようなプロジェクトを作成するには、前回説明した複数のライブラリを用いて .so を作成するという方法に近い物があります。1点違う点があるのは、両者が so となっている点です。まずは、2つのプロジェクトを作成して、今回の概観を作ってみます。

  • NativeAppMain (ネイティブアプリケーションの本体)
  • JavaJniApp (JniProxy.soをもつJavaアプリケーション)

プロジェクトのタイプは、JavaJniApp は Android Application With Native Code で作成し、
NativeAppMainは Android Native Application で作成します。
これらをまとめるソリューションは testJniProxy として作成しました。

作成して、とりあえず必要なファイル名を変更したものが以下のようになります。

続いてプロジェクトの設定を変更します。
NativeAppMain は今回は .so 形式となるので Configuration Type を Dynamic Library(*.so)に変更します。
また JavaJniApp は NativeAppMain に依存するようにしておきます。
そして、JavaJniAppのプロジェクトの設定では、ライブラリ dl を使用するように変更しておきます( -l”dl” を追加のライブラリに入れる)

ここまで設定できたら、各ソースコードを編集します。
ほぼ上記で紹介したサイトのコードのままなのですが以下のようになります。
まずは動作確認の意味もかねて、onCreateでロードして、onPauseで終了が呼ばれるだけの単純なものにしてあります。

JniProxy.cpp

/**********************************
 Java Native Interface library
**********************************/
#include 
#include 
#include 
#include 

#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "jniproxy", __VA_ARGS__))

template
void auto_load( T& a, void* ptr ) {
    a = reinterpret_cast(ptr);
}
#define get_proc_0( image, func_name ) auto_load( proc_##func_name, dlsym( image, #func_name ) )
#define get_proc( func_name )   get_proc_0( LoadApplication, func_name )

static void JNICALL (*proc_app_init)( JNIEnv*, jobject );
static void JNICALL (*proc_app_quit)( JNIEnv*, jobject );
static jint JNICALL (*proc_app_render)( JNIEnv*, jobject );

static void* LoadApplication = NULL;

static void InitializeApplication() {
    // lib 読み込み.
    LoadApplication = dlopen( "/data/data/org.sample.javajniapp/lib/libNativeAppMain.so", RTLD_LAZY );
    if( LoadApplication == NULL ) {
        LOGI( "load error" );
    }
    get_proc( app_init );
    get_proc( app_quit );
    get_proc( app_render );
}
static void FinalizeApplication() {
    if( LoadApplication ) {
        dlclose( LoadApplication );
        LoadApplication = NULL;
    }
}


extern "C" {

JNIEXPORT void
Java_org_sample_javajniapp_JavaJniApp_init( JNIEnv* env, jobject thiz )
{
    LOGI( "JavaJniApp_init" );
    if( !LoadApplication ) {
        InitializeApplication();
        proc_app_init( env, thiz );
    }
}

JNIEXPORT void
Java_org_sample_javajniapp_JavaJniApp_quit( JNIEnv* env, jobject thiz ) 
{
    LOGI( "JavaJniApp_quit" );
    if( LoadApplication ) {
        proc_app_quit( env, thiz );
        FinalizeApplication();
    }
}

JNIEXPORT jint
Java_org_sample_javajniapp_JavaJniApp_render( JNIEnv* env, jobject thiz )
{
    LOGI( "JavaJniApp_render" );
    if( LoadApplication ) {
        proc_app_render( env, thiz );
    }
}

} // extern "C"

JavaAppMain.java

public class JavaJniApp extends Activity
{
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);

		// Enter code here
		init();

	}

	@Override
	public void onPause() 
	{
		quit();
	}

	static {
		System.loadLibrary("JavaJniApp");
	}
	static native void init();
	static native void quit();
	static native int  render();
}

NativeAppMain.c

#include 
#include 

#include 
#include 

#include 
#include 

#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "nativeappmain", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "nativeappmain", __VA_ARGS__))

JNIEXPORT void JNICALL app_init( JNIEnv* env, jobject obj ) {
    LOGI( "app_init called" );
}

JNIEXPORT void JNICALL app_quit( JNIEnv* env, jobject obj ) {
    LOGI( "app_quit called" );
}

JNIEXPORT void JNICALL app_render( JNIEnv* env, jobject obj ) {
    LOGI( "app_render called." );
}

ここまででとりあえず必要な物はそろってはいるのですが、このまま実行するとNativeAppMainのロードが実は出来ません。
その理由は、NativeAppMain.so が JavaJniApp の apk の中に取り込まれないからです。
ちなみに libNativeAppMain.so は ソリューション以下の Android/Debug の中に存在はしているのですが、
今回のケースでは取り込まれないんですよね・・・。
VisualStudioのビルド前後のイベントを使用しても、取り込まれるようには設定できませんでした。

(解決策は次回へ続く。)

Android プログラミング
すらりんをフォローする
すらりん日記

コメント

タイトルとURLをコピーしました