How are the static variables in C++ code managed with JNI? - java

My question is, Assume I have a c++ class with singleton and through JNI methods I call this singleton, does each time I call from java to c++ the singleton variable changed because its static, or it remains the same ? and does each time I call from java to c++ it run the method on new thread or no?
Example Code:
in Java:
class NativeLib
{
public native void updateFrame();
}
in C/C++ :
JNIEXPORT void JNICALL Java_com_Company_NativeLib_NativeLib_updateFrame()
{
sceneManager::getInstance()->updateFrame();
}
Does sceneManager::getInstance() at each call return new instance or the latest created instance since its a static variable.
my main problem in android my app crash without showing any kind of logCat information why it crashed.
but if I comment the sceneManager::getInstance()->updateFrame(); , it never crash so what I think is when ever Java make a call to C++ it is in a new thread which mean static variables does not

Think of the VM as a library of C/C++ code that your application has called into. Sometimes it calls back into your code.
Singletons will not be recreated -- it's just a method call. The Dalvik VM threads are just pthreads, and whichever thread executes the native call from Java-language code will be the thread that executes your C++ code.
Your best bet is to attach a native debugger. FWIW, one way to crash with nothing in logcat is to have native recursion that overflows the stack. Another way is to change the signal handlers for SIGSEGV / SIGBUS and friends.

Related

How To Call JAVA Methods from inside of a Thread in JNI

TL;DR; I'm having a problem with passing my FFMPEG raw data from C++ code to JAVA code, for displaying, through a thread.
There is a server set up that sends out encoded frames to its clients. Those encoded frames are encoded with some FFMPEG magic. When received on client side, the fore-mentioned frames are getting decoded into raw RGB data (as a unsigned char *). The problem now is that frames are being received in a "listener" of sorts. Just a thread running in the background polling the server and running specific onFrame function once a new frame is available.
The current solution for displaying the frames in a video-format is to save each frame to internal storage in C++, and then have a FileObserver on java side that displays an image as soon as it's written in the memory. Sadly, that approach yields a 6 FPS video on phone, for a 10 FPS video from Server.
I need a way of passing that unsigned char * (jbytearray) to my JAVA code so I can decode it and display it from RAM rather than Disk.
It's worth mentioning that onFrame function cannot have JNIEnv* && jobject inside it's arguments list (Library requirements).
What I have tried so far is making a native method in my MainActivity through which I pass JNIEnv and jobject and assign those to global variables
JNIEnv* m_globalEnv = env;
jobject m_globalObject = thiz;
JavaVM m_jvm = 0;
jclass mainActivity = m_globalEnv->GetObjectClass(m_globalObject);
jmethodID testMethod = m_globalEnv->GetMethodID(mainClass, "testMethod", "(I)V");
m_globalEnv->GetJavaVM(&m_jvm);
After that, in my onFrame I call
jvm->AttachCurrentThread(&m_globalEnv, NULL);
And then I try to call a JAVA method from somewhere inside the code (It's irrelevant where/when in the onFrame I call it) by doing:
m_globalEnv->CallVoidMethod(m_globalObject, "testMethod", 5);
And then all crashes with either:
1- JNI DETECTED ERROR IN APPLICATION: use of invalid jobject 0xffe8ea7c
2- JNI DETECTED ERROR IN APPLICATION: Thread is making JNI calls without being attached
.
.
.
EDIT 1
After Trying out the code from Michael's solution, I got the
java_vm_ext.cc:542] JNI DETECTED ERROR IN APPLICATION: use of invalid jobject 0xc94f7f8c error.
After running the app in debug mode to catch the error, I got to the jni.h; Line of code that triggers the error is:
m_env->CallVoidMethod(m_globalObject, testMethod, 5);
(5 being the number I am trying to pass for testing purposes).
The line of code inside jni.h that is being highlighted by the debugger is inside of
void CallVoidMethod(jobject obj, jmethodID methodID, ...)
and it's
functions->CallVoidMethodV(this, obj, methodID, args);
which is defined on line 228:
void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);
I see two potential issues with the code:
1. Sharing a JNIEnv* across threads
Each native thread should obtain its own JNIEnv* by attaching itself to the JVM, and then detaching itself at some point. See this answer for more details and possible solutions.
2. Caching local references
The thiz reference you receive as the second argument to a native function is a local reference, as are most of the jobjects returned from calling JNI functions.
A local reference is usable only "from the thread it was originally handed to, and is valid until either an explicit call to DeleteLocalRef() or, more commonly, until you return from your native method".
If you want to use that object from another thread you need to create a global reference from the local reference:
m_globalObject = NewGlobalRef(thiz);
Remember to delete the global reference (DeleteGlobalRef(m_globalObject)) when you no longer need to use that object anywhere in your native code. Otherwise you may cause a memory leak.

SIGSEV when calling JAVA callback method from native code after multiple calls

I am using JNA to pass a callback function from Java to native code. I am able to call the java inteface method ok, the problem is after about 40 calls of the function i get a SIGSEV and the program terminates.
The SIGSEV occurs at the line when the native code calls the method.
Is this related so some garbage collection on the Java function handle? Is there a way to prevent this?
Note: The closest thread on the sight was "SIGSEV when calling Java method from native pthread". He seemed solve his problem on the native side though by making things global.
I have tried making the java method synchronous but this has not helped. I also modified the native call to launch a pthread and then call the java method. When doing this, the method can be called maybe 1000 times then i get the SIGSEV
on the java side I have
public interface handler extends Callback {
void invoke();
}
static class test_start implements handler {
public synchronized void invoke() {
System.out.println("Hello");
}
}
You are right, that you suspect GC to be your problem, which is also documented in JNA.
Summary: You'll need to keep a strong reference to your Callback Handler on the java side to prevent garbage collection.
The implementation is highly dependent on your architecture. If your handler is global, you can save it in a static field (GC will normally collect static field data only when class is unloaded). If your handler is tied to a concrete java class, you could use a static WeakHashMap to keep the reference until the java object is collected (assuming this also indicates, that the native side will not call the handler anymore). If the handler is tied to a fixed lifecycle, I would implement an AutoCloseable helper object, that unregisters your handler on close.
It should be noted, that in all implementations, you must make sure that your handler is kept referenced. For the AutoClosable implementation running Reference#reachabilityFence​ from the close method after the handler is unregister would be a sane decision.

Notifying java object from C/C++ code?

I am wondering is it possible to notify( notify() ) a java object with native code?
For example let's say we have a thread in java which is waiting for a signal as below.
void _do_something() throws Exception{
synchronized(__lock_){
__lock_.wait();
}
}
Then is it possible to notify the __lock_ object from a native code?!
Should I pass the __lock_ object to the c code? so how and how C code call the notify() method.
Any help is appreciated.
Thanks in advance.
This is very doable from native code. You need to use JNI though...
Then is it possible to notify the _lock object from a native code?!
Sure, as long as your native code has a handle to the _lock object, all you have to do is to synchronize and call notify on it (like you would call any other java object from native code).
Should I pass the _lock object to the c code?
Yes. Both because you need it when you call the CallVoidMethod() JNI function to call notify() but also because you need to enter/exit Monitor of that object (the JNI equivalent way of saying "synchronized(_lock)"
so how and how C code call the notify() method
First you need to understand the basics of mapping your native code to something you can call from java. Then you need to understand how to call back into java from that native code and when you understand that, it is all a matter of learning how to use MonitorEnter, CallVoidMethod and MonitorExit.
Unfortunately, JNI sometimes seems to be designed to keep people away. When you're new at it, it is kind of hard to do proper debugging. I would recommend to start small to get a grip of it and wait with the real stuff until you understand the basics.
My best advice with JNI is to stick to the rules (at least in the beginning), check exceptions after every call (and dump them to stderr or something when you get them) and run your java with -Xcheck:jni.
There are plenty of tutorials around, I found this one in the top10-list when I googled, it seems ok.
Good luck!

Attaching third party thread to vm when using jni

I'm writing a Java program that uses a hardware driver written in c. This hardware driver starts a callback thread, and you can register callback functions to be called when stuff happens. How can I attach this thread to the jvm so that it can call the Java methods for these callbacks? I only have the thread id returned from the start_callbacks() function, returned as an int, but it is the pthread_t used in the call to pthread_create().
One way I found is to use pthread_once on the start of every callback function and attach the thread there. But then there is no way to detach it. I tried to use pthread_cleanup_push/pop, but they need to be called as a pair so that didn't work.
It seems to me that my only option to do this right is to attach and detach the thread at every callback call. Or rewrite the driver somewhat, which I really don't want to do.
Is there something I missed?
That's exactly what the JNI calls AttachCurrentThread() and DetachCurrentThread() are for.
The solution to you problem can be resolved with thread_local storage (C++ 11 and higher). This allows you to attach to an arbitrary thread, and then it will automatically detach when the thread exist (even when you didn't create the thread and have no control over it's life cycle).
A sample example of how to implement that in C++ can be found in my answer here:
https://stackoverflow.com/a/59934966/8367574

JNI Global Static Variables in C++ Code

I have a JNI C++ code being called from a multi-threaded java application
This C++ code has 2 global static variables a boolean and a string.
For some reason i keep getting segmentation fault from this code . Any idea what could lead to this ? I know this is not thread safe, but i am treating the variables as read only from the java application and only the C++ code is able to modify the values of these variables
Help much appreciated
EDIT : This code runs on a Linux machine . And runs for months at a time without any issues, then it issues a signal 11 segmentation fault and the JVM crashes.
If you're calling the C++ code from multiple threads, and the C++ code has global static variables, then it would be amazing if it worked. The simplest thing to try is to put a lock around the call, i.e. in the Java side change
native int callToCppFunction(int parameter);
to
synchronized native int callToCppFunction(int parameter);
to ensure that only one thread can be in the C++ code at a time.
Then there's another possible issue, which I bumped on about a year ago: apparently in Windows dlls it may not be enough to serialize calls to it (i.e. use synchronized). They may also require to be called from the same thread each time. This answer offers an explanation to how that can be. The solution is to make a single threaded executor to the Java side, and route all calls to the native code through it.

Categories

Resources