I'm trying to call a JNI function from my Java code in an android app,
The function is called but the parameters value in the JNI function is not the same as the one passed in the function.
here are my java declaration and call:
public native void setIA(Integer model);
setIA(1);
and here is my JNI function
extern "C" JNIEXPORT void JNICALL
Java_com_sfy_vitaltechnics_Utils_Parameters_setIA(JNIEnv *env, jobject thiz, jint model) {
LOGD( "This is a number from JNI: %d", model );
}
I get value like -578062932 but it's never the same value.
I tried several cast and type of arguement(long, double, float, string and thir java equivalent).
and everytime it give me weird value(for string it give me non UTF-8 character)
I think the problem come from my way of declaring the function but I'm not sure
Integer corresponds to jobject in C, so you should either alter C function or change java declaration to setIA(int model); to match existing C function.
Related
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.
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)
I want to know how to get a custom object from Java to c++?
I need to implement a method in c++ for get performance. I already have the method working in java but I want to port to c++.
On Java a I call the method like this:
private native boolean P(Mat Previous, String Name);
On CPP file I need to get the mat object. Getting string is easy! But how can I get the custom mat object similar to c++(cv::Mat)? I need to get java Mat into a cv::Mat.
Here the cpp file:
JNIEXPORT bool JNICALL Java_br_raphael_detector_SimpsonDetector_P
(JNIEnv* env,jobject thiz, jobject Previous, jstring Name){
jboolean sim = false;
const char* N = env->GetStringUTFChars(Name,0);
std::string Nome = N;
//Release
env->ReleaseStringUTFChars(Name,N);
//Then Return
return sim;
}
A java Mat object is a totally different thing from a native cv::Mat, you can't get one directly from the other.
That said, if you know what fields are inside Mat, and you know the corresponding fields in cv::Mat, you can write a conversion function that copies the contents of the fields one-by-one.
// First get the Mat class
jclass Mat = (*env)->GetObjectClass(env, Previous);
// To get a field
jfieldId field = (*env)->GetFieldID(env, Mat, "fieldName", field type);
// To get a method
jmethodId method = (*env)->GetMethodID(env, Mat, "methodName", method signature);
from there you can read the values of fields, or call methods
// getting a field
(*env)->GetObjectField(env, Previous, field);
// calling a method
(*env)->CallObjectMethod(env, Previous, method, parameters);
refer to http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html for details
I'm one year late to the party, but the way you pass a Mat to C is with a jlong with the address of the Java's Mat. You can do something like this:
private static native boolean P(long matAddress, String name);
In C:
JNIEXPORT jboolean JNICALL Java_br_raphael_detector_SimpsonDetector_P
(JNIEnv* env,jobject thiz, jlong matAddress, jstring Name)
{
cv::Mat* image = (cv::Mat*)matAddress;
// Do stuff with image.
}
Then you would call the method in Java like this:
P(myMat.getNativeObjAddr(), name);
OpenCV exposes this method just for cases like this. (I would link to the documentation's page but the website is not loading here, sorry.)
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.
I want to call the Java method from Jni code with the int and int[] arguments. for that i have Go-ogled and found the following sample .
Calling a java method from c++ in Android
And it worked fine with String parameter . But While trying with int i got issues .
Please help me .
JNI CODE:
jstring Java_com_calljavafromjni_MainActivity_getJniString( JNIEnv* env, jobject obj){
jstring jstr = (*env)->NewStringUTF(env, "RAJESH TEST from JNI ");
jint sss=1111;
jclass clazz = (*env)->FindClass(env, "com/calljavafromjni/MainActivity");
jmethodID messageMe = (*env)->GetMethodID(env, clazz, "messageMe", "(Ljava/lang/String;)Ljava/lang/Integer;");
jobject result = (*env)->CallObjectMethod(env, obj, messageMe, sss);
const char* str = (*env)->GetStringUTFChars(env,(jstring) result, NULL); // should be released but what a heck, it's a tutorial :)
printf("%s\n", str);
return (*env)->NewStringUTF(env, str);
}
Java code
public String messageMe(Integer text) {
System.out.println( "aaaaaaaaaaaaaaaa "+text);
return "test";
}
I don't see where int[] come into your problem, but with int it should be easy to solve.
You need to look at your GetMethodId() call, specifically the method signature argument (the last one). The JNI Specification provides a list of all its Type Signatures here. That should also help you when you eventually come to pass your int arrays too.
So we can see at the moment your signature is:
String messageMe(Integer text)
but you told JNI it was (Ljava/lang/String;)Ljava/lang/Integer; which translates to something like:
java.lang.Integer messageMe(String text)
The Type Signatures show us that the signature for an int is simply I so your argument for GetMethodId() should be something like this:
jmethodID messageMe = (*env)->GetMethodID(env, clazz, "messageMe", "(I)Ljava/lang/String;");
I hope that helps. As I said before, JNI isn't the easiest thing to get into but the answers really are all in the Specification, you just have to look quite hard.
EDIT: I corrected my signature.
Basically, you were almost there - you just got the arguments and return value the wrong way around in the signature. It should be (<arguments>)<return type>. You also made the easy mistake of specifying the class for Integer, instead of the primitive type.