Java native ReleaseByteArrayElements() clearing buffer

Thread Starter

geekoftheweek

Joined Oct 6, 2013
1,214
What I want to do is declare a buffer, pass it to the native code to modify, then use the changed buffer to update the app. This is an Android project that in the end will use another native library to do the actual work so this seems to be the best route to me.

In the main activity
Code:
byte the_buffer[];
the_buffer = new byte[1024];
int bytes_read = myLibrary.ReadMessage(the_id,the_buffer);

...
writes the bytes out in a list to scroll through
which calls the native

Code:
JNIEXPORT jint JNICALL Java_com_example_myapp_mylibrary_ReadMessage(JNIEnv *pEnv, jobject pThis, jint nexiq_id, jbyteArray buffer) {
    jboolean is_copy;
    jbyte *buf = (char*)pEnv->GetByteArrayElements(buffer,&is_copy);
    char char_buf[1024] = {0};

    // test
    int bytes_read = rand();
    while(bytes_read > 1024) bytes_read -= 1024;

    int i;
    for (i = 0; i < bytes_read; i++) {
        char_buf[i] = (char)(rand() & 0xff);
   }

    pEnv->SetByteArrayRegion(buffer,0,i,(jbyte*)char_buf);
    pEnv->ReleaseByteArrayElements(buffer, buf, 0);


    return bytes_read;

}
If I leave in the ReleaseByteArrayElements() when it returns from native to write the buffer in a list the buffer seems to reset to all 0's.
If I comment out the ReleaseByteArrayElements() the buffer keeps the random numbers.

Is this right or did I miss something?

In the end instead of filling it with random numbers it will call a read function of another library and return that data.
 

Thread Starter

geekoftheweek

Joined Oct 6, 2013
1,214
I spent a few more hours looking at code examples trying to find a definite answer, but still no luck. All seem to show sending data to the native calls, but nothing showing modifying the data to be used outside of the native call.

I kind of fell asleep and it run for about an hour before it crashed. More or less it just keeps looping and calling the native as fast as it can. From what I can tell the crash was more from the scroll view getting too big than any other sort of memory leaks that are associated with not calling the ReleaseByteArrayElements().

I have a semi decent grasp of Java, but the native stuff was a whole new learning experience... Thanks all for looking!!
 

xox

Joined Sep 8, 2017
838
What I want to do is declare a buffer, pass it to the native code to modify, then use the changed buffer to update the app. This is an Android project that in the end will use another native library to do the actual work so this seems to be the best route to me.

In the main activity
Code:
byte the_buffer[];
the_buffer = new byte[1024];
int bytes_read = myLibrary.ReadMessage(the_id,the_buffer);

...
writes the bytes out in a list to scroll through
which calls the native

Code:
JNIEXPORT jint JNICALL Java_com_example_myapp_mylibrary_ReadMessage(JNIEnv *pEnv, jobject pThis, jint nexiq_id, jbyteArray buffer) {
    jboolean is_copy;
    jbyte *buf = (char*)pEnv->GetByteArrayElements(buffer,&is_copy);
    char char_buf[1024] = {0};

    // test
    int bytes_read = rand();
    while(bytes_read > 1024) bytes_read -= 1024;

    int i;
    for (i = 0; i < bytes_read; i++) {
        char_buf[i] = (char)(rand() & 0xff);
   }

    pEnv->SetByteArrayRegion(buffer,0,i,(jbyte*)char_buf);
    pEnv->ReleaseByteArrayElements(buffer, buf, 0);


    return bytes_read;

}
If I leave in the ReleaseByteArrayElements() when it returns from native to write the buffer in a list the buffer seems to reset to all 0's.
If I comment out the ReleaseByteArrayElements() the buffer keeps the random numbers.

Is this right or did I miss something?

In the end instead of filling it with random numbers it will call a read function of another library and return that data.
JNI is a very fickle beast. Lots of undocumented behavior relating to specific parameter states and what have you.

Try passing NULL in place of the is_copy parameter. And while you're at it, why not just write directly to the buffer instead of the double-pass?

Another thing. Rather than repeated subtractions you can simply use the modulus operator.

Code:
JNIEXPORT jint JNICALL Java_com_example_myapp_mylibrary_ReadMessage(JNIEnv *pEnv, jobject pThis, jint nexiq_id, jbyteArray buffer) {
  jbyte *char_buf = (char*)pEnv->GetByteArrayElements(buffer, NULL);
  int bytes_read = rand() % 1024;
  int i;
  for (i = 0; i < bytes_read; i++) {
  char_buf[i] = (char)(rand() & 0xff);
  }
  pEnv->ReleaseByteArrayElements(buffer, char_buf, 0);
  return bytes_read;
}
 

Thread Starter

geekoftheweek

Joined Oct 6, 2013
1,214
Try passing NULL in place of the is_copy parameter. And while you're at it, why not just write directly to the buffer instead of the double-pass?

Another thing. Rather than repeated subtractions you can simply use the modulus operator.
Thanks for the tips. I do remember seeing the modulus somewhere, but lost it somewhere while digging around.
 

Thread Starter

geekoftheweek

Joined Oct 6, 2013
1,214
@xox I finally made my way back to this project. You put things on the right track after a couple tweaks. What I finally ended up with...

Code:
JNIEXPORT jint JNICALL Java_com_example_mytest_testLib_ReadMessage(JNIEnv *pEnv, jobject pThis, jint device_id, jbyteArray buffer) {
    jbyte *buf = pEnv->GetByteArrayElements(buffer,nullptr);
    int bytes_read = test_ReadMessage(device_id, (char*) buf, 2048, 0);
    pEnv->ReleaseByteArrayElements(buffer, buf, 0);
    return bytes_read;
}
 
Top