C ++信号处理程序无法通知Java端

时间:2018-08-14 12:40:35

标签: android c++ java-native-interface

我有以下CPP代码。我想做的是,当本机端发生错误时,我将通知Java。我以How can I catch SIGSEGV (segmentation fault) and get a stack trace under JNI on Android?作为参考。

static JavaVM* g_JVM = NULL;
static jobject  g_thejavaobject  = NULL;

void InitializeNativeSide(JNIEnv *env, jclass, jobject object)
{
    env->GetJavaVM(&g_JVM);
    g_thejavaobject = env->NewGlobalRef(object);
}

// this executes in another thread running in parallel with UI thread
void StartExecuting(JNIEnv *_env, jclass) {
    struct sigaction sa;
    memset(&sa, 0, sizeof(struct sigaction));
    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction = SignalErrorHandler;
    sa.sa_flags   = SA_SIGINFO;
    sigaction(SIGSEGV, &sa, NULL);

    // native starts executing here. after a while, a SEGFAULT is encountered
    // triggering SignalErrorHandler()
    ...
}

void SignalErrorHandler(int signal, siginfo_t *si, void *arg)
{
    JNIEnv *env;
    g_JVM->GetEnv((void**)&env, JNI_VERSION_1_6);

    jclass myClass = env->FindClass("com/company/MyClass");
    jmethodID myMethod = env->GetMethodID(myClass, "nativeCrashed", "()V" );
    env->CallVoidMethod(g_thejavaobject, myMethod);

    env->DeleteLocalRef(myClass);
}

一切正常,但对myClass.nativeCrashed()的调用无效。我在做什么错了?

1 个答案:

答案 0 :(得分:2)

您不能这样做:

void SignalErrorHandler(int signal, siginfo_t *si, void *arg)
{
    JNIEnv *env;
    g_JVM->GetEnv((void**)&env, JNI_VERSION_1_6);

    jclass myClass = env->FindClass("com/company/MyClass");
    jmethodID myMethod = env->GetMethodID(myClass, "nativeCrashed", "()V" );
    env->CallVoidMethod(g_thejavaobject, myMethod);

    env->DeleteLocalRef(myClass);
}

这至少有两个基本原因是行不通的。

首先,只能从信号处理程序中调用异步信号安全功能。 POSIX指定的列表可以在http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03上找到。

没有Java JNI调用是异步信号安全的。

第二,the Java JVM uses SIGSEGV internally-获得SIGSEGV不一定致命:

  

Oracle Solaris,Linux和macOS中使用的信号

     

...

     

SIGSEGV, SIGBUS, SIGFPE, SIGPIPE, SIGILL这些信号用于   隐式null检查的实现,等等。