singhsumit
singhsumit

Reputation: 974

AttachCurrentThread crashing

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

Answers (2)

Valeri Atamaniouk
Valeri Atamaniouk

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, &params);
  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

yushulx
yushulx

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

Related Questions