Reputation: 974
The app crashes if following function is called:
void on_log(JavaVM* vm, int level, const char *data)
{
printOnAndroid(level, data);
pthread_t loggerThread;
pthread_create(&loggerThread, NULL, attachThreadToJavaVMAndPrint, data);
pthread_join(loggerThread, NULL);
}
void attachThreadToJavaVMAndPrint(JavaVM* vm, const char *data)
{
int isThreadAttached = attachJNIEnvToThread(vm);
if (isThreadAttached == 1)
{
JNIEnv* env;
(*vm)->GetEnv(vm, &env, APP_JNI_VERSION);
jclass thisClass = (*env)->GetObjectClass(env, _loggerObject);
jmethodID methodId = (*env)->GetMethodID(env, thisClass, "logFromC","(Ljava/lang/String;)V");
if (methodId != NULL)
{
jstring message = (*env)->NewStringUTF(env, data);
(*env)->CallVoidMethod(env, _loggerObject, methodId, message);
}
(*vm)->DetachCurrentThread(vm);
}
}
void printOnAndroid(int level, const char* data)
{
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "XXXX %i, data %s", level, data);
}
int attachJNIEnvToThread(JavaVM* vm)
{
JNIEnv* env;
JavaVMAttachArgs args;
args.version = APP_JNI_VERSION;
args.name = NULL;
args.group = NULL;
if ((*vm)->GetEnv(vm, &env, APP_JNI_VERSION) == JNI_EDETACHED)
{
jint attachResponse = (*vm)->AttachCurrentThread(vm, &env, &args);
if ((*vm)->GetEnv(vm, &env, APP_JNI_VERSION) != JNI_OK)
{
return 0;
}
}
return 1;
}
There is a macro:
#define APP_JNI_VERSION JNI_VERSION_1_2
As per logs, there is a crash when attachJNIEnvToThread(..) is called
EDIT:
It runs successfully on linux.. so may be there is something android specific that I am not aware of.
EDIT 2:
Changed the signature of the following:
void * attachThreadToJavaVMAndPrint(void* dataArg)
{
JavaVM* vm = _vm;
const char* data = (const char *)dataArg;
int isThreadAttached = attachJNIEnvToThread(vm);
if (isThreadAttached == 1)
{
JNIEnv* env;
(*vm)->GetEnv(vm, &env, APP_JNI_VERSION);
jclass thisClass = (*env)->GetObjectClass(env, _loggerObject);
jmethodID methodId = (*env)->GetMethodID(env, thisClass, "logFromC","(Ljava/lang/String;)V");
if (methodId != NULL)
{
jstring message = (*env)->NewStringUTF(env, data);
(*env)->CallVoidMethod(env, _loggerObject, methodId, message);
}
(*vm)->DetachCurrentThread(vm);
}
return 0;
}
This changes the log slightly and the crash is in attachThreadToJavaAndPrint(..)
EDIT 3:
This has been solved.. Final changes included Edit 2 + some changes in java code (not visible here (there were bugs in it))..
Upvotes: 3
Views: 5537
Reputation: 5163
The problematic place in your code is when you create thread. The thread function takes ONE pointer, not two.
So, you can either give it VM*
, or data
, or wrap them into some structure.
Example of wrapping:
struct params
{
JavaVM *vm;
char *data;
};
void on_log(JavaVM* vm, int level, const char *data)
{
struct params params = {vm, data};
printOnAndroid(level, data);
pthread_t loggerThread;
pthread_create(&loggerThread, NULL, attachThreadToJavaVMAndPrint, ¶ms);
pthread_join(loggerThread, NULL);
}
void * attachThreadToJavaVMAndPrint(void* arg)
{
struct params *params = arg;
JavaVM* vm = params->vm;
const char* data = params->data;
...
Second problem is in thread attachment: you can't get JNIEnv before attaching to thread:
int attachJNIEnvToThread(JavaVM* vm)
{
JNIEnv* env;
return (*vm)->AttachCurrentThread(vm, &env, NULL) ? 1 : 0;
}
Upvotes: 1
Reputation: 12150
First, make sure the parameter vm is correct in void on_log(JavaVM* vm, int level, const char *data)
. I saved the vm as an global variable in JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
, and my code can work:
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
g_vm = vm;
}
in the function for thread
{
ret = g_vm->AttachCurrentThread( (JNIEnv **) &env, NULL);
}
Upvotes: 1