Calling Java Methods from JNI results in program crash - java

Calling get or set methods crashes. Object array is valid. It prints till line 2.Intially was getting error while inserting into the jobjectArray .Also tried with getting the value from Jobject .Both getter and setters fail .
JNICode is as below :
JNIEXPORT jint JNICALL Java_demo_JNIWrapper_pax_1store_1get_1data_1avail_1info
(JNIEnv *env, jclass jclass1, jobjectArray jobj)
{
.....
.....
int len = (*env)->GetArrayLength(env, jobj);
printf ("Incoming object array length = %d\n", len);// - - - > Works.. shows 2 (I am passing 2 objects)
jobject j = (*env)->GetObjectArrayElement(env, jobj,0);
printf("This line 1 \n ");
jmethodID meth1=(*env)->GetMethodID(env,jclass1,"getTimestamp","()Ljava/lang/String;");
printf("This line 2 \n "); // - - - - > Works..
jstring string_from_obj = (*env)->CallObjectMethod(env,j,meth1); // - - - - > Crashes..
printf("This line 3 \n "); // - - -> does not print this..
printf("Contents are =%s\n",(*env)->GetStringUTFChars(env, string_from_obj, 0));
............
}
My Java Object is as Below :
public class DataAvailable {
String timestamp;
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
}
Call to JNI is as below :
public native int pax_store_get_data_avail_info(DataAvailable[] stats_array);

The glaring issue is that pax_store_get_data_avail_info() is not a method of DataAvailable. It is a method of some other class? You don't actually say what it is. But let's suppose it is:
class X {
public native int pax_store_get_data_avail_info(DataAvailable[] stats_array);
}
When you call this method, the jclass jclass1 argument you get is for "X", not for DataAvailable. So your call to GetMethodID() probably fails. You don't check the return, so you re probably handing a bad method ID to the next call. JNI fails are hard crashes and very ugly.
You need to query the jclass for DataAvailable and use that.

Related

SIGSEGV when calling Java method from native pthread

In a Java project that uses C code via JNI I have a piece of native C code that obtains references to an object and one of its methods, then starts a native thread, passing these references to it in a struct. When the thread tries to call the method, the code crashes with a SIGSEGV. Calling that same method from the main thread works.
Doing some research I learned that the env reference is only valid within the thread and that any other native thread must be attached first. I did this but the code still crashes on the first call to the method.
Strangely, when I call the same method from the main thread before I create the other thread (just uncomment the line in the main code), things work for some time. The output thread loops for some 10,000 times before it crashes.
The method call is to DataOutputStream.writeShort(). The thread in question is the only one writing to the DataOutputStream. However, the DataOutputStream is connected to a DataInputStream.
Simplified native code:
static void write_output(struct output_state *s) {
int i;
jint sample;
for (i = 0; i < 2 * s->result_len; i += 2) {
sample = (s->result[i] << 8) + s->result[i+1];
(*(s->env))->CallVoidMethod(s->env, s->tunerOut, s->writeShort, sample);
}
}
static void *output_thread_fn(void *arg)
{
struct output_state *s = arg;
(*(s->jvm))->AttachCurrentThread(s->jvm, &(s->env), NULL);
while (!do_exit) {
// use timedwait and pad out under runs
safe_cond_wait(&s->ready, &s->ready_m);
pthread_rwlock_rdlock(&s->rw); //sync access to s with producer thread
write_output(s);
pthread_rwlock_unlock(&s->rw);
}
(*(s->jvm))->DetachCurrentThread(s->jvm);
return 0;
}
JNIEXPORT jboolean JNICALL Java_eu_jacquet80_rds_input_SdrGroupReader_open
(JNIEnv *env, jobject self) {
jclass clsSelf = (*env)->GetObjectClass(env, self);
jfieldID fTunerOut = (*env)->GetFieldID(env, clsSelf, "tunerOut", "Ljava/io/DataOutputStream;");
jobject tunerOut = (*env)->GetObjectField(env, self, fTunerOut);
jclass cls = (*env)->GetObjectClass(env, tunerOut);
jmethodID writeShortID = (*env)->GetMethodID(env, cls, "writeShort", "(I)V");
if (!writeShortID || !cls)
return 0;
(*env)->GetJavaVM(env, &(output.jvm));
output.tunerOut = tunerOut;
output.writeShort = writeShortID;
// (*env)->CallVoidMethod(env, tunerOut, writeShortID, 0); // just for testing
pthread_create(&controller.thread, NULL, controller_thread_fn, (void *)(&controller));
usleep(100000);
pthread_create(&output.thread, NULL, output_thread_fn, (void *)(&output));
pthread_create(&demod.thread, NULL, demod_thread_fn, (void *)(&demod));
pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void *)(&dongle));
return 1;
}
Are JNI references such as jclass, jfieldID, jobject and jmethodID subject to the same limitations as JNIEnv, i.e. valid only within the same thread?
Suspecting this, I moved the JNI reference stuff from open() to output_thread(), right after the call to AttachCurrentThread(). However, I still need to pass a jobject reference (self) across thread borders, and the call to GetObjectClass() crashes.
What is the correct way to create a thread native code and have that thread call a particular method of a given class instance?
Turns out my suspicion was correct: jobject and jclass references are indeed local, i.e. valid only within the same thread and only until the current native method returns. See http://developer.android.com/training/articles/perf-jni.html#local_and_global_references.
My approach of moving the reference-related code to the thread function was correct, except that I need to first convert self into a global reference by calling NewGlobalRef().
Updated code:
static void write_output(struct output_state *s) {
int i;
jint sample;
for (i = 0; i < 2 * s->result_len; i += 2) {
sample = (s->result[i] << 8) + s->result[i+1];
(*(s->env))->CallVoidMethod(s->env, s->tunerOut, s->writeShort, sample);
}
}
static void *output_thread_fn(void *arg)
{
struct output_state *s = arg;
(*(s->jvm))->AttachCurrentThread(s->jvm, &(s->env), NULL);
jclass clsSelf = (*(s->env))->GetObjectClass(s->env, s->self);
jfieldID fTunerOut = (*(s->env))->GetFieldID(s->env, clsSelf, "tunerOut", "Ljava/io/DataOutputStream;");
s->tunerOut = (*(s->env))->GetObjectField(s->env, s->self, fTunerOut);
jclass cls = (*(s->env))->GetObjectClass(s->env, s->tunerOut);
s->writeShort = (*(s->env))->GetMethodID(s->env, cls, "writeShort", "(I)V");
while (!do_exit) {
// use timedwait and pad out under runs
safe_cond_wait(&s->ready, &s->ready_m);
pthread_rwlock_rdlock(&s->rw); //sync access to s with producer thread
write_output(s);
pthread_rwlock_unlock(&s->rw);
}
(*(s->jvm))->DetachCurrentThread(s->jvm);
return 0;
}
JNIEXPORT jboolean JNICALL Java_eu_jacquet80_rds_input_SdrGroupReader_open
(JNIEnv *env, jobject self) {
jclass clsSelf = (*env)->GetObjectClass(env, self);
if (!writeShortID || !cls)
return 0;
output.self = (*env)->NewGlobalRef(env, self);
(*env)->GetJavaVM(env, &(output.jvm));
(*env)->CallVoidMethod(env, tunerOut, writeShortID, 0); // just for testing
pthread_create(&controller.thread, NULL, controller_thread_fn, (void *)(&controller));
usleep(100000);
pthread_create(&output.thread, NULL, output_thread_fn, (void *)(&output));
pthread_create(&demod.thread, NULL, demod_thread_fn, (void *)(&demod));
pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void *)(&dongle));
return 1;
}
One thing still missing is a call to DeleteGlobalRef() when the output thread is done. This is to make sure the global reference is released when it is no longer needed, so that the garbage collector can pick it up.

Parameter passing in native a method [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
jni converting jstring to char *
There is a function on ะก (traverser.c module)
long int
Traverser(const char * sTraversingRoot)
{
long int nCount;
struct stat rStatBuf;
time_t nTime;
char sActualPath[512];
PGconn *pConn;
// Open DB connection
sprintf(sConnInfo,
"hostaddr=%s port=%s connect_timeout=50 dbname=%s user=%s password=%s",
sIP, sPort, sDBName, sLogin, sPassword);
pConn = PQconnectdb(sConnInfo);
if (PQstatus(pConn) == CONNECTION_BAD) {
AddErrorToLog("No connect\n");
return 0;
}
GetActualPath(sActualPath, sTraversingRoot);
if (*sActualPath) {
stat(sActualPath, &rStatBuf);
} else {
stat("/", &rStatBuf);
}
if (nClock)
nTime = time(NULL);
if(S_ISREG(rStatBuf.st_mode)) {
nCount = 1;
ProcessFile(pConn, sActualPath);
}
if(S_ISDIR(rStatBuf.st_mode)) {
nCount = _Traverser(pConn, sActualPath);
}
if (nClock)
fprintf(stdout, "Total time : %u second(s)\n", time(NULL) - nTime);
// Close DB connection
PQfinish(pConn);
return nCount;
}
I want to create native with the same name a method on Java
public native void Traverser(String path)
Respectively in the traverser.c module there will be a function
JNIEXPORT void JNICALL Java_ParallelIndexation_Traverser(JNIEnv *env, jobject obj, jstring path)
The Java_ParallelIndexation_Traverser function is a Traverser function wrapper from the traverser.c module.The question is: How to call a module from Traverser traverser.c in Java_ParallelIndexation_Traverser, passing it the parameter jstring path, thus converting it to a const char * (signature Traverser see above)?
Did I understand your question correctly: how to implement Java_ParallelIndexation_Traverser so that it calls the unmanaged Traveser function?
If so, here's how:
JNIEXPORT void JNICALL Java_ParallelIndexation_Traverser(JNIEnv* env, jobject obj, jstring path)
{
const jbyte* path2 = env->GetStringUTFChars(path, nullptr);
if (path2 == nullptr)
return;
::Traverser(path2);
env->ReleaseStringUTFChars(path, path2);
}
Edit:
Explanation: JNIEnv::GetStringUTFChars converts a jstring to a byte array. You then need to call JNIEnv::ReleaseStringUTFChars to deallocate that byte array.

Jace:: Virtual machine Shutdown Error

What is wrong with this piece of code?
typedef ::jace::proxy::java::lang::String JString;
JString toString(const std::wstring& p)
{
JString strVal(p.c_str());
return strVal;
}
It throws exception unhandled exception, jace::VirtualMachineShutdownError, where I have passed p.c_str() to JString variable strVal.
The reason you are getting that exception is wstring::c_str() returns const wchar_t* whereas jace::String class has no constructor that accepts a wchar_t*. The closest it comes to is String( ::jace::JArray< ::jace::proxy::types::JChar > p0 ); which could be taken as an equivalent to char*.
A workaround to your problem could be something like this:
JString toString(const std::wstring& p)
{
std::string s;
s.assign( p.begin() , p.end() );
JString strVal( s );
return strVal;
}
This is not an efficient solution but works.

JNI ReferenceTable overflow: how to release ObjectArray containing Strings

I am having a frustrating time resolving this issue and the JNI documentation is woefully sparse. Assistance would be greatly appreciated!
Am assigned a project on an Android networking app. The native side stores information about the users you are connected to and I need to send this user list to the Java side to update UI info. Essentially I need to compose a string array and a boolean array which contain the names and flags of connected users, but later more info may be sent. My difficulty is in releasing & cleaning up the Object array containing the String information. I am not clear on how to do this. Here is what I have:
void name_list_cb(struct user_info* user_list, size_t count, void *userdata)
{
jobject callbacks = (jobject)userdata;
JNIEnv *env;
(*g_vm)->GetEnv(g_vm, (void**)&env, JNI_VERSION_1_4);
jclass cls = (*env)->GetObjectClass(env, callbacks);
jmethodID method = (*env)->GetMethodID(env, cls, "user_list", "([Ljava/lang/String;[Z)V");
int i;
jobjectArray name_list;
jbooleanArray connected_list;
name_list = (jobjectArray)(*env)->NewObjectArray(env, count, (*env)->FindClass(env, "java/lang/String"), (*env)->NewStringUTF(env, ""));
connected_list = (jbooleanArray)(*env)->NewBooleanArray(env, count);
uint8_t boolean_arr[count];
for(i = 0; i < count; i++) {
(*env)->SetObjectArrayElement(env, name_list, i, (*env)->NewStringUTF(env, user_list[i].name));
boolean_arr[i] = user_list[i].connected;
}
(*env)->SetBooleanArrayRegion(env, connected_list, 0, count, (jboolean *)boolean_arr);
(*env)->CallVoidMethod(env, callbacks, method, name_list, connected_list);
(*env)->ReleaseBooleanArrayElements(env, connected_list, (jboolean *)boolean_arr, 0);
for(i = 0; i < count; i++) {
(*env)->ReleaseStringUTFChars(env, (*env)->GetObjectArrayElement(env, name_list, i), user_list[i].name);
//(*env)->ReleaseObjectArrayElements(env, name_list, count, 0);
}
(*env)->DeleteLocalRef(env, boolean_arr);
(*env)->DeleteLocalRef(env, name_list);
(*env)->DeleteLocalRef(env, connected_list);
(*env)->DeleteLocalRef(env, cls);
}
I get either a "referencetable overflow", or a "signal 11 (SIGSEGV), fault addr deadbaad". The overflow/memleak is the main prob. Basically I am not releasing the UTFChars and the Object elements. Although I have seen references to it online, my JNI version does not have ReleaseObjectArrayElement[s]. I have been researching how to do this exactly but no luck so far!
I think the problem is (*env)->DeleteLocalRef(env, boolean_arr); because boolean_arr is C function stack variable.
typedef jarray jobjectArray;
void (*DeleteLocalRef)(JNIEnv*, jobject);
So I think use DeleteLocalRef could release the jobjectArray.
Or you can just new the jobjectArray just one time in an initialize method.

Best way to throw exceptions in JNI code?

I'd like a consistent and simple way to throw exceptions in JNI code; something that handles chained exceptions (implicitly from the env->ExceptionOccurred method, or explicitly by parameters, either way is good) and saves me looking up constructors every time I want to do this. All of the above is preferably in C, although I could translate it from C++ at need.
Does anyone on SO have something like this that they can share?
We just code utility methods for each of the types of exceptions we want to throw. Here are some examples:
jint throwNoClassDefError( JNIEnv *env, char *message )
{
jclass exClass;
char *className = "java/lang/NoClassDefFoundError";
exClass = (*env)->FindClass( env, className);
if (exClass == NULL) {
return throwNoClassDefError( env, className );
}
return (*env)->ThrowNew( env, exClass, message );
}
jint throwNoSuchMethodError(
JNIEnv *env, char *className, char *methodName, char *signature )
{
jclass exClass;
char *exClassName = "java/lang/NoSuchMethodError" ;
LPTSTR msgBuf;
jint retCode;
size_t nMallocSize;
exClass = (*env)->FindClass( env, exClassName );
if ( exClass == NULL ) {
return throwNoClassDefError( env, exClassName );
}
nMallocSize = strlen(className)
+ strlen(methodName)
+ strlen(signature) + 8;
msgBuf = malloc( nMallocSize );
if ( msgBuf == NULL ) {
return throwOutOfMemoryError
( env, "throwNoSuchMethodError: allocating msgBuf" );
}
memset( msgBuf, 0, nMallocSize );
strcpy( msgBuf, className );
strcat( msgBuf, "." );
strcat( msgBuf, methodName );
strcat( msgBuf, "." );
strcat( msgBuf, signature );
retCode = (*env)->ThrowNew( env, exClass, msgBuf );
free ( msgBuf );
return retCode;
}
jint throwNoSuchFieldError( JNIEnv *env, char *message )
{
jclass exClass;
char *className = "java/lang/NoSuchFieldError" ;
exClass = (*env)->FindClass( env, className );
if ( exClass == NULL ) {
return throwNoClassDefError( env, className );
}
return (*env)->ThrowNew( env, exClass, message );
}
jint throwOutOfMemoryError( JNIEnv *env, char *message )
{
jclass exClass;
char *className = "java/lang/OutOfMemoryError" ;
exClass = (*env)->FindClass( env, className );
if ( exClass == NULL ) {
return throwNoClassDefError( env, className );
}
return (*env)->ThrowNew( env, exClass, message );
}
That way, it's easy to find them, your code-completion editor will help you to type them in, and you can pass simple parameters.
I'm sure you could expand this to handle chained exceptions, or other more complicated approaches. This was enough to meet our needs.
I simply use 2 lines:
sprintf(exBuffer, "NE%4.4X: Caller can %s %s print", marker, "log", "or");
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/Exception"), exBuffer);
Produces:
Exception in thread "main" java.lang.Exception: NE0042: Caller can log or print.
My code starts in Java, invokes C++, which then invokes Java back again for things like finding, getting, and setting field values.
In case someone looking for a C++ approach finds this page, I'll plough on with this:
What I'm now doing is wrapping my JNI method bodies up with a C++ try/catch block,
JNIEXPORT void JNICALL Java_com_pany_jni_JNIClass_something(JNIEnv* env, jobject self)
{
try
{
... do JNI stuff
// return something; if not void.
}
catch (PendingException e) // (Should be &e perhaps?)
{
/* any necessary clean-up */
}
}
where PendingException is declared trivially:
class PendingException {};
and I'm invoking the following method after invoking any JNI from C++, so if the Java exception status indicates an error, I'll bail immediately and let the normal Java exception handling add the (Native method) line to the stack trace, while giving the C++ the opportunity to clean up while unwinding:
PendingException PENDING_JNI_EXCEPTION;
void throwIfPendingException(JNIEnv* env)
{
if (env->ExceptionCheck()) {
throw PENDING_JNI_EXCEPTION;
}
}
My Java stack trace looks like this for a failed env->GetFieldId() call:
java.lang.NoSuchFieldError: no field with name='opaque' signature='J' in class Lcom/pany/jni/JniClass;
at com.pany.jni.JniClass.construct(Native Method)
at com.pany.jni.JniClass.doThing(JniClass.java:169)
at com.pany.jni.JniClass.access$1(JniClass.java:151)
at com.pany.jni.JniClass$2.onClick(JniClass.java:129)
at android.view.View.performClick(View.java:4084)
and pretty similar if I call up to a Java method that throws:
java.lang.RuntimeException: YouSuck
at com.pany.jni.JniClass.fail(JniClass.java:35)
at com.pany.jni.JniClass.getVersion(Native Method)
at com.pany.jni.JniClass.doThing(JniClass.java:172)
I can't talk to wrapping the Java exception within another Java exception from within C++, which I think is part of your question - I've not found the need to do that - but if I did, I'd either do it with a Java-level wrapper around the native methods, or just extend my exception-throwing methods to take a jthrowable and replace the env->ThrowNew() call with something ugly: it's unfortunate Sun didn't provide a version of ThrowNew that took a jthrowable.
void impendNewJniException(JNIEnv* env, const char *classNameNotSignature, const char *message)
{
jclass jClass = env->FindClass(classNameNotSignature);
throwIfPendingException(env);
env->ThrowNew(jClass, message);
}
void throwNewJniException(JNIEnv* env, const char* classNameNotSignature, const char* message)
{
impendNewJniException(env, classNameNotSignature, message);
throwIfPendingException(env);
}
I wouldn't consider caching (exception) class constructor references because exceptions aren't supposed to be a usual control flow mechanism, so it shouldn't matter if they're slow. I imagine look-up isn't terribly slow anyway, since Java presumably does its own caching for that sort of thing.
I will put a more complete and general answer for who need a little bit more explanations like I need before.
First is nice to set your method with a Throw Exception so the IDE will ask for try/catch.
public native int func(Param1, Param2, Param3) throws IOException;
I decide for IOException over Exception because of this.
JNIEXPORT int JNICALL Java_YourClass_func
(int Param1, int Param2, int Param3) {
if (Param3 == 0) { //something wrong
jclass Exception = env->FindClass("java/lang/Exception");
env->ThrowNew(Exception, "Can't divide by zero."); // Error Message
}
return (Param1+Param2)/Param3;
}

Categories