当前位置: 首页 > 知识库问答 >
问题:

从C++类崩溃到Java的JNI回调

段干子晋
2023-03-14

下面是一些代码:

Java代码:

//this is what I want to call from native code
public void something(String msg)
{
//do something with msg
}

public void somethingElse()
{
    callNative();
}

private native void callNatve();

//access native
static
{
    System.loadLibrary("someLib");
}

上面所有的工作都很好,但是C++试图做同样的事情,却做不到。(注意:我需要本机库中的类作为类,而不是独立的静态调用)

#include <string>
#include <jni.h>

class MyClass
{
    //ctor
    //dtor

    void someCall(std::string)

    static JNIEnv* envRef;
    static JavaVM* jvmRef;
    static jobject objRef;
};
#include <MyClass.h>

//static members
MyClass:;:JNIEnv* envRef;
MyClass::JavaVM* jvmRef;
MyClass::jobject objRef;

//this is the method whose instructions are crashing
void MyClass::someCall(std::string msg)
{
     //works assuming i call env->NewGlobalRef(MyClass::objRef) or setup/reattach from jvm in exported call or here
     jstring passMsg = envRef->NewStringUTF(msg.c_str());

    clsRef = envRef->GetObjectClass(objRef);
    if(clsRef == NULL)
    {
        return;
    }

    //This doesn't cause crash, but if I call FindClass("where/is/MyClass"); it does... strange
    jmethodID id = envRef->GetMethodID(clsRef, "something", "(Ljava/lang/String;)V");
    if(id == NULL)
    {
        return;
    }

    //Crashes
    //envRef->CallVoidMethod(clsRef, id, passMsg);

    if(envRef->ExceptionCheck())
    {
        envRef->ExceptionDescribe();
    }

    //Also crashes
    //jvmRef->DetachCurrentThread();
}

//this works
extern "C"
{
    JNIEXPORT void JNICALL Java_com_my_project_class_callNative(JNIEnv* env, jobject obj)
    {
        MyClass::objRef = env->NewGlobalRef(obj);
        MyClass::envRef = env;

        //tried both
        //MyClass::envRef->GetJavaVM(&MyClass::jvmRef);
        env->GetJavaVM(&MyClass::jvmRef);


        //Tried this
        /*
        int envStat = MyClass::jvmRef->GetEnv((void**)&MyClass::envRef, JNI_VERSION_1_6);
        if(envStat == JNI_EDETACHED)
        {
            //TODO: LOG
            //std::cout << "GetEnv: not attached" << std::endl;
            if(MyClass::jvmRef->AttachCurrentThread(&MyClass::envRef, NULL) != 0)
            {
                //TODO: LOG
                //std::cout << "Failed to attach" << std::endl;
            }
        }else if(envStat == JNI_OK)
        {
            //
        }else if(envStat == JNI_EVERSION)
        {
            //TODO: LOG
            //std::cout << "GetEnv: version not supported" << std::endl;
        }
        */

        //calling detachcurrentthread here crashes if set above

        MyClassObj.someCall(an std::string);
    }
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void* reserved)
{
    MyClass::jvmRef = jvm;

    return JNI_VERSION_1_6;
}

更新了MyClass::SomeCall定义:

void MyClass::someCall(std::string msg)
{
    //Get environment from cached jvm
    JNIEnv* env;
    jclass cls;

    int envStat = MyClass::jvmRef->GetEnv((void**)&env, JNI_VERSION_1_6);

    bool attached = false;
    if(envStat == JNI_EDETACHED)
    {
        //TODO: LOG
        if(JavaInterface::jvmRef->AttachCurrentThread(&env, NULL) != 0)
        {
            //TODO: LOG
            // "Failed to attach"
            return;
        }else if(envStat == JNI_OK)
        {
            attached = true;
        }else if(envStat == JNI_EVERSION)
        {
            //TODO: LOG
            // "GetEnv: version not supported"
        }
    }

     cls = env->FindClass("package/location/project/JavaClass");
    if(cls == NULL)
    {
        //TODO: LOG
        return;
    }

    jmethodID id = env->GetMethodID(cls, "something", "(Ljava/lang/String;)V");
    if(id == NULL)
    {
        return;
    }

    jstring passMsg = env->NewStringUTF(msg.c_str());

    //Crashes
    env->CallVoidMethod(cls, id, passMsg);

    if(attached)
        jvmRef->DetachCurrentThread();
 }

共有1个答案

戚衡
2023-03-14

Edit#1更改后的错误是,我向CallVoidMethod()传递了错误的对象。我最后做的工作是将callNative传递的jobject存储为MyClass的静态成员,并将其传递给CallVoidMethod,而不是CLS。

早先的电话:

JNIEXPORT void JNICALL Java_path_to_project_JavaClass_nativeCall(JNIEnv* env, jobject obj)
{
    JavaInterface::objRef = env->NewGlobalRef(obj)
}

在不再需要DeleteGlobalRef(objRef)之后,将在其他地方调用它。然后,唯一的变化是原生的“someCall”方法:

void MyClass::someCall(std::string msg)
{
    //everything here is the same

    //Now either of these will work
    cls = env->FindClass("com/empsoftworks/andr3ds/NativeInterface");
//cls = env->GetObjectClass(objRef);

    //unchanged stuff

    //This is what fixed it
    env->CallVoidMethod(objRef, id, passMsg);
}
 类似资料:
  • 我正在尝试修复崩溃,例如: 1: 2: 三: 我已经复习了IndirectReferenceTable()的源代码https://android.googlesource.com/platform/art//kitkat dev/runtime/indirect\u reference\u表。cc),它似乎因为表溢出而崩溃。 据我所知,我正在正确删除所有本地引用。 问题是否可能与当地参考文献无关?

  • 我的Android应用在使用时崩溃 这是我收到的唯一明显的错误消息: 无法将堆栈跟踪写入/data/anr/跟踪。txt(6738中的5571):没有这样的文件或目录 libMySharedLib.so 是从 ndk-build 生成的。我正在使用powerVR SDK,因此我假设这个库是事先在内部加载的。 如果我将我的代码分离到一个不同的共享库中,我可以让它工作,但这违背了我的需要(所有数据、指

  • 希望你做得很好。 我有一个C语言的JNI实现,其中一个C函数连接到当前JVM线程并回调一个Java方法,这实际上是在attachCurrentThread()函数调用时使JVM崩溃。我的实现基于链接中给出的答案,保持对JNIEnv环境的全局引用 线程创建部分,它将侦听套接字连接以接受事件并注入GetEvent函数。 回调函数 在接收到事件时执行GetEvent()后,我的JVM在AttachMon

  • 我已经编译了一个用于jni的测试dll。除了#include之外,它实际上完全是空的 这是加载库的类: true是最后打印的内容,证明错误在true和loaded!之间!。如果我在eclipse中运行,会打印两条错误消息,但互联网不知道它们是什么。 信息: 堆栈转储是无信息的。 当我在维基百科页面上运行示例时,实验也失败了。它以同样的方式失败。

  • 问题内容: 我目前在一个项目中同时使用C 和Java,并且希望能够将包含在C 中的对象发送到我的Java接口,以便通过GUI对其进行修改,然后将所做的修改发送回C ++中。 到目前为止,我一直没有通过JNI接口向Java返回int或boolean值。这次我必须通过接口发送对象。我已经在C ++和Java中提供了类似的类定义。 我想知道如何创建对象,以便可以在Java中使用它。 在C ++中,我有:

  • 问题内容: 我试图从jni回调中写入AudioTrack,但收到信号7(SIGBUS),错误地址00000000。 我已经看了看Wolf3D例如,对于odroid,他们似乎使用android.os.Handler发布一个Runnable将在正确的线程上下文做一个更新。我也尝试了AttachCurrentThread,但是在这种情况下我也失败了。 即使我将其包装在线程中,然后将其发布到处理程序中,它