Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read a bytearray in JNI?

Is it possible to just reference a entire bytearray in JNI but not invoking any copy ?

In native C code, I have a bytearray passing from Java, and I just want to compare some data to this bytearray so I do not want to do any memory copy. Is it possible ?

I know I could get the pointer of a bytearray in native by using GetPrimitiveArrayCritical something like that

JNIEXPORT jbyteArray JNICALL Java_nfore_android_bt_pro_nfhfp_dsp
(JNIEnv *env, jobject jobj, jbyteArray jbIn, jbyteArray jbBase){

    jbyte *bufferIn;
    jbyte *bufferBase;
    bufferIn = (*env)->GetPrimitiveArrayCritical(env, jbIn, NULL);

    LOGD("Begin of dsp()"); 
    LOGD("In dsp() Before Comparing...");

        // Compare bufferIn with bufferBase here...

    LOGD("In dsp() After Comparing...");
    LOGD("End of dsp()");

    (*env)->ReleasePrimitiveArrayCritical(env, jbIn, bufferIn, 0);

    return jbIn;
}

As you could see, because I might change the data in the jbIn, I should use GetPrimitiveArrayCritical to get its pointer and release it later.

However, if I just want to READ the bytearray jbBase, how could I get the pointer of the jbBase but not using GetPrimitiveArrayCritical ?

Any suggestion would be appreciated. Thanks a lot.

like image 673
Bohan Lu Avatar asked Jul 18 '11 04:07

Bohan Lu


People also ask

How do you read a Bytearray?

The read(byte[ ], int, int) method of ByteArrayInputStream class in Java is used to read the given number of bytes into the given byte array from the ByteArrayOutputStream. This method is different from the above read() method as it can read several bytes at a time.

How do I print a Bytearray?

You can simply iterate the byte array and print the byte using System. out. println() method.

What does Bytearray mean?

A byte array is simply a collection of bytes. The bytearray() method returns a bytearray object, which is an array of the specified bytes. The bytearray class is a mutable array of numbers ranging from 0 to 256.


2 Answers

I use the following to read byte arrays...

jbyte *b = (jbyte *)env->GetByteArrayElements(jbBase, NULL);
// read bytes in *b here
...
// release it
env->ReleaseByteArrayElements(jbBase, b, 0 );

You still need to release it as that stops the Garbage collector getting rid of it potentially while you are still using it.

like image 196
Jim Morris Avatar answered Sep 28 '22 16:09

Jim Morris


GetByteArrayElements method can not guarantee that your program use reference or copy. JNI return isCopy flag for state it copied object or pinned it(pin means reference). If you dont want to copy it never, you havent to use GetArrayElements methods, because it always returns copy(JVM decides copy or not and probably copy prefered because copy eases burden of Garbage Collector). I tried it and I saw that my ram increased when sent a big array. You can also see that at below link:

IBM copy and pin (look at copy and pin subject from tree view)

As document says,GetPrimitiveArrayCritical returns the direct heap address of a Java array, disabling garbage collection until the corresponding ReleasePrimitiveArrayCritical is called. So you must use that GetPrimitiveArrayCritical, if you dont want to copy(u need that when you have a big array). If we look at your code, you can get array one by one as below(I assumed you sent int array as a jobject to JNI function):

length = (*env)->GetArrayLength(jbIn);
bufferIn = (*env)->GetPrimitiveArrayCritical(env, jbIn, NULL);
for(int i=0; i<length; i++)
   printf("Value of jbIn[%d]: %d", i, bufferIn[i]);
(*env)->ReleasePrimitiveArrayCritical(env, jbIn, bufferIn, 0);

Important Note: You cannot GetArrayLength after GetPrimitiveArrayCritical because JNI doesn't permit program to call any JNI function for same object between get critical and release methods.

like image 42
Mustafa Kemal Avatar answered Sep 28 '22 18:09

Mustafa Kemal