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.
Related
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.
ArrayList<String> myArraylist;
public ArrayList<String> getData(){
myArraylist = new ArrayList<String>();
myArraylist.add("1267982563");
myArraylist.add("2345678");
myArraylist.add("5432789");
return myArraylist;
}
How to get the each items from the above method in JNI side and Push to vector and return from the JNI to other CPP calls in the JNI layer.
Convert ArrayList to std::vector<std::string>:
jclass java_util_ArrayList;
jmethodID java_util_ArrayList_;
jmethodID java_util_ArrayList_size;
jmethodID java_util_ArrayList_get;
jmethodID java_util_ArrayList_add;
thread_local JNIEnv *env;
void init() {
java_util_ArrayList = static_cast<jclass>(env->NewGlobalRef(env->FindClass("java/util/ArrayList")));
java_util_ArrayList_ = env->GetMethodID(java_util_ArrayList, "<init>", "(I)V");
java_util_ArrayList_size = env->GetMethodID (java_util_ArrayList, "size", "()I");
java_util_ArrayList_get = env->GetMethodID(java_util_ArrayList, "get", "(I)Ljava/lang/Object;");
java_util_ArrayList_add = env->GetMethodID(java_util_ArrayList, "add", "(Ljava/lang/Object;)Z");
}
std::vector<std::string> java2cpp(jobject arrayList) {
jint len = env->CallIntMethod(arrayList, java_util_ArrayList_size);
std::vector<std::string> result;
result.reserve(len);
for (jint i=0; i<len; i++) {
jstring element = static_cast<jstring>(env->CallObjectMethod(arrayList, java_util_ArrayList_get, i));
const char *pchars = env->GetStringUTFChars(element, nullptr);
result.emplace_back(pchars);
env->ReleaseStringUTFChars(element, pchars);
env->DeleteLocalRef(element);
}
}
Push ArrayList from JNI back to Java
If you don't modify this list in JNI, then the best strategy would be to simply keep a global reference to it somewhere in your native code. If you modify it a little, keep this jobject always up-to-date (you will probably need the methods java_util_ArrayList_add or java_util_ArrayList_set).
If you choose to reconstruct the list from scratch the vector, you will unwind the above method:
jobject cpp2java(std::vector<std::string> vector) {
jobject result = env->NewObject(java_util_ArrayList, java_util_ArrayList_, vector.size());
for (std::string s: vector) {
jstring element = env->NewStringUTF(s.c_str());
env->CallBooleanMethod(result, java_util_ArrayList_add, element);
env->DeleteLocalRef(element);
}
return result;
}
At any rate, be careful with threads when you work with Jni, always attach your native threads and detach before the native thread is destroyed.
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.
We are implementing a one-to-one mapping of some winapi methods, for the xidobi serial port project. The mapping of the C methods to java works as expected, but for an unknown reason GetLastError() get cleared.
Here is the C-Code:
// CreateFile ////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL
Java_org_xidobi_OS_CreateFile(JNIEnv *env, jobject this,
jstring lpFileName,
jint dwDesiredAccess,
jint dwShareMode,
jint lpSecurityAttributes,
jint dwCreationDisposition,
jint dwFlagsAndAttributes,
jint hTemplateFile) {
const char* fileName = (*env)->GetStringUTFChars(env, lpFileName, NULL);
HANDLE handle = CreateFile(fileName,
dwDesiredAccess,
dwShareMode,
(LPSECURITY_ATTRIBUTES) lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
(HANDLE) hTemplateFile);
(*env)->ReleaseStringUTFChars(env, lpFileName, fileName);
return (jint) handle;
}
// GetLastError ////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL
Java_org_xidobi_OS_GetLastError(JNIEnv *env, jobject this) {
return (jint) GetLastError();
}
In Java we call the mapped native methods in like this:
int handle = os.CreateFile("\\\\.\\" + portName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (handle != INVALID_HANDLE_VALUE)
return handle;
int lastError= os.GetLastError(); //-> sometimes 0 (ERROR_SUCCESS)
We figured out that if we call GetLastError() in C right after CreateFile(..) the correct error code is returned. Since the one-to-one mapping is dead simple we assume that JNI or the VM calls SetLastError() itself and clears our last error.
We don't want to give up the one-to-one mapping design, so what can we do to solve this puzzle?
Here is a similar question that doesn't help in this case: CreateFile() returns INVALID_HANDLE_VALUE but GetLastError() is ERROR_SUCCESS
There is no guarantee that GetLastError() will survive whatever the JVM is doing between your native call to CreateFile and your native call to GetLastError. Therefore you should immediately call GetLastError after CreateFile and save the value in a thread local slot of your own.
Then your implementation of GetLastError will retrieve it from wherever you stored it.
You may wish to rename it LastXidobiError or some such as it will only retrieve an error which was set by a call in your library.
// Space to store last error ////////////////////////////////////////////
static DWORD dwTlsIndexLastError = 0;
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
){
switch(fdwReason){
case DLL_PROCESS_ATTACH:
dwTlsIndexLastError = TlsAlloc();
break;
case DLL_PROCESS_DETACH:
TlsFree(dwTlsIndexLastError);
dwTlsIndexLastError = 0;
break;
}
return TRUE;
}
///// Save the last error.
///// Call this function after the "real" function whose error you want to report.
void SaveLastError()
{
TlsSetValue(dsTlsIndexLastError, (LPVOID)(DWORD_PTR)GetLastError());
}
// GetLastError ////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL
Java_org_xidobi_OS_GetLastError(JNIEnv *env, jobject this) {
return (jint) TlsGetValue(dsTlsIndexLastError);
}
// CreateFile ////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL
Java_org_xidobi_OS_CreateFile(JNIEnv *env, jobject this,
jstring lpFileName,
jint dwDesiredAccess,
jint dwShareMode,
jint lpSecurityAttributes,
jint dwCreationDisposition,
jint dwFlagsAndAttributes,
jint hTemplateFile) {
const char* fileName = (*env)->GetStringUTFChars(env, lpFileName, NULL);
HANDLE handle = CreateFile(fileName,
dwDesiredAccess,
dwShareMode,
(LPSECURITY_ATTRIBUTES) lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
(HANDLE) hTemplateFile);
// Save the value of GetLastError for the relevant function
SaveLastError();
(*env)->ReleaseStringUTFChars(env, lpFileName, fileName);
return (jint) handle;
}
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;
}