Hi everyone I have a problem on certain android devices (This device is running android 5.1)
I have the following code
extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_peachss_sadldecoder_Decoder_getDecodedPhoto(JNIEnv *env, jclass clazz,
jbyteArray photo_data, jint size) {
jbyte* input= env->GetByteArrayElements(photo_data, 0);
WiResultImage decode = DecodeImage((unsigned char*)input, size + 1);
env->ReleaseByteArrayElements(photo_data, input, JNI_ABORT);
jbyteArray output = env->NewByteArray(decode.size);
env->SetByteArrayRegion(output, 0, decode.size, (jbyte*)decode.raw);
return output;
}
The moment it reaches 'NewByteArray' I get the following error
Signal: SIGABRT (signal SIGABRT)
Related
I keep trying Multi Processing (using Shared Memory) in Android Studio (With NDK). I installed NDK, LLDB, CMake. Also I use API Level 26 and min SDK is also 26 (OREO, 8.0).
I created native_lib.cpp, and making some files for testing FD.
I made simple small class for testing .
Class has int FileDescriptor, char* buffer.
I checked variables and it seems like made succesfully. ASharedMemory_Create() returns fd, and i can get size of memory from ASharedMemory_getSize(int fd).
But how can i access shared memory from another process? Am i need to use java for IPC? If i can i want to use native only. Currently java is only for UI.
https://developer.android.com/ndk/reference/group/memory
I checekd here. If there are something that worth i can refer please let me know. Thank you.
Edited---------------------------------------------------
I want to make shared memory in both of parent and child. Also want to access shared memory freely. Child to child, child to parents, parents to child.
Making File Descriptor and buffer in parents works smoothly, but when i try to make buffer or fd in child, i cant access it.
I used same name and size for ASharedMemory_create, but other process making different File descriptor in my opinion. Don't know whats wrong.
Below is my native_lib.cpp for testing. Functions matched with Buttons except Init. Init called onCreate.
int fd[4];
char* buffer[4];
int myFd;
int* cBuf;
const char* names[4] = {"Test", "Inter", "Process", "Mech"};
const int size = 512;
extern "C" JNIEXPORT void JNICALL
Java_org_techtwon_multipro_MainActivity_SyncBuffer(
JNIEnv *env,
jobject /* this */) {
int cVal;
memcpy(&cVal, cBuf, sizeof(int));
for(int i = 0 ; i < cVal; ++i)
{
if(fd[i] != NULL) {
buffer[i] = (char *) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[i], 0);
}
}
}
extern "C" JNIEXPORT void JNICALL
Java_org_techtwon_multipro_MainActivity_MakeFileDesc(
JNIEnv *env,
jobject /* this */) {
pid_t pid = fork();
int cVal;
if(pid < 0) {
return;
} else if(pid == 0) {
memcpy(&cVal, cBuf, sizeof(int));
fd[cVal] = ASharedMemory_create(names[cVal], size);
buffer[cVal] = (char*) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[cVal], 0);
memset(buffer[cVal], 0, size);
memcpy(buffer[cVal], names[cVal], strlen(names[cVal]));
cVal++;
memcpy(cBuf, &cVal, sizeof(int));
sleep(1);
exit(1);
}
}
extern "C" JNIEXPORT void JNICALL
Java_org_techtwon_multipro_MainActivity_Init(
JNIEnv *env,
jobject /* this */) {
myFd = ASharedMemory_create("Num", sizeof(int));
cBuf = (int*) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, myFd, 0);
for(int i = 0 ; i < 4; ++i) fd[i] = ASharedMemory_create(names[i], size);
buffer[0] = (char*) mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd[0], 0);
memcpy(buffer[0], names[0], strlen(names[0]));
memset(cBuf, 0, sizeof(int));
}
extern "C" JNIEXPORT jint JNICALL
Java_org_techtwon_multipro_MainActivity_GetFd(
JNIEnv *env,
jobject /* this */, jint idx) {
return fd[idx];
}
extern "C" JNIEXPORT jbyteArray JNICALL
Java_org_techtwon_multipro_MainActivity_GetBuffer(
JNIEnv *env,
jobject /* this */, jint idx) {
jbyteArray tmp = (*env).NewByteArray(strlen(buffer[idx]));
env->SetByteArrayRegion(tmp, 0, strlen(buffer[idx]), (jbyte*) buffer[idx]);
return tmp;
}
extern "C" JNIEXPORT jint JNICALL
Java_org_techtwon_multipro_MainActivity_GetcVal(
JNIEnv *env,
jobject /* this */, jint idx) {
int cVal;
memcpy(&cVal, cBuf, sizeof(int));
return cVal;
}
The code snippet in official docs has it quite clear:
int fd = ASharedMemory_create("memory", 128);
// By default it has PROT_READ | PROT_WRITE | PROT_EXEC.
char *buffer = (char *) mmap(NULL, 128, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
strcpy(buffer, "This is an example."); // trivially initialize content
// limit access to read only
ASharedMemory_setProt(fd, PROT_READ);
// share fd with another process here and the other process can only map with PROT_READ.
The name has no meaning, only helpful for debugging. The size should match.
This is the API you should use for API 29 and higher, the old ways (below) don't work anymore.
If you need also to cover devices below API 26, you need a fallback that makes direct IOCTLs to /dev/ashmem file descriptors. This was available since Android early days:
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/ashmem.h>
int fd = open("/dev/ashmem", O_RDWR);
ioctl(fd, ASHMEM_SET_NAME, "memory");
ioctl(fd, ASHMEM_SET_SIZE, 128);
char *buffer = (char * ) mmap(NULL, 128, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
There even is a nice example of wrapping this shared memory for use in Java: ANDROID – CREATING SHARED MEMORY USING ASHMEM.
I had to use NDK in my java code to call some audio processing functions, but i have never tried JNI or C/C++ coding. I tried to start from the scratch but i really have no time. so i found this library here and tried to use it. I always get a fatal signal 11 (sigsegv) error. I really don't know where to start. here's what i have done so far:
in the Android Activity:
public native int transform(double[] real,double[]imag, int n);
public native int convolve(double[]xreal,double[]ximag,double[]yreal,double[]yimag,double[]outreal,double[]outim, int n);
and they are called in the same file like this :
transform(raw1, imag1,raw1.length);//result back into each vector
transform(raw2, imag2,raw2.length);
convolve(raw1,imag1,raw2,imag2,outre,outim,raw1.length);
in the C file:
JNIEXPORT jint JNICALL Java_com_example_ffttest_FFTActivity_transform
(JNIEnv *env, jobject obj, jdoubleArray real, jdoubleArray imag, jint n)
{
if (n == 0)
return 1;
else if ((n & (n - 1)) == 0) // Is power of 2
return transform_radix2(real, imag, n);
else // More complicated algorithm for arbitrary sizes
return transform_bluestein(real, imag, n);
}
and made some changes to the convolve function:
JNIEXPORT jint JNICALL Java_com_example_ffttest_FFTActivity_convolve
(JNIEnv *env, jobject obj, jdoubleArray xreal, jdoubleArray ximag, jdoubleArray yreal, jdoubleArray yimag, jdoubleArray outreal, jdoubleArray outimag, jint n)
{
//size = n * sizeof(double);
n = (*env)->GetArrayLength(env, xreal);
jdouble *a=(*env)->GetDoubleArrayElements(env,xreal,0);
jdouble *b=(*env)->GetDoubleArrayElements(env,ximag,0);
jdouble *c=(*env)->GetDoubleArrayElements(env,yreal,0);
jdouble *d=(*env)->GetDoubleArrayElements(env,yimag,0);
jdouble *e=(*env)->GetDoubleArrayElements(env,outreal,0);
jdouble *f=(*env)->GetDoubleArrayElements(env,outimag,0);
...
Is there some changes i need to know from C to JNI?
I want return a pointer to a double array in JNI, and then, use this values in Java's code. So i did this:
JNIEXPORT jlong JNICALL Java_com_sistoleaudiocapture_Processing_prueba_1nativa(
JNIEnv * env, jclass, jlong retorno, jbyteArray data, jint lenbytes) {
//PROCESS
long dirt;
dirt=(long)d_est;
return(dirt);
}
In my java funcition:
public void prueba(byte[] data, int lenbytes) {
prueba=prueba_nativa(retorno, data, lenbytes);
}
So now, How can I acess to my values?
Thanks
You can either create additional functions to access the array on the native side, exposing them to Java. Or you can create a jDoubleArray within your native code, and return that to Java.
const double * arrayPtr = (const double *)&yourDoubleArray;
jint lengthOfArray = 0; //Fill dynamically with the length of your native double array.
jdoubleArray doubleArray = (*env)->NewDoubleArray(env, lengthOfArray);
(*env)->SetDoubleArrayRegion( env, doubleArray, 0, 16, arrayPtr);
return doubleArray;
I want to use native memory instead of Java heap, for camera buffer in camera.addCallbackBuffer();
I write some code, but it's wrong. I get null -array.
How to do it properly?
Java PART
buflen=allocBuffer(1280,720);
byte[] x= getBuffern(0,1280,720);//than i want to use this for addCallbackBuffer()
freeBuffer();
NDK PART
signed char * yuvm;
size_t getTotalSystemMemory()
{
long pages = sysconf(_SC_PHYS_PAGES);
long page_size = sysconf(_SC_PAGE_SIZE);
return pages * page_size;
}
jint Java_com_example_testdvr_mycamview_allocBuffer(JNIEnv * env, jclass obj, jint width, jint height){
jint bufLength=getTotalSystemMemory()/4;
bufLength=bufLength/(width*height*1.5);
yuvm = (signed char*) malloc (bufLength*width*height*1.5);
return bufLength;
}
void Java_com_example_testdvr_mycamview_freeBuffer(JNIEnv * env, jclass obj){
if (sizeof(yuvm)!=0){
free(yuvm);
}
}
jbyteArray Java_com_example_testdvr_mycamview_getBuffern(JNIEnv * env, jclass obj, jint numbuf, jint width, jint height){
jbyteArray res;
env->SetByteArrayRegion(res,width*height*1.5*numbuf,width*height*1.5,yuvm);
return res;
}
Also i have idea to use camera object from NDK for native memory for buffer.
LIKE THIS:
JNIEXPORT void JNICALL Java_com_test_jnicall_ld(
JNIEnv *env,
jclass clazs,
jobject camera) {
jclass clazz = env->GetObjectClass(camera);
jmethodID voidVoidMethod = env->GetMethodID(clazz,"addCallbackBuffer", "([B)V");
jbyteArray* b=malloc(640*480*3/2);
env->CallVoidMethod(camera, voidVoidMethod,b);
}
But have a problem to:
09-18 13:24:22.982: W/dalvikvm(27090): Invalid indirect reference 0x783f8008 in decodeIndirectRef
09-18 13:24:22.982: E/dalvikvm(27090): VM aborting
09-18 13:24:22.982: A/libc(27090): Fatal signal 6 (SIGABRT) at 0x000069d2 (code=-6), thread 27123 (Thread-4070)
I tryed to writer method like InputStream:read(byte[] buffer,int offset,int length):
/*
* Class: com_readium_ResourceStream
* Method: readNative
* Signature: ([BII)I
*/
JNIEXPORT jint JNICALL Java_com_readium_ResourceStream_readNative
(JNIEnv *, jobject, jbyteArray, jint, jint);
How can I write uint_8 array to jbyteArray from params?
This is my answer. It must be compiled as a c++ compilation unit. Otherwise you have to pass env as the first param (ie env->GetArrayLength(...); become in c GetArrayLength(env, ...).
/*
* Class: com_readium_ResourceStream
* Method: readNative
* Signature: ([BII)I
*/
JNIEXPORT jint JNICALL Java_com_readium_ResourceStream_readNative
(JNIEnv *env, jobject obj, jbyteArray buffer, jint offset, jint len)
{
jint readed;
// Read data and set readed
jboolean isCopy;
jsize arrayLen = env->GetArrayLength(buffer);
jbyte* array = env->GetByteArrayElements(env, buffer, &isCopy);
// Use array here
env->ReleaseByteArrayElements(buffer, array, 0);
return readed;
}
Remeber, java bytes are always signed.