I am trying following code inside cpp file to receive arraylist from java file. Here is the code
jobjectArray trackables;
JNIEXPORT void JNICALL
Java_com_putitout_buck_VideoPlayback_setTrackables(JNIEnv *env, jobject obj, jobject trackables_)
{
// use the Array list
jclass ArrayList_class = env->FindClass( "java/util/ArrayList" );
// to conver jobject to jstring
jmethodID caster = env->GetMethodID(ArrayList_class, "toString", "()Ljava/lang/String;");
// get two methods
jmethodID Get_method = env->GetMethodID( ArrayList_class, "get", "(I)Ljava/lang/Object" );
jmethodID Size_method = env->GetMethodID( ArrayList_class, "size", "()I" );
// call java.lang.ArrayList.get()
int NumElts = env->CallIntMethod(trackables_, Size_method);
// allocate output array
jclass objClass = env->FindClass("java/lang/String");
trackables = env->NewObjectArray(NumElts, objClass, 0);
// fetch all the items
for(int i = 0 ; i < NumElts ; i++)
{
// call java.lang.ArrayList.get(int index) method
// Not sure about the parameter passing here
jobject Tmp = env->CallObjectMethod(trackables_, Get_method, i);
jstring Str = (jstring)env->CallObjectMethod(Tmp, caster);
__android_log_print(ANDROID_LOG_ERROR, "TRACKERS", "%s", Str);
// get the length
int StrLen = env->GetStringLength(Str);
env->SetObjectArrayElement(trackables, i, Str);
}
}
Following is the code I am declaring in java file
public native void setTrackables(ArrayList<String> trackables);
Following is in the log.
10-24 17:45:44.555: W/dalvikvm(27400): JNI WARNING: JNI method called with exception pending
10-24 17:45:44.555: W/dalvikvm(27400): in Lcom/putitout/buck/VideoPlayback;.setTrackables:(Ljava/util/ArrayList;)V (GetMethodID)
10-24 17:45:44.555: W/dalvikvm(27400): Pending exception is:
10-24 17:45:44.555: E/dalvikvm(27400): VM aborting
10-24 17:45:44.560: A/libc(27400): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1)
Why are you using JNI to convert an ArratList of objects into an array of strings? Better do that in Java - much cleaner code - and pass the array of strings to JNI.
That said, LogCat says one of your Java method calls is causing an exception. It does not say which one. To debug, insert a check after every CallXXXMethod:
if(env->ExceptionOccurred())
{
__android_log_write(ANDROID_LOG_ERROR, "TRACKERS", "Error in (MethodName)");
env->ExceptionDescribe();
}
Also, "any help?" comment is not constructive. Please don't rush the community. This is a free service, no one here owes you an answer.
Related
New to JNI. I am trying to call Element::getChild and Element::getChildText APIs (java org.jdom.Element) to get the version number of a system that is stored in "settings.xml" This xml file is archived in JAR file. Assuming the root element is available, here is what I am doing:
jstring fileNameStr = env->NewStringUTF("settings.xml");
jobject rootElement = env->CallStaticObjectMethod(a_class, xmlRootElement_mid, fileNameStr);
jclass cls_element = env->FindClass("org/jdom/Element");
/*get method ID for getChild() & getChildText() */
jmethodID getChild_mid = env->GetMethodID(cls_element, "getChild", "(Ljava/lang/String;)Lorg/jdom/Element;");
jmethodID getChildText_mid = env->GetMethodID(cls_element, "getChildText", "(Ljava/lang/String;)Ljava/lang/String;");
jstring aboutStr = env->NewStringUTF("about");
jobject about = env->CallStaticObjectMethod(cls_element, getChild_mid, aboutStr); ---> Seg Faults!!!
Basically, I want to do Java equivalent of this:
In Java:
import org.jdom.Element;
...
Element element = SomeMethodToReadXmlFile("settings.xml");
version = element.getChild("about").getChildText("version"); <---- works
How should I do this?
Using JNI, here is what worked for me that uses org.jdom.Element. My settings.xml file looks like this:
<?xml version="1.0">
<settings>
<about>
<version>1.0</version>
</about>
</settings>
JNI C++:
jstring fileNameStr = env->NewStringUTF("settings.xml");
// assuming xmlRootElement_mid is known
jobject element_obj = env->CallStaticObjectMethod(a_class, xmlRootElement_mid, fileNameStr);
jclass cls_element = env->FindClass("org/jdom/Element");
/*get method ID for getChild() & getChildText() */
jmethodID getChild_mid = env->GetMethodID(cls_element, "getChild", "(Ljava/lang/String;)Lorg/jdom/Element;");
jmethodID getChildText_mid = env->GetMethodID(cls_element, "getChildText", "(Ljava/lang/String;)Ljava/lang/String;");
jstring jstr = env->NewStringUTF("about");
element_obj = env->CallObjectMethod(element_obj, getChild_mid, jstr)
jstr = env->NewStringUTF("version");
jstring version_str = (jstring)env->CallObjectMethod(element_obj, getChildText_mid, jstr);
//Convert to std::string
std::string version_std_str;
if (version_str)
{
const char *c = env->GetStringUTFChars(version_str, 0);
version_std_str = std::string(c);
env->ReleaseStringUTFChars(version_str, c);
}
std::cout << version_std_str << std::endl
Outputs:
1.0
i write this code in my android Activity to send a request to C in android ndk:
Toast.makeText(getApplicationContext(),Calculate("1")+"",Toast.LENGTH_SHORT).show();
public native String Calculate(String j_key_name);
and in ndk side in C file i write this code:
JNIEXPORT jstring JNICALL
Java_org_sample_aguar_NActivity_Calculate(JNIEnv *env, jobject thiz, jstring j_key_name) {
if (j_key_name == "1") {
return (*env)->NewStringUTF(env, " its 1 ");
} else{
return (*env)->NewStringUTF(env, " it's not 1 ");
}
}
i don't have any error But That's always run else part and when i send "1" in response i get (it's not 1 ).
I have written simple if-else program in c. I use String.h library in
it and working correctly.
#include<string.h>
char j_key_name[] ="1";
int check = strcmp(j_key_name, "1");
if (check == 0) {
printf("if");
} else{
printf("else");
}
Let's try above code. Hopefully solve your issue. Thanks in advance.
So I'm having some java-Code that I want to call from C++ via JNI. It's done by the following code:
int main(int argc, char **argv) {
JavaVM * jvm;
JNIEnv* env = create_vm(&jvm);
invoke_class( env );
}
JNIEnv* create_vm(JavaVM ** jvm) {
JNIEnv* env;
JavaVMInitArgs vm_args;
JavaVMOption options;
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
options.optionString = "-Djava.class.path=<path_to_java_class>:<path_to_jars>";
vm_args.options = &options;
vm_args.ignoreUnrecognized = JNI_FALSE;
int ret = JNI_CreateJavaVM(jvm, (void **)&env, &vm_args);
if(ret < 0)
printf("\nUnable to Launch JVM\n");
return env;
}
void invoke_class(JNIEnv* env) {
jclass helloWorldClass;
helloWorldClass = env->FindClass("A");
if (env->ExceptionCheck()){
std::cout << "EXCEPTION OCCURED: " << std::endl;
env->ExceptionDescribe();
}
}
call_main(env, helloWorldClass);
void call_main(JNIEnv* env, jclass hClass){
jmethodID mainMethod;
jobjectArray applicationArgs;
jstring applicationArg0;
jstring applicationArg1;
mainMethod = env->GetStaticMethodID(hClass, "main", "([Ljava/lang/String;)V");
applicationArgs = env->NewObjectArray(2, env->FindClass("java/lang/String"), NULL);
applicationArg0 = env->NewStringUTF("planes.txt");
applicationArg1 = env->NewStringUTF("out.txt");
env->SetObjectArrayElement(applicationArgs, 0, applicationArg0);
env->SetObjectArrayElement(applicationArgs, 1, applicationArg1);
env->CallStaticVoidMethod(hClass, mainMethod, applicationArgs);
}
The corresponding Java-Code that is called is as follows:
public class A{
import org.mindswap.pellet.jena.PelletReasonerFactory;
import com.hp.hpl.jena.rdf.model.ModelFactory;
private OntModel model = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
public A() {
System.out.println("hi2");
}
public static void main(String[] args) throws Exception {
System.out.println("hi1");
A app = new A();
long start = System.currentTimeMillis();
long stop = System.currentTimeMillis();
System.out.println("Processing took " + (stop - start) + " ms");
System.out.println("Normal program end.");
}
}
Okay, so if I'm now executing the C++-Code I get the following output:
hi1
without any error-messages, the program terminates correctly. However, I would expect the output to be something like:
hi1
hi2
Processing took 0ms
Normal program end.
It seems like calling the constructor just doesn't happen and the code after that isn't executed at all.
However, if I remove the line
private OntModel model = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
the output is correct.
Since leaving out this isn't an option, what is happening here? How is it even possible that the program is terminating without an error-message although it shouldn't be finished at all?
I've tried to put in something like Thread.sleep(10000) to see if it has something to do with the time that given call takes, but that doesn't seem to be a problem at all.
EDIT: sry, I forgot to change the class-name.
EDIT2: I should mention that the java-code ist running perfectly fine when it is not called out of a C++-environment
Problem solved. It had something to do with the jar-files and some file-locations. Sorry for bothering for nothing!
I'm trying to make an android app in which I need to access accelerometer in jni.
java code :
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
jni code :
jclass cls_context = env->FindClass("android/content/Context");
jfieldID tService = env->GetStaticFieldID(cls_context, "SENSOR_SERVICE","Ljava/lang/String;");
jstring jstr = (jstring)env->GetStaticObjectField(cls_context, tService);
//getSystemService(SENSOR_SERVICE);
jclass cls_act = env->GetObjectClass(activity);
jmethodID GetSystemService = env->GetMethodID(cls_act,"getSystemService","(Ljava/lang/String;)Ljava/lang/Object;");
jobject systemservice = env->CallObjectMethod(activity,GetSystemService,jstr);
//getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
jclass sensormanager = env->GetObjectClass(systemservice);
jmethodID getdefaultsensor = env->GetMethodID(sensormanager, "getDefaultSensor", "(I)Landroid/hardware/Sensor;");
jobject sensor = env->CallObjectMethod(systemservice, getdefaultsensor, "Sensor.TYPE__ACCELEROMETER");
But jobject sensor is getting null.
Sensor.TYPE_ACCELEROMETER is an inlined constant of type int and has value 1, which should be passed there.
But anyway those 2 lines split into 9 lines of JNI code looks bad. Wouldn't it be better to leave those original lines of Java code and then just call it from JNI?
I would like to determine what exception has been thrown by a Java function when calling that function from C++ code using JNI. I have the following code that catches the Java exception:
JNIEnv * pEnv; // assume this is properly initialized
jclass javaClass; // ditto
jmethodID javaFunction; // ditto
pEnv->CallStaticVoidMethod(javaClass, javaFunction);
jthrowable exc;
if(exc = pEnv->ExceptionOccurred())
{
pEnv->ExceptionClear();
}
I do not know how to obtain descriptive information about the Java exception within this C++ code. Can somebody help?
I have omitted calling ExceptionCheck() after each JNI call and checking for any failed attempts to locate methods for brevity: you should add these when implementing.
First, store the exception and then acquire the Java methods necessary for obtaining information about the Throwable:
// Get the exception and clear as no
// JNI calls can be made while an exception exists.
jthrowable exception = pEnv->ExceptionOccurred();
pEnv->ExceptionClear();
jclass throwable_class = pEnv->FindClass("java/lang/Throwable");
jmethodID mid_throwable_getCause =
pEnv->GetMethodID(throwable_class,
"getCause",
"()Ljava/lang/Throwable;");
jmethodID mid_throwable_getStackTrace =
pEnv->GetMethodID(throwable_class,
"getStackTrace",
"()[Ljava/lang/StackTraceElement;");
jmethodID mid_throwable_toString =
pEnv->GetMethodID(throwable_class,
"toString",
"()Ljava/lang/String;");
jclass frame_class = pEnv->FindClass("java/lang/StackTraceElement");
jmethodID mid_frame_toString =
pEnv->GetMethodID(frame_class,
"toString",
"()Ljava/lang/String;");
Second, recursively construct the error message (you may want to modify this):
std::string error_msg; // Could use ostringstream instead.
_append_exception_trace_messages(*pEnv,
error_msg,
exception,
mid_throwable_getCause,
mid_throwable_getStackTrace,
mid_throwable_toString,
mid_frame_toString);
void _append_exception_trace_messages(
JNIEnv& a_jni_env,
std::string& a_error_msg,
jthrowable a_exception,
jmethodID a_mid_throwable_getCause,
jmethodID a_mid_throwable_getStackTrace,
jmethodID a_mid_throwable_toString,
jmethodID a_mid_frame_toString)
{
// Get the array of StackTraceElements.
jobjectArray frames =
(jobjectArray) a_jni_env.CallObjectMethod(
a_exception,
a_mid_throwable_getStackTrace);
jsize frames_length = a_jni_env.GetArrayLength(frames);
// Add Throwable.toString() before descending
// stack trace messages.
if (0 != frames)
{
jstring msg_obj =
(jstring) a_jni_env.CallObjectMethod(a_exception,
a_mid_throwable_toString);
const char* msg_str = a_jni_env.GetStringUTFChars(msg_obj, 0);
// If this is not the top-of-the-trace then
// this is a cause.
if (!a_error_msg.empty())
{
a_error_msg += "\nCaused by: ";
a_error_msg += msg_str;
}
else
{
a_error_msg = msg_str;
}
a_jni_env.ReleaseStringUTFChars(msg_obj, msg_str);
a_jni_env.DeleteLocalRef(msg_obj);
}
// Append stack trace messages if there are any.
if (frames_length > 0)
{
jsize i = 0;
for (i = 0; i < frames_length; i++)
{
// Get the string returned from the 'toString()'
// method of the next frame and append it to
// the error message.
jobject frame = a_jni_env.GetObjectArrayElement(frames, i);
jstring msg_obj =
(jstring) a_jni_env.CallObjectMethod(frame,
a_mid_frame_toString);
const char* msg_str = a_jni_env.GetStringUTFChars(msg_obj, 0);
a_error_msg += "\n ";
a_error_msg += msg_str;
a_jni_env.ReleaseStringUTFChars(msg_obj, msg_str);
a_jni_env.DeleteLocalRef(msg_obj);
a_jni_env.DeleteLocalRef(frame);
}
}
// If 'a_exception' has a cause then append the
// stack trace messages from the cause.
if (0 != frames)
{
jthrowable cause =
(jthrowable) a_jni_env.CallObjectMethod(
a_exception,
a_mid_throwable_getCause);
if (0 != cause)
{
_append_exception_trace_messages(a_jni_env,
a_error_msg,
cause,
a_mid_throwable_getCause,
a_mid_throwable_getStackTrace,
a_mid_throwable_toString,
a_mid_frame_toString);
}
}
}
I copied this from code I wrote a few years ago (modified to eliminate boiler plate ExceptionCheck()s), but I did not compile what I have posted but the general approach is hopefully clear.
If you are just interested in the stack trace of the exception you can:
if (env->ExceptionOccurred()) // check if an exception occurred
{
env->ExceptionDescribe(); // print the stack trace
}
The easy way out of this is to declare the JNI method to throw all possible exceptions, then:
jthrowable throwable = ExceptionOccurred(env);
if (throwable != NULL)
Throw(env, throwable);
and let your Java code deal with it.