cocos2d-xのAndroidではネイティブの処理を利用しているため、ハイパフォーマンスな動作が期待出来ます。
が、実際にアプリを開発しているとエラーに直面することも多いと思います。
その際に出るエラーはこのようなものです。
I/DEBUG ( xxxx): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG ( xxxx): Build fingerprint: '---------------------------------------'
I/DEBUG ( xxxx): pid: xxxx, tid: xxxx >>> /system/bin/netd <<<
I/DEBUG ( xxxx): signal 11 (SIGSEGV), fault addr deadbaad
I/DEBUG ( xxxx): r0 00001728 r1 100ffd7c r2 00000027 r3 00000000
I/DEBUG ( xxxx): r4 afd42328 r5 00000000 r6 00000000 r7 00011000
I/DEBUG ( xxxx): r8 00100000 r9 aef01cad 10 10000000 fp 40008008
I/DEBUG ( xxxx): ip ffffffff sp 100ffd68 lr deadbaad pc afd11ca4 cpsr 40000030
以下略
デバッグダンプとか呼ばれているもので、ここからエラーの原因を追っていくわけですが、
このエラー、AndroidOSが発しているものなので、フックすることが出来ます。
Test.cpp
#import <stdio.h>
#import <stdlib.h>
#import <android/log.h>
#import <signal.h>
void initSignalHandler(){
signal(SIGSEGV , &sigsegvSignalHandler);
}
static void sigsegvSignalHandler(int sig){
jclass exception;
signal(sig , SIG_IGN);
JNIEnv *pEnv = 0;
bool bRet = false;
JavaVM* jvm = cocos2d::JniHelper::getJavaVM();
jvm->GetEnv((void**)&pEnv , JNI_VERSION_1_4);
if (! pEnv)
{
return;
}
exception = getClassID(pEnv , "java.lang.RuntimeException");
if(exception != NULL){
jmethodID methodId = pEnv->GetMethodID(exception , "toString" , "()Ljava/lang/String;");
jmethodID methodPrintStack = pEnv->GetMethodID(exception , "printStackTrace" , "()V");
jstring errMes = (jstring)pEnv->CallObjectMethod(exception , methodId);
pEnv->CallObjectMethod(exception , methodPrintStack);
const char* chars = pEnv->GetStringUTFChars(errMes , NULL);
pEnv->ThrowNew(exception , chars);
pEnv->DeleteLocalRef(exception);
free((void*)chars);
pEnv->DeleteLocalRef(chars);
}
}
signal関数を使用して、そこにHandlerを登録すると、
sigsegvが発生した時に処理を受けることが出来ます。
そこからjavaのRuntimeExceptionを生成して、それをthrowすることも出来ます。
initSignalHandlerは好きなタイミングで呼び出して下さい。
アプリ起動時にJNI経由で呼び出すなら、こんな感じでしょうか。
MainActivity.java
static private native void initSignalHandler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initSignalHandler();
}
Test.h
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_hoge_hoge_MainActivity_initSignalHandler(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
Test.cpp
JNIEXPORT void JNICALL Java_hoge_hoge_MainActivity_initSignalHandler(JNIEnv* env, jclass clazz) {
signal(SIGSEGV , &sigsegvSignalHandler);
}
で、
で!
で!!!!!
RuntimeExceptionの中身は…空っぽです。
なんにもありません。
そりゃそうだ、何も入れてないんだから!
このソースはこのままでは使えないので、利用方法によって変えるといいよ!
(ログ収集SDK組み込んでるならlogEvent仕込んだりね)
と、投げっぱなしジャーマンな事だったんで、書きにくかったんですが、
途中経過って事で何卒ご了承を。
本当はsigsegvが吐き出すデバッグダンプの中身まで拾いたい。
【追記】
import忘れてた…。