Android native C++ function call cause application crash - android

I have Android app, where I need to use C++ code. But I realised, I have problem to call C++ function. I have read something about it and tried to write something, I thought it could work. Here is my code:
private native int test(int a);
private void process() {
int ret=test(5);
Toast.makeText(this, String.valueOf(ret), Toast.LENGTH_LONG).show();
}
And my C++ code is:
#include <jni.h>
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_woodem_woodem_1opencvgrains_Main_test(JNIEnv *env, jint a)
{
return a*a;
}
Of course, my real function is much more complicated and I need to pass about 6 arguments, but I hope, this can illustrate.
NOTE: Even this code doesn't work to me.
My application crash immediately after calling process(). Could you please advice me, what am I doing wrong? Compiler tells me nothing and I have no idea, where the problem is.

You are forgetting about the second argument. For example method void test() will have JNI signature JNIEXPORT void JNICALL Java..._test(JNIEnv *env, jobject thiz). In your case, edit signature to (JNIEnv *env. jobject thiz, jint a).
Edit
The previous version showed a signature for a static function. I've updated it to match instance function.
For static signature is (JNIEnv *env, jclass clazz).

You've declared your native function as private native int test(); passing an integer argument to it.
It should be private native int test(int num);

Related

SIGILL in GetMethodID while "Evaluate Expression" is OK

I want to call back Java code from native code.
The Java code:
public final class Underlying {
public static native int setOnEventListener(OnEventListener listener);
public interface OnEventListener {
int EVENT_TEST = 1;
int onEvent(int code, String msg);
}
}
The C++ code (I omit some checks to make it clear):
extern "C" JNIEXPORT jint JNICALL
Java_packageName_Underlying_setOnEventListener(JNIEnv* env, jclass type, jobject listener) {
jclass clz = env->GetObjectClass(listener);
// assign to static jobject
eventListener = env->NewGlobalRef(listener);
// assign to static jmethodID
onEventMethodID = env->GetMethodID(clz, "onEvent", "(ILjava/lang/String;)I");
}
SIGILL (signal SIGILL: illegal instruction operand) occurs in GetMethodID. But I evaluate the same sentence by Evaluate Expression in Android Studio and everything is OK.
There must be some differences between reality and Evaluate Expression. One difference I could think of is that the calling thread may be different. setOnEventListener was originally called in UI thread, so I created a new thread to do this, but nothing changed.
I found two things lead to this error.
The return type is jint, then a jint must be returned.
In Android Studio, Make Project sometimes doesn't rebuild the C++ code to APK, Rebuild Project is needed in this situation.

Bad values being pass in android jni calls

This is driving me crazy! I'm making a library with ndk, the linking was fine but I find that, when calling a method, the value of the argument passed to the corresponding c function is incorrect.
My java class is as follows
package ccme.usernet.love;
class LovePlayerEngine {
static {
System.loadLibrary("loveplayer");
}
public static native void init(int id);
}
And my C file is as follows:
#include <jni.h>
#include <android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "TEST", __VA_ARGS__))
JNIEXPORT void JNICALL Java_ccme_usernet_love_LovePlayerEngine_init(JNIEnv *env, jint id)
{
LOGI("INIT with id %d\n", id);
}
The compiling and library linking was fine and the app was running.
But when I called LovePlayerEngine.init(0); somewhere in my java code, I get some bad values such as 1079062016 which is not stable and will change on different runs.
My other tests such as passing variables instead of constants or passing a String all failed in getting unexpected values.
Anyone has got any clue of where the problem could be? This is sickin me, I've never encountered this in my former ndk projects.
You're missing a parameter in your call. It should be JNIEXPORT void JNICALL Java_ccme_usernet_love_LovePlayerEngine_init(JNIEnv *env, jobject obj, jint id)
The missing parameter means you're using the object as the int value by mistake.
Gabe Sechan's answer will get you up and running for now, but the second parameter for static methods is jclass, not jobject.
Java_ccme_usernet_love_LovePlayerEngine_init(JNIEnv *env, jclass cls, jint id)

Android/Cocos2d-x unsatisfiedlinkerror using JNI using Java to call C++

EDIT: I've solved this problem (and found the next issue in the long line of JNI tribulations!) by changing the following:
Delete "static" declaration of the native method in both Java and C++, add a Java method to get an instance of my SimpleGame class, and calling
public static void callCppApiResponse (String result, String token, long context) {
**getInstance()**.cppAndroidApiResponse(token, 200, result, result.length(), context);
}
Now the information successfully makes it from Java to C++. Hopefully this may help someone else with a similar issue.
ORIGINAL POST:
I'm using the Cocos2d-x platform and writing C++ code for a cross-platform iOS/Android app, and there are certain methods that I need to be handled by the respective native iOs/Android systems, so I need to be able to call Java from C++ then call C++ from Java.
I am able to load the shared library for the app and trigger a Java response from C++, but when I try to call C++ from Java I get the following logcat output and the app crashes:
dalvik vm No implementation found for native Lorg/cocos2dx/simplegame/SimpleGame; cppSideAndroidApiResponse:(Ljava/lang/String;ILJava/lang/String;IJ)V
AndroidRuntime java.lang.UnsatisfiedLinkError: Native method not found: org.cocos2dx.simplegame.SimpleGame.cppAndroidApiResponse:(Ljava/lang/String;ILJava/lang/String;IJ)V
Here is the relevant Java code:
package org.cocos2dx.simplegame;
private static native void cppAndroidApiResponse(String token, int response, String data, int dataLen, long context);
static {
System.loadLibrary("sb");
}
public static void callCppApiResponse (String result, String token, long context) {
//This is where the error is triggered
cppAndroidApiResponse(token, 200, result, result.length(), context);
}
and in the C++ file cppSide.h:
# if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "platform/android/jni/JniHelper.h"
#include <jni.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
# if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
JNIEXPORT static void JNICALL
Java_org_cocos2dx_simplegame_SimpleGame_cppAndroidApiResponse(JNIEnv *, jobject, jstring, jint, jstring, jint, jlong);
#endif
#ifdef __cplusplus
}
#endif
Then finally the cppSide.cpp file
#include "cppSide.h"
extern "C" {
JNIEXPORT static void JNICALL
Java_org_cocos2dx_simplegame_SimpleGame_cppAndroidApiResponse(JNIEnv *env, jobject obj, jstring token, jint response, jstring data, jint length, jlong context)
{ ...do stuff...}
}
I know that my shared library is loading because I get my C++ based loading screen, and I know that JNI is working at least partially because I am able to call Java from that same cppSide.cpp file in another method. I have been researching the JNI and Cocos2d-X documentation, but to no avail.
Thanks in advance!

What is "jobject thiz" in JNI and what is it used for?

I am having a hard time finding an answer to this. But, what is "jboject thiz" used for in JNI function calls? For example:
jobjectArray Java_com_gnychis_awmon_Test( JNIEnv* env, jobject thiz ) {
I use env to allocate objects often, but I've never used thiz and I'm not sure what it is for. Just for knowledge purposes.
The following is a JNI wrapper function which has two parameters, and returns a primitive array of objects:
jobjectArray Java_com_gnychis_awmon_Test( JNIEnv* env, jobject thiz );
From the function name you have given I don't think it is complete, that is, you haven't respected the obligatory function name convention which is:
Start the function with Java_
Append the package name separated by _ (undescores) i.e. com_company_awesomeapp. So far the function name is composed of: Java_com_company_awesomeapp
Append the Java class name where the native method has been defined,
followed by the actual function name. So at this point we should have the following function name: Java_com_company_awesomeapp_MainActivity_Test
The first parameter is a pointer to a structure storing all JNI function pointers, i.e. all the predefined functions you have available after you #include <jni.h>.
The second parameter is a reference to the Java object inside which this native method has been declared in. You can use it to call the other methods of the Java object from the current JNI function, i.e. Call Java instance methods from JNI code written in C or C++.
If for example you have the following Java class inside the MainActivity.java file:
public class MainActivity extends Activity
{
static
{
try
{
System.loadLibrary("mynativelib");
}
catch (UnsatisfiedLinkError ule)
{
Log.e(TAG, "WARNING: Could not load native library: " + ule.getMessage());
}
}
public static native Object[] Test();
}
Then, the jobject thiz parameter of the JNI function would be a reference to an object of type MainActivity.
I found this link that should help clarify the question.
https://library.vuforia.com/articles/Solution/How-To-Communicate-Between-Java-and-C-using-the-JNI
Here is an example in it that uses the "jobject".
JNIEXPORT void JNICALL
Java_com_qualcomm_QCARSamples_ImageTargets_ImageTargets_initApplicationNative(
JNIEnv* env, jobject obj, jint width, jint height)
{
...
jclass activityClass = env->GetObjectClass(obj);
jmethodID getTextureCountMethodID = env->GetMethodID(activityClass,
"getTextureCount", "()I");
if (getTextureCountMethodID == 0)
{
LOG("Function getTextureCount() not found.");
return;
}
textureCount = env->CallIntMethod(obj, getTextureCountMethodID);
...
}
jobject thiz means the this in java class.
Sometimes if you create a static native method like this.
void Java_MyClass_method1 (JNIEnv *, jclass);
jclass means the class itself.

loadNativeCode not registered

I try to get a android app running, which implements part of it's code in native.
It does find the shared library, but when it attempts to run it in the Emulator and it calls loadNativeCode I get:
AndroidRuntime(1342): java.lang.UnsatisfiedLinkError: loadNativeCode
As far as I traced the code it seems to miss a call to register_android_app_NativeActivity which sets up the loadNativeCode mapping. But since this is done in the runtime I have no clue why it does not work.
JNI
loadNativeCode native function MUST format as:
Static way:
JNIEXPORT void JNICALL Java_com_tapir_android_jniutils_test_MainActivity_emptyf(JNIEnv *env, jobject obj)
{
...
}
package name is com.tapir.android.jniutils.test
class name is MainActivity
function name is emptyf
Dynamic way,use RegisterNatives to register your native function in JNI_onLoad function
JNINativeMethod nm;
nm.name = "emptyf";
/* method descriptor assigned to signature field */
nm.signature = "()V";
nm.fnPtr = native_emptyf;
env->RegisterNatives( cls, &nm, 1);
native_emptyf MUST like as
void native_emptyf(JNIEnv *env, jobject obj)
{
...
}
hope can help u

Categories

Resources