JNI Function Causing Android App to Crash - java

I have the following JNI function that sends an event to my Java code.
void onIncrementAchievement(unsigned char _iArgumentCount, const void *_pArguments, void *_pUserData){
JNIEnv *pJNIEnv = GetJNIEnv();
if (pJNIEnv){
if ( _pArguments && ( _iArgumentCount > 0 ) ){
const S3DX::AIVariable *pVariables = (const S3DX::AIVariable *)_pArguments ;
if(_iArgumentCount != 2)
LOGI("INCORRECT NUMBER OF PARAMETERS");
else{
if(pVariables[0].GetType() == S3DX::AIVariable::eTypeString){
// CHANGE ME!
jclass pJNIActivityClass = pJNIEnv->FindClass ( "com/nurfacegames/testgame01/TestGame01" );
if(pJNIActivityClass == NULL)
LOGI("jclass was null!?!");
else{
jmethodID pJNIMethodID = pJNIEnv->GetStaticMethodID(pJNIActivityClass, "onIncrementAchievement", "(Ljava/lang/String;Ljava/lang/Integer;)V");
if(pJNIMethodID == NULL)
LOGI("jmethodID was null!?!?");
else{
//Create a new string
jstring arg;
arg = pJNIEnv->NewStringUTF(pVariables[0].GetStringValue());
jint arg2 = pVariables[1].GetNumberValue();
//Call the method and pass the string parameter along
pJNIEnv->CallStaticVoidMethod(pJNIActivityClass, pJNIMethodID, arg, arg2);
//Free the string
pJNIEnv->DeleteLocalRef(arg);
}
}
}
}
}
}
}
When I run my Android App, it force closes without even giving a single error in logcat, and when I compile with Ant, there are no compile errors.
I hate to post such a vague question, but if someone has an idea what is wrong with my JNI code, please give me a hint. Thanks!
The areas that I think have a problem (that I have been working on) are:
if(_iArgumentCount != 2)
LOGI("INCORRECT NUMBER OF PARAMETERS");
else{
and this section:
jint arg2 = pVariables[1].GetNumberValue();
pJNIEnv->CallStaticVoidMethod(pJNIActivityClass, pJNIMethodID, arg, arg2);
Thanks!

Well, look at your method name void onIncrementAchievement, as far as I know, that isn't the right way to declare your method in native section, it should be:
Java_com_example_yourpackagename_youractivityname_yourmethod(...)
And one more thing, the arguments in your method are also wrong I guess, check out this tutorial.

Related

A fatal error while creating java instance from c++ using NewObject JNI

I am trying to call Java methods from c++ using JNI. According to my understanding when c++ wants to access non static java methods we need to have instance to java to access those methods.
I am getting runtime error and I am not able to understand where exactly the error is but my code is breaking.I tracked by cout and its breaking while creating the instance
Error is : V [libjvm.so+0x2c3253] methodHandle::methodHandle(Method)+0x33*
And my code is like this:
.h file
static jclass clsEventStatus;
static jmethodID constructorEventStatus;
jobject EventStatusInstance;
.cpp file
jclass EventStatusJNI::clsEventStatus;
jmethodID EventStatusJNI::constructorEventStatus;
int EventStatusJNI::initialize() {
if(clsEventStatus==0) {
clsEventStatus = StubJava::env->FindClass("metronome/EventStatus");//no error
if(clsEventStatus == 0){
std::cout<<"class Eventstatus Not found";
}
constructorEventStatus = StubJava::env->GetMethodID(clsEventStatus, "<init>", "()V");//no error
return 0;
}
return 1;
}
EventStatusJNI::EventStatusJNI(){
EventStatusInstance = StubJava::env->NewObject(clsEventStatus, constructorEventStatus); //its breaking here when call happens
if(EventStatusInstance == 0 ){std::cout<<"No EventStatusInstance found ";}
}
In .java file:
public class EventStatus {
public EventStatus(){
System.out.println("Entered Event status.java");
setStatusValue(EventStatusValue.PROCESSING);
}
}
thank you for your time!

matlab calling Findclass JNI crashes

I´m trying to call java methods from simulink Matlab using JNI. I developed a small code in C++ that calls a main method which only prints helloworld on screen as a first test but at the line that it calls to find the class, matlab crashes.
The C++ code is this :
#include <stdio.h>
#include <jni.h>
#include "mex.h"
class MatlabAmbassador {
public:
MatlabAmbassador ();
//Destructor
~MatlabAmbassador ();
void run();
JNIEnv* create_vm() ;
void invoke_class(JNIEnv* env);
private:
}; // end class
MatlabAmbassador::MatlabAmbassador() {
}
MatlabAmbassador::~MatlabAmbassador() {
}
// -------------------------------------------------------------------------
JNIEnv* MatlabAmbassador::create_vm() {
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[1];
long status;
/* There is a new JNI_VERSION_1_4, but it doesn't add anything for the purposes of our example. */
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
options[0].optionString = "-Djava.class.path=C:\\Apps\\Projetos em java\\Portico\\Portico_Agent\\bin";
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
status=JNI_CreateJavaVM(&jvm, (void **)&env, &args);
return env;
}
// -------------------------------------------------------------------------
void MatlabAmbassador::invoke_class(JNIEnv* env) {
jclass helloWorldClass;
jmethodID mainMethod;
jobjectArray applicationArgs;
jstring applicationArg0;
mexPrintf("First\n");
helloWorldClass = env->FindClass("Teste"); <--- MATLAB CRASHES HERE
mexPrintf("second\n");
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
env->ExceptionClear() ;
}
if ( helloWorldClass == NULL ) {
mexPrintf( "%s%s\n", "Unable to obtain class reference for ",
helloWorldClass );
return;
} else {
mexPrintf( "%s%s\n", "Sucessfully created class reference for ",
helloWorldClass );
}
mainMethod = env->GetStaticMethodID( helloWorldClass, "main", "([Ljava/lang/String;)V");
applicationArgs = env->NewObjectArray(1, env->FindClass("java/lang/String"), NULL);
applicationArg0 = env->NewStringUTF( "From-C-program");
env->SetObjectArrayElement( applicationArgs, 0, applicationArg0);
env->CallStaticVoidMethod( helloWorldClass, mainMethod, applicationArgs);
}
// -------------------------------------------------------------------------
void MatlabAmbassador::run() {
char str [80];
mexPrintf(" INITIALIZING....\n" );
JNIEnv* env = create_vm();
invoke_class( env );
}
// -------------------------------------------------------------------------
Simulink Matlab has some methods to be used. One of this method is used to call the method run() described above. Here follows a piece of code:
static void mdlStart(SimStruct *S)
{
char *buf;
size_t buflen;
int status;
buflen = mxGetN((ssGetSFcnParam(S, 2)))*sizeof(mxChar)+1 ; // le o 3o parametro passado pela funcao (nome do arq)
buf = (char *)mxMalloc(buflen); // aloca memoria
status = mxGetString((ssGetSFcnParam(S, 2)), buf,(mwSize)buflen);
ssGetPWork(S)[0] = (void *) new MatlabAmbassador; // store new C++ object in the
MatlabAmbassador *c = (MatlabAmbassador *) ssGetPWork(S)[0];
c->run();
and the simple java code is:
public class Teste
{
public static void main(String[] args)
{
System.out.println(" INITALIZING...");
}
}
So, can anyone explain what am I missing or explain if there is a real problem calling JNI inside Matlab. Matlab is version 2011b and java version installed is JDK 1.0.6_45.
I´d appreciate any help as soon as possible.
Best regards
André Nudel
andre.nudel#gmail.com
Are you sure JNI_CreateJavaVM succeeds? Your code is not checking the returned status code or resulting env value (which is not getting initialized, so it may contain garbage), and the crash is apparently occurring at the first attempt to use env.
If you're running this inside Matlab, the JVM creation may be failing because there's already a JVM running inside the process as part of Matlab's normal environment. The JNI documents say that "creation of multiple VMs in a single process is not supported" (http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/invocation.html#wp636). If this is what's happening, JNI_CreateJavaVM will return JNI_EEXIST (-5). Even if that's not what's going on here, it's good practice to check the status codes returned from functions that can fail. The examples in the JNI documentation omit error checking "for clarity", but you should include it in code you're actually going to run.
Check the status returned by JNI_CreateJavaVM and print it out to make sure it's succeeding. And maybe initialize env to 0 so it's clear whether you got a pointer from JNI or just random data.
I am not very familiar with Simulink, so I'm showing an example of a regular MEX-function instead.
As suggested by #AndrewJanke, I retrieve the existing JVM instance running inside the MATLAB process instead of creating a new one.
jni.cpp
#include "mex.h"
#include "jni.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
// get MATLAB Java virtual machine instance
JavaVM *vm = NULL;
int n; jint res;
res = JNI_GetCreatedJavaVMs(&vm, 1, (jsize*) &n);
if (res != JNI_OK || n != 1) {
mexErrMsgIdAndTxt("mex:jni", "Couldn't find existing Java VM");
}
// get JNI interface instance
JNIEnv *env = NULL;
res = vm->GetEnv((void**) &env, JNI_VERSION_1_6);
if (res != JNI_OK || env == NULL) {
mexErrMsgIdAndTxt("mex:jni", "Couldn't get Java JNI environment");
}
mexPrintf("using Java %d.%d\n",
env->GetVersion() >> 16, env->GetVersion() & 0xFFFF);
}
I compiled the file using:
mex -I"C:\Program Files\Java\jdk1.6.0_45\include"
-I"C:\Program Files\Java\jdk1.6.0_45\include\win32" jni.cpp
"C:\Program Files\Java\jdk1.6.0_45\lib\jvm.lib"
Run in MATLAB, I get:
>> jni
using Java 1.6
You should be able to extend the example above to call an external Java class. Note that I have not been able to pass data between MATLAB MEX-API and Java JNI API (by that I mean passing Java objects as they are to a MEX-function, or the other way around, passing some kind of jobject back directly as is to MATLAB, without conversion that is), as in:
>> x = java.lang.Double(1)
>> my_mex_jni_fcn(x)
The problem is that mxArray is an opaque type, so I do not know how to interpret the pointer returned by mxGetData

JNI method returns old data

I've spent whole day on this problem and still have no idea how to solve it.
Here is the simplified code
JAVA
class javaclass{
private volatile boolean isTerminated;
public void javamethod()
{
log.logInfo("java :"+isTerminated());
}
public int isTerminated()
{
return (isTerminated) ? 1 : 0;
}
public doJob()
{
executeNative();
}
private native int executeNative() throws Exception;
}
C++
bool cmethod()
{
cerr &lt&lt "JNI " &lt&lt wrapper::isTerminated() &lt&lt "\n";
if(wrapper::isTerminated)
return false;
jni->CallVoidMethod(self, apiJavamethod, xPoint);
return true;
//apiJavamethod is jMethodId of javamethod
}
int wrapper::isTerminated()
{
return jni->CallIntMethod(self, apiIsTerminated);
}
JNIEXPORT jint JNICALL NAMESPACE_javaclass_executeNative(JNIEnv* env, jobject self) {
for(int i=0;i &lt _ITERATIONS;++i)
{
if(!cmethod())
break;
}
}
C++ cmethod is executed in some loop, which stops when C++ catches isTerminated().
In output i see:
....
....
in log:
java 0
java 1
java 1
java 1
in console:
JNI 0
JNI 0
JNI 0
JNI 1
So, JNI is somehow behind the real state of variable.
It produces an important bug in application (((
Maybe it's some problem with java itself? (v.1.5, i forced to used it)
Any help is greatly appreciated.
I would suggest doing all the synchronization in one language or the other. It's looking like "volatile" isn't being respected across the boundary for some reason. Something like:
public doJob()
{
while(!isTerminated)
executeNative();
}

Why does my JNI code not successfully find a jthrowable's getMessage method?

I'm trying to access the message in a jthrowable while handing an exception generated when I fail to find a class. However, I am unable to access the message ID of getMessage() on the jthrowable object, and I don't know why. I've tried changing the signature of getMessage to "()Ljava/lang/String" (without the semicolon at the end, but that's necessary, right?) with no joy. I'm confused as hell about this. I even tried replacing getMessage with toString, and that didn't work. Obviously I'm doing something trivially wrong here.
Here's the code I'm using:
jthrowable java_exception;
jclass java_class;
jmethodID method;
java_exception = (*jEnv)->ExceptionOccurred(jEnv);
assert (java_exception != NULL);
java_class = (*jEnv)->GetObjectClass (jEnv, java_exception);
assert (java_class != NULL);
method = (*jEnv)->GetMethodID (jEnv, java_class, "getMessage", "()Ljava/lang/String;");
if (method == NULL) {
printf ("Seriously, how do I get here?!\n");
(*jEnv)->ExceptionDescribe (jEnv);
return;
}
The output of this code (amongst other things) looks like this:
Seriously, how do I get here?!
Exception in thread "main" java.lang.NoClassDefFoundError: com/planet/core360/docgen/Processor
javap -p -s java.lang.Throwable gives me this:
Compiled from "Throwable.java"
public class java.lang.Throwable extends java.lang.Object implements java.io.Serializable{
...
public java.lang.String getMessage();
Signature: ()Ljava/lang/String;
...
Okay, so it looks like my problem was that GetObjectClass doesn't act the way you'd expect it to on a jthrowable, or at least the results of it are not useful for the purposes of getting methods. Replacing that portion of the code with this works:
java_class = (*jEnv)->FindClass (jEnv, "java/lang/Throwable");
method = (*jEnv)->GetMethodID (jEnv, java_class, "getMessage", "()Ljava/lang/String;");
Damnably odd, that. I hope this helps someone else in the future, though.
I tried your approach, and it worked for me. A few things though: I'm using the C++ interface (though that shouldn't make a difference), and I'm using Java 6 update 10, x64 edition, on Ubuntu 8.04. Perhaps the Java version and/or platform used will make a difference.
#include <cstdio>
#include <jni.h>
int
main(int argc, char** argv)
{
if (argc != 3) {
std::fprintf(stderr, "usage: %s class message\n", argv[0]);
return 1;
}
JavaVM* jvm;
void* penv;
JavaVMInitArgs args = {JNI_VERSION_1_6};
if (jint res = JNI_CreateJavaVM(&jvm, &penv, &args)) {
std::fprintf(stderr, "Can's create JVM: %d\n", res);
return -res;
}
JNIEnv* env(static_cast<JNIEnv*>(penv));
jint vers(env->GetVersion());
std::printf("JNI version %d.%d\n", vers >> 16, vers & 0xffff);
env->ThrowNew(env->FindClass(argv[1]), argv[2]);
jthrowable exc(env->ExceptionOccurred());
std::printf("Exception: %p\n", exc);
if (exc) {
jclass exccls(env->GetObjectClass(exc));
jclass clscls(env->FindClass("java/lang/Class"));
jmethodID getName(env->GetMethodID(clscls, "getName", "()Ljava/lang/String;"));
jstring name(static_cast<jstring>(env->CallObjectMethod(exccls, getName)));
char const* utfName(env->GetStringUTFChars(name, 0));
jmethodID getMessage(env->GetMethodID(exccls, "getMessage", "()Ljava/lang/String;"));
jstring message(static_cast<jstring>(env->CallObjectMethod(exc, getMessage)));
char const* utfMessage(env->GetStringUTFChars(message, 0));
std::printf("Exception: %s: %s\n", utfName, utfMessage);
env->ReleaseStringUTFChars(message, utfMessage);
env->ReleaseStringUTFChars(name, utfName);
}
return -jvm->DestroyJavaVM();
}
I've used jnitest java/lang/InternalError 'Hello, world!' for my testing; feel free to try with different exception types!

Best way to throw exceptions in JNI code?

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;
}

Categories