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

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.

Related

Make Java calls from JNI during native signal handling

I implement a custom POSIX signal handler
Ref : http://blog.httrack.com/blog/2013/08/23/catching-posix-signals-on-android/
Their appears to be a platform limitation with ART.
Is there a work around or any other way to achieve, calling java method from JNI through the signal handler method.
If not then is there an alternative scheme to catch the native crash and propagate to the app ?
First of all - you should be very carefully with what you doing in signal handler. Also there is a list of functions that you can safely invoke from there, look for "Async-signal-safe functions". And surely you shouldn't invoke anything outside of that list or anythyng via JNIEnv because you don't know what JVM does under the hood.
As result there is no way to propagate error to the app. You can just write anything you want to some file with write() and then test this file at next launch.

Activity instance changing per tick in JNI

I have an Android lifecycle question that I can't find answered anywhere else.
(This is not a question about making the activity class a global ref)
I'm using the standard JNI->Native Init() and Tick() calls to run the game on the native side. Very similar to the San Angeles demo.
I pass both of these calls a instance of the Java Activity object. This is so I can call back
to Java in order to (for example, turn adverts off, interact with the Java Twitter, etc).
Q1 : When I call Tick() to call my native calls, does this create a new thread, if so, why don't I have to call DetachCurrentThread from the native side?
Q2: I've tried caching the Activity instance on my Native Init() function and storing this in a static. This works on some devices, but on pre-android 5.0 device I get a stale reference JNI error when I use the instance in the Tick() function. Will making this a global 'reference' like I do for the activity 'class' in my OnLoad() function sort this?
Q3: When the user closes the interstitial adverts, I get a callback on the Java side, which I pass to the native side (eg, to restart the music). Does this create a new Native thread? Will my previously cached Activity instance still be valid?
Many thanks,
Steve.
Ok found my own answers.
1.No.
2.Yes, do the GlobalReference thing.
3.No, but the the Java side a a new thread.

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

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.

Accessing global C variable from java

I'm calling a C function that resides in a dll from a java thread. This C function runs indefinitely and processes video frames in real time, outputting a result for each frame.
I want to spawn another java thread to read the results from the processing function without interrupting the function. I also need to implement some kind of thread control to protect from reading corrupted data.
Any ideas?
The global is controlled by your C environment.
I suspect that you should do this:
Create a function that returns the value of the global variable and call it from java using JNI.
Implement your synchronization stuff in C.
You can embed your C function in a executable that will be started by your java thread. The C function can post results into a pipe or send them through a socket to your java thread. This gives you the flexibility to even have your C function running on one machine and the java thread on another.

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