超能力 NDK 安卓:返回 int 在"extern"块中成功,在调用函数中失败

Superpowered NDK Android: returning int succeeds in "extern" block, fails in called function

本文关键字:成功 调用 函数 失败 NDK int 返回 安卓 超能力 extern      更新时间:2023-10-16

我正试图弄清楚如何从C++函数向Java返回int。

在Java方面,我在一个按钮中有以下内容。我把它放在一个按钮中,以确保在尝试执行returnInt()之前应用程序已完全加载。

int testInt;
testInt = returnInt();
Log.i(TAG, "testInt");
Log.i(TAG, String.valueOf(testInt));

private native int returnInt();

在C++方面,在extern块中返回int成功:

extern "C" JNIEXPORT jint Java_com_superpowered_crossexample_MainActivity_returnInt(JNIEnv * __unused javaEnvironment, jobject __unused obj) {
return 50;
}

但是使用SIGILL:尝试以下操作失败

jint SuperpoweredExample::returnInt() {
__android_log_print(ANDROID_LOG_VERBOSE, "CrossExample ", "returnInt");  // this runs
return 50;  // This fails with SIGILL
}
extern "C" JNIEXPORT jint Java_com_superpowered_crossexample_MainActivity_returnInt(JNIEnv * __unused javaEnvironment, jobject __unused obj) {
// fails with SIGILL
example->returnInt();
}

知道为什么上面会产生SIGILL吗?

我正在用Superpowered提供的CrossExample项目的克隆进行测试。(我只是用CrossExample作为一种简单的方式,让一个功能强大的项目发挥作用。)

我的项目在这里:

https://github.com/mhurwicz/myCrossExample

这个返回int的尝试在我的项目的myCrossExample1分支中。

如果出于任何原因你想要它,最初的Superpowered项目就在这里:

https://github.com/superpoweredSDK/Low-Latency-Android-Audio-iOS-Audio-Engine

以下是调试输出:

Signal = SIGILL (signal SIGILL: illegal instruction operand)
javaEnvironment = {JNIEnv * | 0xb40d9a80} 0xb40d9a80
[0] = {JNIEnv} 
functions = {const JNINativeInterface * | 0xb4032a40} 0xb4032a40
[0] = {const JNINativeInterface} 
reserved0 = {void * | 0x0} nil
reserved1 = {void * | 0x0} nil
reserved2 = {void * | 0x0} nil
reserved3 = {void * | 0x0} nil
GetVersion = {jint (*)(JNIEnv *) | 0xb3a505f5} (libart.so`art::CheckJNI::GetVersion(_JNIEnv*))
DefineClass = {jclass (*)(JNIEnv *, const char *, jobject, const jbyte *, jsize) | 0xb3a51ad0} (libart.so`art::CheckJNI::DefineClass(_JNIEnv*, char const*, _jobject*, signed char const*, int))
FindClass = {jclass (*)(JNIEnv *, const char *) | 0xb3a51f8c} (libart.so`art::CheckJNI::FindClass(_JNIEnv*, char const*))
FromReflectedMethod = {jmethodID (*)(JNIEnv *, jobject) | 0xb3a52c2f} (libart.so`art::CheckJNI::FromReflectedMethod(_JNIEnv*, _jobject*))
FromReflectedField = {jfieldID (*)(JNIEnv *, jobject) | 0xb3a531b4} (libart.so`art::CheckJNI::FromReflectedField(_JNIEnv*, _jobject*))
ToReflectedMethod = {jobject (*)(JNIEnv *, jclass, jmethodID, jboolean) | 0xb3a536f0} (libart.so`art::CheckJNI::ToReflectedMethod(_JNIEnv*, _jclass*, _jmethodID*, unsigned char))
GetSuperclass = {jclass (*)(JNIEnv *, jclass) | 0xb3a523d8} (libart.so`art::CheckJNI::GetSuperclass(_JNIEnv*, _jclass*))
IsAssignableFrom = {jboolean (*)(JNIEnv *, jclass, jclass) | 0xb3a527f0} (libart.so`art::CheckJNI::IsAssignableFrom(_JNIEnv*, _jclass*, _jclass*))
ToReflectedField = {jobject (*)(JNIEnv *, jclass, jfieldID, jboolean) | 0xb3a53b50} (libart.so`art::CheckJNI::ToReflectedField(_JNIEnv*, _jclass*, _jfieldID*, unsigned char))
Throw = {jint (*)(JNIEnv *, jthrowable) | 0xb3a53fb0} (libart.so`art::CheckJNI::Throw(_JNIEnv*, _jthrowable*))
ThrowNew = {jint (*)(JNIEnv *, jclass, const char *) | 0xb3a544c0} (libart.so`art::CheckJNI::ThrowNew(_JNIEnv*, _jclass*, char const*))
ExceptionOccurred = {jthrowable (*)(JNIEnv *) | 0xb3a549da} (libart.so`art::CheckJNI::ExceptionOccurred(_JNIEnv*))
ExceptionDescribe = {void (*)(JNIEnv *) | 0xb3a54dd0} (libart.so`art::CheckJNI::ExceptionDescribe(_JNIEnv*))
ExceptionClear = {void (*)(JNIEnv *) | 0xb3a55200} (libart.so`art::CheckJNI::ExceptionClear(_JNIEnv*))
FatalError = {void (*)(JNIEnv *, const char *) | 0xb3a55a30} (libart.so`art::CheckJNI::FatalError(_JNIEnv*, char const*))
PushLocalFrame = {jint (*)(JNIEnv *, jint) | 0xb3a55e3e} (libart.so`art::CheckJNI::PushLocalFrame(_JNIEnv*, int))
PopLocalFrame = {jobject (*)(JNIEnv *, jobject) | 0xb3a5625d} (libart.so`art::CheckJNI::PopLocalFrame(_JNIEnv*, _jobject*))
NewGlobalRef = {jobject (*)(JNIEnv *, jobject) | 0xb3a56bd5} (libart.so`art::CheckJNI::NewGlobalRef(_JNIEnv*, _jobject*))
DeleteGlobalRef = {void (*)(JNIEnv *, jobject) | 0xb3a572d9} (libart.so`art::CheckJNI::DeleteGlobalRef(_JNIEnv*, _jobject*))
DeleteLocalRef = {void (*)(JNIEnv *, jobject) | 0xb3a5729f} (libart.so`art::CheckJNI::DeleteLocalRef(_JNIEnv*, _jobject*))
IsSameObject = {jboolean (*)(JNIEnv *, jobject, jobject) | 0xb3a57740} (libart.so`art::CheckJNI::IsSameObject(_JNIEnv*, _jobject*, _jobject*))
NewLocalRef = {jobject (*)(JNIEnv *, jobject) | 0xb3a56b9b} (libart.so`art::CheckJNI::NewLocalRef(_JNIEnv*, _jobject*))
EnsureLocalCapacity = {jint (*)(JNIEnv *, jint) | 0xb3a57313} (libart.so`art::CheckJNI::EnsureLocalCapacity(_JNIEnv*, int))
AllocObject = {jobject (*)(JNIEnv *, jclass) | 0xb3a57b90} (libart.so`art::CheckJNI::AllocObject(_JNIEnv*, _jclass*))
NewObject = {jobject (*)(JNIEnv *, jclass, jmethodID, ...) | 0xb3a5867c} (libart.so`art::CheckJNI::NewObject(_JNIEnv*, _jclass*, _jmethodID*, ...))
NewObjectV = {jobject (*)(JNIEnv *, jclass, jmethodID, va_list) | 0xb3a580a5} (libart.so`art::CheckJNI::NewObjectV(_JNIEnv*, _jclass*, _jmethodID*, char*))
NewObjectA = {jobject (*)(JNIEnv *, jclass, jmethodID, jvalue *) | 0xb3a586a7} (libart.so`art::CheckJNI::NewObjectA(_JNIEnv*, _jclass*, _jmethodID*, jvalue*))
GetObjectClass = {jclass (*)(JNIEnv *, jobject) | 0xb3a58c7e} (libart.so`art::CheckJNI::GetObjectClass(_JNIEnv*, _jobject*))
IsInstanceOf = {jboolean (*)(JNIEnv *, jobject, jclass) | 0xb3a59090} (libart.so`art::CheckJNI::IsInstanceOf(_JNIEnv*, _jobject*, _jclass*))
GetMethodID = {jmethodID (*)(JNIEnv *, jclass, const char *, const char *) | 0xb3a599b0} (libart.so`art::CheckJNI::GetMethodID(_JNIEnv*, _jclass*, char const*, char const*))
CallObjectMethod = {jobject (*)(JNIEnv *, jobject, jmethodID, ...) | 0xb3a6a042} (libart.so`art::CheckJNI::CallObjectMethod(_JNIEnv*, _jobject*, _jmethodID*, ...))
CallObjectMethodV = {jobject (*)(JNIEnv *, jobject, jmethodID, va_list) | 0xb3a69fd9} (libart.so`art::CheckJNI::CallObjectMethodV(_JNIEnv*, _jobject*, _jmethodID*, char*))
CallObjectMethodA = {jobject (*)(JNIEnv *, jobject, jmethodID, jvalue *) | 0xb3a67197} (libart.so`art::CheckJNI::CallObjectMethodA(_JNIEnv*, _jobject*, _jmethodID*, jvalue*))
CallBooleanMethod = {jboolean (*)(JNIEnv *, jobject, jmethodID, ...) | 0xb3a69f6f} (libart.so`art::CheckJNI::CallBooleanMethod(_JNIEnv*, _jobject*, _jmethodID*, ...))
CallBooleanMethodV = {jboolean (*)(JNIEnv *, jobject, jmethodID, va_list) | 0xb3a69f05} (libart.so`art::CheckJNI::CallBooleanMethodV(_JNIEnv*, _jobject*, _jmethodID*, char*))
CallBooleanMethodA = {jboolean (*)(JNIEnv *, jobject, jmethodID, jvalue *) | 0xb3a6712d} (libart.so`art::CheckJNI::CallBooleanMethodA(_JNIEnv*, _jobject*, _jmethodID*, jvalue*))
CallByteMethod = {jbyte (*)(JNIEnv *, jobject, jmethodID, ...) | 0xb3a69e9b} (libart.so`art::CheckJNI::CallByteMethod(_JNIEnv*, _jobject*, _jmethodID*, ...))
CallByteMethodV = {jbyte (*)(JNIEnv *, jobject, jmethodID, va_list) | 0xb3a69e31} (libart.so`art::CheckJNI::CallByteMethodV(_JNIEnv*, _jobject*, _jmethodID*, char*))
CallByteMethodA = {jbyte (*)(JNIEnv *, jobject, jmethodID, jvalue *) | 0xb3a670c3} (libart.so`art::CheckJNI::CallByteMethodA(_JNIEnv*, _jobject*, _jmethodID*, jvalue*))
CallCharMethod = {jchar (*)(JNIEnv *, jobject, jmethodID, ...) | 0xb3a69dc7} (libart.so`art::CheckJNI::CallCharMethod(_JNIEnv*, _jobject*, _jmethodID*, ...))
CallCharMethodV = {jchar (*)(JNIEnv *, jobject, jmethodID, va_list) | 0xb3a69d5d} (libart.so`art::CheckJNI::CallCharMethodV(_JNIEnv*, _jobject*, _jmethodID*, char*))
CallCharMethodA = {jchar (*)(JNIEnv *, jobject, jmethodID, jvalue *) | 0xb3a67059} (libart.so`art::CheckJNI::CallCharMethodA(_JNIEnv*, _jobject*, _jmethodID*, jvalue*))
CallShortMethod = {jshort (*)(JNIEnv *, jobject, jmethodID, ...) | 0xb3a69cf3} (libart.so`art::CheckJNI::CallShortMethod(_JNIEnv*, _jobject*, _jmethodID*, ...))
CallShortMethodV = {jshort (*)(JNIEnv *, jobject, jmethodID, va_list) | 0xb3a69c89} (libart.so`art::CheckJNI::CallShortMethodV(_JNIEnv*, _jobject*, _jmethodID*, char*))
CallShortMethodA = {jshort (*)(JNIEnv *, jobject, jmethodID, jvalue *) | 0xb3a66fef} (libart.so`art::CheckJNI::CallShortMethodA(_JNIEnv*, _jobject*, _jmethodID*, jvalue*))
CallIntMethod = {jint (*)(JNIEnv *, jobject, jmethodID, ...) | 0xb3a69c20} (libart.so`art::CheckJNI::CallIntMethod(_JNIEnv*, _jobject*, _jmethodID*, ...))
obj = {jobject | 0xbfcc426c} 0xbfcc426c

SuperpoweredExample()之前调用returnInt()。因此,您正在取消引用一个NULL指针example

此外,您没有从声明为返回jint的函数中返回任何内容

您需要:

extern "C" JNIEXPORT jint Java_com_superpowered_crossexample_MainActivity_returnInt(JNIEnv * __unused javaEnvironment, jobject __unused obj) {
return example->returnInt();
}