void JNIExecutor::frameworkMessage(ExecutorDriver* driver, const string& data)
{
  jvm->AttachCurrentThread((void**) &env, NULL);

  jclass clazz = env->GetObjectClass(jdriver);

  jfieldID exec = env->GetFieldID(clazz, "exec", "Lorg/apache/mesos/Executor;");
  jobject jexec = env->GetObjectField(jdriver, exec);

  clazz = env->GetObjectClass(jexec);

  // exec.frameworkMessage(driver, data);
  jmethodID frameworkMessage =
    env->GetMethodID(clazz, "frameworkMessage",
		     "(Lorg/apache/mesos/ExecutorDriver;"
		     "[B)V");

  // byte[] data = ..;
  jbyteArray jdata = env->NewByteArray(data.size());
  env->SetByteArrayRegion(jdata, 0, data.size(), (jbyte*) data.data());

  env->ExceptionClear();

  env->CallVoidMethod(jexec, frameworkMessage, jdriver, jdata);

  if (env->ExceptionOccurred()) {
    env->ExceptionDescribe();
    env->ExceptionClear();
    jvm->DetachCurrentThread();
    driver->stop();
    this->error(driver, -1, "Java exception caught");
    return;
  }

  jvm->DetachCurrentThread();
}
Esempio n. 2
0
void Thread::DetachFromJVM()
{
    if (true == IsMainThread())
        return;

    DAVA::CorePlatformAndroid *core = (DAVA::CorePlatformAndroid *)DAVA::Core::Instance();
    DAVA::AndroidSystemDelegate* delegate = core->GetAndroidSystemDelegate();
    JavaVM *vm = delegate->GetVM();
    JNIEnv *env;

    if (JNI_OK == vm->GetEnv((void**)&env, JNI_VERSION_1_6))
    {
        if (0 != vm->DetachCurrentThread())
            Logger::Error("runtime_error(Could not detach current thread from JNI)");
    }
}
void callVoidJavaMethod(const char* javaMethodName, string param){
	ANativeActivity* activity = NULL; JavaVM* jvm = NULL; JNIEnv* env = NULL;	
	if(prepareForCallJavaMethod(&activity, &jvm, &env)){
		jclass clazz = env->GetObjectClass(activity->clazz);
		jmethodID methodID = env->GetMethodID(clazz, javaMethodName, "(Ljava/lang/String;)V");
		jstring jStringParam = env->NewStringUTF( param.c_str() );
		if( !jStringParam )
		{ 
			__android_log_print(ANDROID_LOG_ERROR, "MainNativeActivity#callJavaMethod", "Fallo al pasar string de ndk a java");
			return;
		}
		env->CallVoidMethod(activity->clazz, methodID, jStringParam);
		env->DeleteLocalRef( jStringParam );
		jvm->DetachCurrentThread();
	}
}
Esempio n. 4
0
    ~msandroid_sound_write_data() {
        ms_bufferizer_flush(bufferizer);
        ms_bufferizer_destroy(bufferizer);
        ms_cond_destroy(&cond);
        if (audio_track_class!=0) {
            //JNIEnv *env = ms_get_jni_env();

            JNIEnv *env = NULL;
            JavaVM *jvm = ms_get_jvm();
            if (jvm->AttachCurrentThread(&env, NULL)!=0) {
                ms_fatal("AttachCurrentThread() failed !");
            }
            env->DeleteGlobalRef(audio_track_class);
            jvm->DetachCurrentThread();
        }
    }
Esempio n. 5
0
void GoogleStoreFront::makePayment(const char * productID, int quantity, const char * usernameHash)
{
    android_app* app = __state;
    JNIEnv* env = app->activity->env;
    JavaVM* vm = app->activity->vm;
    vm->AttachCurrentThread(&env, NULL);

    jstring paramString = env->NewStringUTF(productID);

    while (quantity-- > 0)
        env->CallVoidMethod(app->activity->clazz, __midPurchaseItem, paramString);

    vm->DetachCurrentThread();

    getListener()->paymentTransactionInProcessEvent(productID, quantity);
}
Esempio n. 6
0
/**
 * Used for user supplied input/output functions.  See initDxClass();
 */
int dx_uio_read (int fd, char* ptr, unsigned cnt) {
	JavaVM *vm = jvr_getVM();
	JNIEnv *e;
	int detach = 0;
	if (vm->GetEnv((void **)&e, JNI_VERSION_1_2) != JNI_OK) {
		vm->AttachCurrentThread((void**)&e,&attachArgs);
		detach = 1;
	}
	if (e->ExceptionOccurred()) {
		e->ExceptionDescribe();
		e->ExceptionClear();
		return -1;
	}

  jcharArray charArray = (jcharArray) e->CallStaticObjectMethod(dx_class, dx_uio_read_method, (jint) fd, (jint) cnt);
	if (e->ExceptionOccurred()) {
		e->ExceptionDescribe();
		e->ExceptionClear();
		if (detach) { vm->DetachCurrentThread(); }
		return -1;
	}
	if (charArray == NULL) {
		// EOF
		if (detach) { vm->DetachCurrentThread(); }
		return -1;
	}

	int buflen = e->GetArrayLength(charArray);
	if (e->ExceptionOccurred()) {
		e->ExceptionDescribe();
		e->ExceptionClear();
		if (detach) { vm->DetachCurrentThread(); }
		return -1;
	}
	if (buflen == 0) {
		// EOF aka no data
		if (detach) { vm->DetachCurrentThread(); }
		return -1;
	}

	jchar* bufp = (jchar*) e->GetCharArrayElements(charArray,0);
	if (e->ExceptionOccurred()) {
		e->ExceptionDescribe();
		e->ExceptionClear();
		if (detach) { vm->DetachCurrentThread(); }
		return -1;
	}

	memcpy(ptr,bufp,buflen);
	e->ReleaseCharArrayElements(charArray, bufp, JNI_ABORT);
	e->DeleteLocalRef(charArray);
	if (detach) { vm->DetachCurrentThread(); }
	return buflen;
}
static void report_exception(JNIEnv* env, jthrowable excep, const char* msg)
{
    env->ExceptionClear();

    jstring tagstr = env->NewStringUTF(LOG_TAG);
    jstring msgstr = env->NewStringUTF(msg);

    if ((tagstr == NULL) || (msgstr == NULL)) {
        env->ExceptionClear();      /* assume exception (OOM?) was thrown */
        ALOGE("Unable to call Log.e()\n");
        ALOGE("%s", msg);
        goto bail;
    }

    env->CallStaticIntMethod(
        gLogOffsets.mClass, gLogOffsets.mLogE, tagstr, msgstr, excep);
    if (env->ExceptionCheck()) {
        /* attempting to log the failure has failed */
        ALOGW("Failed trying to log exception, msg='%s'\n", msg);
        env->ExceptionClear();
    }

    if (env->IsInstanceOf(excep, gErrorOffsets.mClass)) {
        /*
         * It's an Error: Reraise the exception, detach this thread, and
         * wait for the fireworks. Die even more blatantly after a minute
         * if the gentler attempt doesn't do the trick.
         *
         * The GetJavaVM function isn't on the "approved" list of JNI calls
         * that can be made while an exception is pending, so we want to
         * get the VM ptr, throw the exception, and then detach the thread.
         */
        JavaVM* vm = jnienv_to_javavm(env);
        env->Throw(excep);
        vm->DetachCurrentThread();
        sleep(60);
        ALOGE("Forcefully exiting");
        exit(1);
        *((int *) 1) = 1;
    }

bail:
    /* discard local refs created for us by VM */
    env->DeleteLocalRef(tagstr);
    env->DeleteLocalRef(msgstr);
}
// Called by the HAL to notify us of fingerprint events
static void hal_notify_callback(fingerprint_msg_t msg) {
    uint32_t arg1 = 0;
    uint32_t arg2 = 0;
    uint32_t arg3 = 0; // TODO
    switch (msg.type) {
        case FINGERPRINT_ERROR:
            arg1 = msg.data.error;
            break;
        case FINGERPRINT_ACQUIRED:
            arg1 = msg.data.acquired.acquired_info;
            break;
        case FINGERPRINT_PROCESSED:
            arg1 = msg.data.processed.id;
            break;
        case FINGERPRINT_TEMPLATE_ENROLLING:
            arg1 = msg.data.enroll.id;
            arg2 = msg.data.enroll.samples_remaining;
            arg3 = msg.data.enroll.data_collected_bmp;
            break;
        case FINGERPRINT_TEMPLATE_REMOVED:
            arg1 = msg.data.removed.id;
            break;
        default:
            ALOGE("fingerprint: invalid msg: %d", msg.type);
            return;
    }
    //ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2);

	// TODO: fix gross hack to attach JNI to calling thread
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    JavaVM* vm = NULL;
    if (env == NULL) {
        JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
        vm = AndroidRuntime::getJavaVM();
        int result = vm->AttachCurrentThread(&env, (void*) &args);
        if (result != JNI_OK) {
            ALOGE("Can't call JNI method: attach failed: %#x", result);
            return;
        }
    }
    env->CallVoidMethod(gFingerprintServiceClassInfo.callbackObject,
            gFingerprintServiceClassInfo.notify, msg.type, arg1, arg2);
    if (vm != NULL) {
        vm->DetachCurrentThread();
    }
}
int32_t SpiReadAutoReceiveBufferCallbackStore::performCallback(
    const char* name, uint32_t* buffer, int32_t numToRead) {
  JNIEnv* env;
  JavaVM* vm = sim::GetJVM();
  bool didAttachThread = false;
  int tryGetEnv = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
  if (tryGetEnv == JNI_EDETACHED) {
    // Thread not attached
    didAttachThread = true;
    if (vm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr) != 0) {
      // Failed to attach, log and return
      wpi::outs() << "Failed to attach\n";
      wpi::outs().flush();
      return -1;
    }
  } else if (tryGetEnv == JNI_EVERSION) {
    wpi::outs() << "Invalid JVM Version requested\n";
    wpi::outs().flush();
  }

  auto toCallbackArr = MakeJIntArray(
      env, wpi::ArrayRef<uint32_t>{buffer, static_cast<size_t>(numToRead)});

  jint ret = env->CallIntMethod(m_call, sim::GetBufferCallback(),
                                MakeJString(env, name), toCallbackArr,
                                (jint)numToRead);

  jint* fromCallbackArr = reinterpret_cast<jint*>(
      env->GetPrimitiveArrayCritical(toCallbackArr, nullptr));

  for (int i = 0; i < ret; i++) {
    buffer[i] = fromCallbackArr[i];
  }

  env->ReleasePrimitiveArrayCritical(toCallbackArr, fromCallbackArr, JNI_ABORT);

  if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
  }

  if (didAttachThread) {
    vm->DetachCurrentThread();
  }
  return ret;
}
static void callback_thread_event(bt_cb_thread_evt event) {
    JavaVM* vm = AndroidRuntime::getJavaVM();
    if (event  == ASSOCIATE_JVM) {
        JavaVMAttachArgs args;
        char name[] = "BT Service Callback Thread";
        args.version = JNI_VERSION_1_6;
        args.name = name;
        args.group = NULL;
        vm->AttachCurrentThread(&callbackEnv, &args);
        ALOGV("Callback thread attached: %p", callbackEnv);
    } else if (event == DISASSOCIATE_JVM) {
        if (!checkCallbackThread()) {
            ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
            return;
        }
        vm->DetachCurrentThread();
    }
}
Esempio n. 11
0
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
extern "C" void SuspendSleep( int bStopSleep )
{
	static jobject  WindowManager_LayoutParams_FLAG_KEEP_SCREEN_ON;

    // Attaches the current thread to the JVM. 
    jint lResult; 
    jint lFlags = 0; 

    JavaVM* lJavaVM = engine.app->activity->vm; 
    JNIEnv* lJNIEnv = engine.app->activity->env; 

    JavaVMAttachArgs lJavaVMAttachArgs; 
    lJavaVMAttachArgs.version = JNI_VERSION_1_6; 
    lJavaVMAttachArgs.name = "NativeThread"; 
    lJavaVMAttachArgs.group = NULL; 

    lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs);
    if (lResult == JNI_ERR) { 
        return; 
    } 

    // Retrieves NativeActivity. 
    jobject lNativeActivity = engine.app->activity->clazz; 
	jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity);

	if( bStopSleep )
	{
		jmethodID MethodSetFlags = lJNIEnv->GetMethodID(      ClassNativeActivity, "setSuspendSleep", "()V");
      LOGI( "suspend Sleep" );
		if( MethodSetFlags )
			lJNIEnv->CallVoidMethod( lNativeActivity,  MethodSetFlags );
	}
	else
	{
		jmethodID MethodSetFlags = lJNIEnv->GetMethodID(      ClassNativeActivity, "setAllowSleep", "()V");
		if( MethodSetFlags )
			lJNIEnv->CallVoidMethod( lNativeActivity,  MethodSetFlags );
	}



	// Finished with the JVM. 
	lJavaVM->DetachCurrentThread();
}
string callStringJavaMethod(const char* javaMethodName, string param){
	ANativeActivity* activity = NULL; JavaVM* jvm = NULL; JNIEnv* env = NULL;	
	string result;
	if(prepareForCallJavaMethod(&activity, &jvm, &env)){
		jclass clazz = env->GetObjectClass(activity->clazz);
		jmethodID methodID = env->GetMethodID(clazz, javaMethodName, "(Ljava/lang/String;)Ljava/lang/String;");
		jstring jStringParam = env->NewStringUTF( param.c_str() );
		if( !jStringParam )
		{ 
			__android_log_print(ANDROID_LOG_ERROR, "NativeActivityConnector#callStringJavaMethod", "Fallo al pasar string de ndk a java");
			return result;
		}
		jstring jresult = (jstring) env->CallObjectMethod(activity->clazz, methodID, jStringParam);
		result = jstringToString(jresult, env);
		env->DeleteLocalRef( jStringParam );
		jvm->DetachCurrentThread();
	}
	return result;
}
Esempio n. 13
0
/**
 * Used for user supplied input/output functions.  See initDxClass();
 */
long dx_uio_seek (int fd, long offset, int whence) {

	JavaVM *vm = jvr_getVM();
	JNIEnv *e;
	int detach = 0;
	if (vm->GetEnv((void **)&e, JNI_VERSION_1_2) != JNI_OK) {
		vm->AttachCurrentThread((void**)&e,&attachArgs);
		detach = 1;
	}
	if (e->ExceptionOccurred()) {
		e->ExceptionDescribe();
		e->ExceptionClear();
		return -1;
	}
	long ret = e->CallStaticLongMethod(dx_class,dx_uio_seek_method,(jint) fd,(jlong) offset,(jint) whence);
	if (detach) { vm->DetachCurrentThread(); }
	return ret;

}
Esempio n. 14
0
int GetUnicodeChar(struct android_app* app, int eventType, int keyCode, int metaState)
{
JavaVM* javaVM = app->activity->vm;
JNIEnv* jniEnv = app->activity->env;

JavaVMAttachArgs attachArgs;
attachArgs.version = JNI_VERSION_1_6;
attachArgs.name = "NativeThread";
attachArgs.group = NULL;

jint result = javaVM->AttachCurrentThread(&jniEnv, &attachArgs);
if(result == JNI_ERR)
{
    return 0;
}

jclass class_key_event = jniEnv->FindClass("android/view/KeyEvent");
int unicodeKey;

if(metaState == 0)
{
    jmethodID method_get_unicode_char = jniEnv->GetMethodID(class_key_event, "getUnicodeChar", "()I");
    jmethodID eventConstructor = jniEnv->GetMethodID(class_key_event, "<init>", "(II)V");
    jobject eventObj = jniEnv->NewObject(class_key_event, eventConstructor, eventType, keyCode);

    unicodeKey = jniEnv->CallIntMethod(eventObj, method_get_unicode_char);
}

else
{
    jmethodID method_get_unicode_char = jniEnv->GetMethodID(class_key_event, "getUnicodeChar", "(I)I");
    jmethodID eventConstructor = jniEnv->GetMethodID(class_key_event, "<init>", "(II)V");
    jobject eventObj = jniEnv->NewObject(class_key_event, eventConstructor, eventType, keyCode);

    unicodeKey = jniEnv->CallIntMethod(eventObj, method_get_unicode_char, metaState);
}

javaVM->DetachCurrentThread();

LOGI("Unicode key is: %d", unicodeKey);
return unicodeKey;
}
Esempio n. 15
0
/****************************************************************************
Desc:
****************************************************************************/
RCODE JNIBackupStatus::backupStatus(
	FLMUINT64		ui64BytesToDo,
	FLMUINT64		ui64BytesDone)
{
	RCODE				rc = NE_XFLM_OK;
	JNIEnv *			pEnv;
	jclass			Cls;
	jmethodID		MId;
	FLMBOOL			bMustDetach = FALSE;
	
	if (m_pJvm->GetEnv( (void **)&pEnv, JNI_VERSION_1_2) != JNI_OK)
	{
		if (m_pJvm->AttachCurrentThread( (void **)&pEnv, NULL) != 0)
		{
			rc = RC_SET(NE_XFLM_FAILURE);	
			goto Exit;
		}
		
		bMustDetach = TRUE;
	}

	Cls = pEnv->GetObjectClass( m_jStatus);
	MId = pEnv->GetMethodID( Cls, "backupStatus", "(JJ)I");
	flmAssert( MId);
		
	rc = (RCODE)pEnv->CallIntMethod( m_jStatus, MId, (jlong)ui64BytesToDo,
									 (jlong)ui64BytesDone);
									  
Exit:

	if (bMustDetach)
	{
		if (m_pJvm->DetachCurrentThread() != 0)
		{
			flmAssert( 0);
			rc = RC_SET( NE_XFLM_FAILURE);
		}
	}

	return( rc);
}
Esempio n. 16
0
JniCallbackHelper::~JniCallbackHelper() {

	if (mMethodId != 0) {
		if (mEnv->ExceptionCheck()) {
			JNI_HELPER_LOGE(
					"There was an exception thrown from the Java method!!");
			mEnv->ExceptionClear();
		}
	}
	for (std::vector<jobject>::iterator it = mNewJavaObjects.begin();
			it != mNewJavaObjects.end(); ++it) {
		mEnv->DeleteLocalRef(*it);
	}

	mEnv->DeleteGlobalRef(mJObject);

	if (JNI_EDETACHED == mGetEnvResult) {
		JavaVM * vm;
		mEnv->GetJavaVM(&vm);
		vm->DetachCurrentThread();
	}
}
void OpenSLMediaPlayerHQVisualizerJNIBinder::onLeaveInternalPeriodicCaptureThread(
    OpenSLMediaPlayerHQVisualizer *visualizer) noexcept
{
    LOGD("onLeaveInternalPeriodicCaptureThread()");

    JavaVM *vm = jvm_;

    if (jvm_attached_) {
        // release global references
        for (auto &t : jwaveform_data_) {
            t.release(env_);
        }
        for (auto &t : jfft_data_) {
            t.release(env_);
        }

        // detach
        (void)vm->DetachCurrentThread();
        jvm_attached_ = false;
    }
    env_ = nullptr;
}
Esempio n. 18
0
void GoogleStoreFront::getProducts(const char ** productIDs) const
{
    __products.clear();
    __requestedProducts.clear();

    android_app* app = __state;
    JNIEnv* env = app->activity->env;
    JavaVM* vm = app->activity->vm;
    vm->AttachCurrentThread(&env, NULL);

    while (*productIDs)
    {
        __requestedProducts.insert(*productIDs);

        jstring paramString = env->NewStringUTF(*productIDs++);
        env->CallVoidMethod(app->activity->clazz, __midQueueSKURequest, paramString);
    }

    env->CallVoidMethod(app->activity->clazz, __midFlushSkuDetailsQueue);

    vm->DetachCurrentThread();
}
Esempio n. 19
0
int closeKeyboardIME()
{
    ANativeActivity *activity = sf::getNativeActivity();
    JavaVM* vm = activity->vm;
    JNIEnv* env = activity->env;
    JavaVMAttachArgs attachargs;
    attachargs.version = JNI_VERSION_1_6;
    attachargs.name = "NativeThread";
    attachargs.group = NULL;
    jint res = vm->AttachCurrentThread(&env, &attachargs);
    if (res == JNI_ERR)
        return EXIT_FAILURE;

    jclass natact = env->FindClass("android/app/NativeActivity");
    jclass context = env->FindClass("android/content/Context");

    jfieldID fid = env->GetStaticFieldID(context, "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
    jobject svcstr = env->GetStaticObjectField(context, fid);


    jmethodID getss = env->GetMethodID(natact, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
    jobject imm_obj = env->CallObjectMethod(activity->clazz, getss, svcstr);

    jclass imm_cls = env->GetObjectClass(imm_obj);
    jmethodID toggleSoftInput = env->GetMethodID(imm_cls, "toggleSoftInput", "(II)V");

    env->CallVoidMethod(imm_obj, toggleSoftInput, 1, 0);

    env->DeleteLocalRef(imm_obj);
    env->DeleteLocalRef(imm_cls);
    env->DeleteLocalRef(svcstr);
    env->DeleteLocalRef(context);
    env->DeleteLocalRef(natact);

    vm->DetachCurrentThread();

    return EXIT_SUCCESS;
}
Esempio n. 20
0
void show_ads (void)
{
    // Get the android application's activity.
    ANativeActivity* activity = gEngine.app->activity;
    JavaVM* jvm = activity->vm;

    JNIEnv* env = NULL;
    DTboolean needs_detach = false;
    int env_stat = jvm->GetEnv( (void**) &env, JNI_VERSION_1_6);
    if (env_stat == JNI_EDETACHED) {
        jvm->AttachCurrentThread(&env, 0);
        needs_detach = true;
    }
    ASSERT(env);

    jclass c_activity = env->GetObjectClass(activity->clazz);
    jmethodID m_show_ad_popup = env->GetMethodID(c_activity, "showAdPopup", "()V");

    env->CallVoidMethod(activity->clazz, m_show_ad_popup);

    if (needs_detach)
        jvm->DetachCurrentThread();
}
static bool set_wake_alarm_callout(uint64_t delay_millis, bool should_wake, alarm_cb cb, void *data) {
    JNIEnv *env;
    JavaVM *vm = AndroidRuntime::getJavaVM();
    jint status = vm->GetEnv((void **)&env, JNI_VERSION_1_6);
    jboolean ret = JNI_FALSE;

    if (status != JNI_OK && status != JNI_EDETACHED) {
        ALOGE("%s unable to get environment for JNI call", __func__);
        return false;
    }

    if (status == JNI_EDETACHED && vm->AttachCurrentThread(&env, &sAttachArgs) != 0) {
        ALOGE("%s unable to attach thread to VM", __func__);
        return false;
    }

    sAlarmCallback = cb;
    sAlarmCallbackData = data;

    jboolean jshould_wake = should_wake ? JNI_TRUE : JNI_FALSE;
    if (sJniAdapterServiceObj) {
        ret = env->CallBooleanMethod(sJniAdapterServiceObj, method_setWakeAlarm, (jlong)delay_millis, jshould_wake);
    } else {
       ALOGE("JNI ERROR : JNI reference already cleaned : set_wake_alarm_callout", __FUNCTION__);
    }

    if (!ret) {
        sAlarmCallback = NULL;
        sAlarmCallbackData = NULL;
    }

    if (status == JNI_EDETACHED) {
        vm->DetachCurrentThread();
    }

    return !!ret;
}
// static
void *TimedEventQueue::ThreadWrapper(void *me) {

#ifdef ANDROID_SIMULATOR
    // The simulator runs everything as one process, so any
    // Binder calls happen on this thread instead of a thread
    // in another process. We therefore need to make sure that
    // this thread can do calls into interpreted code.
    // On the device this is not an issue because the remote
    // thread will already be set up correctly for this.
    JavaVM *vm;
    int numvms;
    JNI_GetCreatedJavaVMs(&vm, 1, &numvms);
    JNIEnv *env;
    vm->AttachCurrentThread(&env, NULL);
#endif

    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_FOREGROUND);
    static_cast<TimedEventQueue *>(me)->threadEntry();

#ifdef ANDROID_SIMULATOR
    vm->DetachCurrentThread();
#endif
    return NULL;
}
Esempio n. 23
0
    std::string Database::getPath(std::string name) {
        std::string databasePath;
        JNIEnv* env;
        JavaVM* vm = engine->app->activity->vm;
        
        vm->AttachCurrentThread(&env, NULL);

        jclass clazz = env->GetObjectClass(engine->app->activity->clazz);
        jmethodID methodj = env->GetMethodID(clazz, "getDatabasePath", "(Ljava/lang/String;)Ljava/io/File;");
        jobject filej = env->CallObjectMethod(engine->app->activity->clazz, methodj, env->NewStringUTF(name.c_str()));
        if (filej != NULL) {
            clazz = env->GetObjectClass(filej);
            methodj = env->GetMethodID(clazz, "getPath", "()Ljava/lang/String;");
            jstring jstr = (jstring)env->CallObjectMethod(filej, methodj);
            if (jstr != NULL) {
                const char* str = env->GetStringUTFChars(jstr, NULL);
                databasePath = str;
                env->ReleaseStringUTFChars(jstr, str);
            }
        }
        vm->DetachCurrentThread();

        return databasePath;
    }
static int SetThreadEvent(ThreadEvent event) {
  JavaVM* javaVm = AndroidRuntime::getJavaVM();

  switch(event) {
    case ASSOCIATE_JVM:
    {
      if(sCallbackEnv != NULL) {
        ALOGE(
            "Attempted to associate callback in '%s'. Callback already associated.",
            __FUNCTION__
            );
        return FLP_RESULT_ERROR;
      }

      JavaVMAttachArgs args = {
          JNI_VERSION_1_6,
          "FLP Service Callback Thread",
          /* group */ NULL
      };

      jint attachResult = javaVm->AttachCurrentThread(&sCallbackEnv, &args);
      if (attachResult != 0) {
        ALOGE("Callback thread attachment error: %d", attachResult);
        return FLP_RESULT_ERROR;
      }

      ALOGV("Callback thread attached: %p", sCallbackEnv);

      // Send the version to the upper layer.
      sCallbackEnv->CallVoidMethod(
            sCallbacksObj,
            sSetVersion,
            sFlpInterface->size == sizeof(FlpLocationInterface) ? 2 : 1
            );
      CheckExceptions(sCallbackEnv, __FUNCTION__);
      break;
    }
    case DISASSOCIATE_JVM:
    {
      if (!IsValidCallbackThread()) {
        ALOGE(
            "Attempted to dissasociate an unnownk callback thread : '%s'.",
            __FUNCTION__
            );
        return FLP_RESULT_ERROR;
      }

      if (javaVm->DetachCurrentThread() != 0) {
        return FLP_RESULT_ERROR;
      }

      sCallbackEnv = NULL;
      break;
    }
    default:
      ALOGE("Invalid ThreadEvent request %d", event);
      return FLP_RESULT_ERROR;
  }

  return FLP_RESULT_SUCCESS;
}
Esempio n. 25
0
void platformDisplayKeyboard(bool pShow)
{
    jint lResult;
    jint lFlags = 0;

    JavaVM* lJavaVM = gApp->activity->vm;
    JNIEnv* lJNIEnv = gApp->activity->env;

    JavaVMAttachArgs lJavaVMAttachArgs;
    lJavaVMAttachArgs.version = JNI_VERSION_1_6;
    lJavaVMAttachArgs.name = "NativeThread";
    lJavaVMAttachArgs.group = NULL;

    lResult=lJavaVM->AttachCurrentThread(&lJNIEnv,
&lJavaVMAttachArgs);
    if (lResult == JNI_ERR) {
        return;
    }

    // Retrieves NativeActivity.
    jobject lNativeActivity = gApp->activity->clazz;
    jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity);

    // Retrieves Context.INPUT_METHOD_SERVICE.
    jclass ClassContext = lJNIEnv->FindClass("android/content/Context");
    jfieldID FieldINPUT_METHOD_SERVICE =
        lJNIEnv->GetStaticFieldID(ClassContext,
            "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
    jobject INPUT_METHOD_SERVICE =
        lJNIEnv->GetStaticObjectField(ClassContext,
            FieldINPUT_METHOD_SERVICE);
    //jniCheck(INPUT_METHOD_SERVICE);

    // Runs getSystemService(Context.INPUT_METHOD_SERVICE).
    jclass ClassInputMethodManager = lJNIEnv->FindClass(
        "android/view/inputmethod/InputMethodManager");
    jmethodID MethodGetSystemService = lJNIEnv->GetMethodID(
        ClassNativeActivity, "getSystemService",
        "(Ljava/lang/String;)Ljava/lang/Object;");
    jobject lInputMethodManager = lJNIEnv->CallObjectMethod(
        lNativeActivity, MethodGetSystemService,
        INPUT_METHOD_SERVICE);

    // Runs getWindow().getDecorView().
    jmethodID MethodGetWindow = lJNIEnv->GetMethodID(
        ClassNativeActivity, "getWindow",
        "()Landroid/view/Window;");
    jobject lWindow = lJNIEnv->CallObjectMethod(lNativeActivity,
        MethodGetWindow);
    jclass ClassWindow = lJNIEnv->FindClass(
        "android/view/Window");
    jmethodID MethodGetDecorView = lJNIEnv->GetMethodID(
        ClassWindow, "getDecorView", "()Landroid/view/View;");
    jobject lDecorView = lJNIEnv->CallObjectMethod(lWindow,
        MethodGetDecorView);

    if (pShow) {
        // Runs lInputMethodManager.showSoftInput(...).
        jmethodID MethodShowSoftInput = lJNIEnv->GetMethodID(
            ClassInputMethodManager, "showSoftInput",
            "(Landroid/view/View;I)Z");
        jboolean lResult = lJNIEnv->CallBooleanMethod(
            lInputMethodManager, MethodShowSoftInput,
            lDecorView, lFlags);
    } else {
        // Runs lWindow.getViewToken()
        jclass ClassView = lJNIEnv->FindClass(
            "android/view/View");
        jmethodID MethodGetWindowToken = lJNIEnv->GetMethodID(
            ClassView, "getWindowToken", "()Landroid/os/IBinder;");
        jobject lBinder = lJNIEnv->CallObjectMethod(lDecorView,
            MethodGetWindowToken);

        // lInputMethodManager.hideSoftInput(...).
        jmethodID MethodHideSoftInput = lJNIEnv->GetMethodID(
            ClassInputMethodManager, "hideSoftInputFromWindow",
            "(Landroid/os/IBinder;I)Z");
        jboolean lRes = lJNIEnv->CallBooleanMethod(
            lInputMethodManager, MethodHideSoftInput,
            lBinder, lFlags);
    }

    // Finished with the JVM.
    lJavaVM->DetachCurrentThread();
}
Esempio n. 26
0
 ~JniThreadBinding() {
     if (status == JNI_EDETACHED) { jvm->DetachCurrentThread(); }
 }
Esempio n. 27
0
static void* msandroid_write_cb(msandroid_sound_write_data* d) {
    jbyteArray 		write_buff;
    jmethodID 		write_id=0;
    jmethodID play_id=0;
    int min_size=-1;
    int count;
    int max_size=sndwrite_flush_threshold*(float)d->rate*(float)d->nchannels*2.0;
    int check_point_size=3*(float)d->rate*(float)d->nchannels*2.0; /*3 seconds*/
    int nwrites=0;

    set_high_prio();
    int buff_size = d->write_chunk_size;
    //JNIEnv *jni_env = ms_get_jni_env();

    JNIEnv *jni_env = NULL;
    JavaVM *jvm = ms_get_jvm();
    if (jvm->AttachCurrentThread(&jni_env, NULL)!=0) {
        ms_fatal("AttachCurrentThread() failed !");
        goto end;
    }
    // int write  (byte[] audioData, int offsetInBytes, int sizeInBytes)
    write_id = jni_env->GetMethodID(d->audio_track_class,"write", "([BII)I");
    if(write_id==0) {
        ms_error("cannot find AudioTrack.write() method");
        goto end;
    }
    play_id = jni_env->GetMethodID(d->audio_track_class,"play", "()V");
    if(play_id==0) {
        ms_error("cannot find AudioTrack.play() method");
        goto end;
    }
    write_buff = jni_env->NewByteArray(buff_size);
    uint8_t tmpBuff[buff_size];

    //start playing
    jni_env->CallVoidMethod(d->audio_track,play_id);

    ms_mutex_lock(&d->mutex);
    ms_bufferizer_flush(d->bufferizer);
    ms_mutex_unlock(&d->mutex);

    while(d->started) {
        int bufferizer_size;

        ms_mutex_lock(&d->mutex);
        min_size=-1;
        count=0;
        while((bufferizer_size = ms_bufferizer_get_avail(d->bufferizer)) >= d->write_chunk_size) {
            if (min_size==-1) min_size=bufferizer_size;
            else if (bufferizer_size<min_size) min_size=bufferizer_size;

            ms_bufferizer_read(d->bufferizer, tmpBuff, d->write_chunk_size);
            ms_mutex_unlock(&d->mutex);
            jni_env->SetByteArrayRegion(write_buff,0,d->write_chunk_size,(jbyte*)tmpBuff);
            int result = jni_env->CallIntMethod(d->audio_track,write_id,write_buff,0,d->write_chunk_size);
            d->writtenBytes+=result;
            if (result <= 0) {
                ms_error("write operation has failed [%i]",result);
            }
            nwrites++;
            ms_mutex_lock(&d->mutex);
            count+=d->write_chunk_size;
            if (count>check_point_size) {
                if (min_size > max_size) {
                    ms_warning("we are late, flushing %i bytes",min_size);
                    ms_bufferizer_skip_bytes(d->bufferizer,min_size);
                }
                count=0;
            }
        }
        if (d->started) {
            d->sleeping=true;
            ms_cond_wait(&d->cond,&d->mutex);
            d->sleeping=false;
        }
        ms_mutex_unlock(&d->mutex);
    }


    goto end;
end: {
        jvm->DetachCurrentThread();
        ms_thread_exit(NULL);
        return NULL;
    }
}
Esempio n. 28
0
int WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates* states)
{
    // Prepare the Java virtual machine
    jint lResult;
    jint lFlags = 0;

    JavaVM* lJavaVM = states->activity->vm;
    JNIEnv* lJNIEnv = states->activity->env;

    JavaVMAttachArgs lJavaVMAttachArgs;
    lJavaVMAttachArgs.version = JNI_VERSION_1_6;
    lJavaVMAttachArgs.name = "NativeThread";
    lJavaVMAttachArgs.group = NULL;

    lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs);

    if (lResult == JNI_ERR) {
        err() << "Failed to initialize JNI, couldn't get the Unicode value" << std::endl;
        return 0;
    }

    // Retrieve everything we need to create this MotionEvent in Java
    jlong downTime = AMotionEvent_getDownTime(_event);
    jlong eventTime = AMotionEvent_getEventTime(_event);
    jint action = AMotionEvent_getAction(_event);
    jfloat x = AMotionEvent_getX(_event, 0);
    jfloat y = AMotionEvent_getY(_event, 0);
    jfloat pressure = AMotionEvent_getPressure(_event, 0);
    jfloat size = AMotionEvent_getSize(_event, 0);
    jint metaState = AMotionEvent_getMetaState(_event);
    jfloat xPrecision = AMotionEvent_getXPrecision(_event);
    jfloat yPrecision = AMotionEvent_getYPrecision(_event);
    jint deviceId = AInputEvent_getDeviceId(_event);
    jint edgeFlags = AMotionEvent_getEdgeFlags(_event);

    // Create the MotionEvent object in Java trough its static constructor obtain()
    jclass ClassMotionEvent = lJNIEnv->FindClass("android/view/MotionEvent");
    jmethodID StaticMethodObtain = lJNIEnv->GetStaticMethodID(ClassMotionEvent, "obtain", "(JJIFFFFIFFII)Landroid/view/MotionEvent;");
    jobject ObjectMotionEvent = lJNIEnv->CallStaticObjectMethod(ClassMotionEvent, StaticMethodObtain, downTime, eventTime, action, x, y, pressure, size, metaState, xPrecision, yPrecision, deviceId, edgeFlags);

    // Call its getAxisValue() method to get the delta value of our wheel move event
    jmethodID MethodGetAxisValue = lJNIEnv->GetMethodID(ClassMotionEvent, "getAxisValue", "(I)F");
    jfloat delta = lJNIEnv->CallFloatMethod(ObjectMotionEvent, MethodGetAxisValue, 0x00000001);

    lJNIEnv->DeleteLocalRef(ClassMotionEvent);
    lJNIEnv->DeleteLocalRef(ObjectMotionEvent);

    // Create and send our mouse wheel event
    Event event;
    event.type = Event::MouseWheelMoved;
    event.mouseWheel.delta = static_cast<double>(delta);
    event.mouseWheel.x = AMotionEvent_getX(_event, 0);
    event.mouseWheel.y = AMotionEvent_getY(_event, 0);

    forwardEvent(event);

    // Detach this thread from the JVM
    lJavaVM->DetachCurrentThread();

    return 1;
}
Esempio n. 29
0
static void sound_read_setup(MSFilter *f) {
    ms_debug("andsnd_read_preprocess");
    msandroid_sound_read_data *d=(msandroid_sound_read_data*)f->data;
    jmethodID constructor_id=0;
    jmethodID min_buff_size_id;
    //jmethodID set_notification_period;
    int rc;

    //JNIEnv *jni_env = ms_get_jni_env();
    JNIEnv *jni_env = NULL;
    JavaVM *jvm = ms_get_jvm();
    if (jvm->AttachCurrentThread(&jni_env, NULL)!=0) {
        ms_fatal("AttachCurrentThread() failed !");
        return;
    }

    d->audio_record_class = (jclass)jni_env->NewGlobalRef(jni_env->FindClass("android/media/AudioRecord"));
    if (d->audio_record_class == 0) {
        ms_error("cannot find android/media/AudioRecord");
        jvm->DetachCurrentThread();
        return;
    }

    constructor_id = jni_env->GetMethodID(d->audio_record_class,"<init>", "(IIIII)V");
    if (constructor_id == 0) {
        ms_error("cannot find AudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)");
        jvm->DetachCurrentThread();
        return;
    }
    min_buff_size_id = jni_env->GetStaticMethodID(d->audio_record_class,"getMinBufferSize", "(III)I");
    if (min_buff_size_id == 0) {
        ms_error("cannot find AudioRecord.getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)");
        jvm->DetachCurrentThread();
        return;
    }
    d->buff_size = jni_env->CallStaticIntMethod(d->audio_record_class,min_buff_size_id,d->rate,2/*CHANNEL_CONFIGURATION_MONO*/,2/*  ENCODING_PCM_16BIT */);
    d->read_chunk_size = d->buff_size/4;
    d->buff_size*=2;/*double the size for configuring the recorder: this does not affect latency but prevents "AudioRecordThread: buffer overflow"*/

    if (d->buff_size > 0) {
        ms_message("Configuring recorder with [%i] bits  rate [%i] nchanels [%i] buff size [%i], chunk size [%i]"
                   ,d->bits
                   ,d->rate
                   ,d->nchannels
                   ,d->buff_size
                   ,d->read_chunk_size);
    } else {
        ms_message("Cannot configure recorder with [%i] bits  rate [%i] nchanels [%i] buff size [%i] chunk size [%i]"
                   ,d->bits
                   ,d->rate
                   ,d->nchannels
                   ,d->buff_size
                   ,d->read_chunk_size);
        return;
    }

    d->read_buff = jni_env->NewByteArray(d->buff_size);
    d->read_buff = (jbyteArray)jni_env->NewGlobalRef(d->read_buff);
    if (d->read_buff == 0) {
        ms_error("cannot instanciate read buff");
        jvm->DetachCurrentThread();
        return;
    }

    d->audio_record =  jni_env->NewObject(d->audio_record_class
                                          ,constructor_id
                                          ,sdk_version<11?1/*MIC*/:7/*VOICE_COMMUNICATION*/
                                          ,d->rate
                                          ,2/*CHANNEL_CONFIGURATION_MONO*/
                                          ,2/*  ENCODING_PCM_16BIT */
                                          ,d->buff_size);


    d->audio_record = jni_env->NewGlobalRef(d->audio_record);
    if (d->audio_record == 0) {
        ms_error("cannot instantiate AudioRecord");
        jvm->DetachCurrentThread();
        return;
    }
    d->min_avail=-1;
    d->read_samples=0;
    d->ticker_synchronizer = ms_ticker_synchronizer_new();
    d->outgran_ms=20;
    d->start_time=-1;
    d->framesize=(d->outgran_ms*d->rate)/1000;
    d->started=true;
    // start reader thread
    rc = ms_thread_create(&d->thread_id, 0, (void*(*)(void*))msandroid_read_cb, d);
    if (rc) {
        ms_error("cannot create read thread return code  is [%i]", rc);
        d->started=false;
    }
    jvm->DetachCurrentThread();
}
Esempio n. 30
0
bool startJVM(TCHAR* basedir, TCHAR* appFolder, TCHAR* jar, int argCount, LPTSTR *szArgList) {
    TCHAR jvmPath[LAUNCHER_MAXPATH+1] = {0};
    JavaVMInitArgs jvmArgs;
    JavaVMOption options[MAX_OPTIONS];
    JVM_CREATE createProc;
    JNIEnv* env;
    JavaVM* jvm = NULL;
    char jarASCII[LAUNCHER_MAXPATH] = {0};
    char classpath[LAUNCHER_MAXPATH*2] = {0};
    char mainclassASCII[LAUNCHER_MAXPATH] = {0},
        appClasspath[LAUNCHER_MAXPATH] = {0};
    size_t outlen = 0;
    jclass cls;
    jmethodID mid;
    TCHAR argname[MAX_OPTION_NAME + 1] = {0};
    TCHAR argvalue[LAUNCHER_MAXPATH] = {0},
    mainclass[LAUNCHER_MAXPATH] = {0};
    CHAR  argvalueASCII[LAUNCHER_MAXPATH] = {0};
    HMODULE msvcrtdll;
    bool runtimeBundled;
    TCHAR tmpPath[LAUNCHER_MAXPATH] = {0};
    TCHAR appid[LAUNCHER_MAXPATH] = {0};

    memset(&options, 0, sizeof(JavaVMOption)*MAX_OPTIONS);
    memset(&jvmArgs, 0, sizeof(JavaVMInitArgs));

    makeFullFileName(basedir, _T("\\runtime"), tmpPath, sizeof(tmpPath)/sizeof(TCHAR));
    runtimeBundled = fileExists(tmpPath);
    if (runtimeBundled) {
       if (!getJvmPath(basedir, jvmPath, LAUNCHER_MAXPATH)) {
            showError(_T("jvm.dll is not found in bundled runtime."), jvmPath);
            return false;
       }
       //make sure msvcr100 is loaded (or we may fail if copy of it is not installed into system)
       makeFullFileName(basedir, _T("runtime\\jre\\bin\\msvcr100.dll"), tmpPath, sizeof(tmpPath)/sizeof(TCHAR));
       msvcrtdll = ::LoadLibrary(tmpPath);
    } else {
        if (!getSystemJvmPath(jvmPath, LAUNCHER_MAXPATH)) {
            showError(_T("No bundled runtime and can not find system JRE."), jvmPath);
            return false;
        }
       //make sure msvcr100 is loaded (or we may fail if copy of it is not installed into system)
       makeFullFileName(basedir, _T("\\bin\\msvcr100.dll"), tmpPath, sizeof(tmpPath)/sizeof(TCHAR));
       msvcrtdll = ::LoadLibrary(tmpPath);
    }

    // Dynamically load the JVM
    HMODULE jvmLibHandle = LoadLibrary(jvmPath);
    if (jvmLibHandle == NULL) {
        DWORD dwErr = GetLastError();
        showError(_T("Error loading jvm.dll"), jvmPath);
        return false;
    }

    //convert argument to ASCII string as this is what CreateJVM needs
    wcstombs_s(&outlen, jarASCII, LAUNCHER_MAXPATH, jar, (size_t) wcslen(jar) + 1);
    strcpy_s(classpath, LAUNCHER_MAXPATH*2, "-Djava.class.path=");
    strcat_s(classpath, LAUNCHER_MAXPATH, jarASCII);

    if (getConfigValue(basedir, CONFIG_CLASSPATH_KEY, argvalue, LAUNCHER_MAXPATH)) {
           size_t inLen = (size_t) wcslen(argvalue);
           //convert argument to ASCII string as this is what CreateJVM needs
           wcstombs_s(&outlen, argvalueASCII, sizeof(argvalueASCII), argvalue, inLen + 1);
           //compress spaces and replaces them with ;
           {
               char *in = argvalueASCII;
               char *out = argvalueASCII;
               bool needSemicolon = false;

               while (*in != 0) {
                   if (*in == ' ') {
                       if (needSemicolon) {
                          *out = ';';
                          out++;
                          needSemicolon = false;
                       }
                   } else {
                       needSemicolon = true;
                       *out = *in;
                       out++;
                   }
                   in++;
               }
               *out = 0;
           }
           if (strlen(argvalueASCII) > 0) {
               strcat_s(classpath, LAUNCHER_MAXPATH, ";");
               strcat_s(classpath, LAUNCHER_MAXPATH, argvalueASCII);
           }
    }

    // Set up the VM init args
    jvmArgs.version = JNI_VERSION_1_2;

    options[0].optionString = _strdup(classpath);

    int cnt = 1;
    if (isDebug) {
       options[cnt].optionString = _strdup("vfprintf");
       options[cnt].extraInfo    = vfprintfHook;
       cnt++;
    }

    //Note: should not try to quote the path. Spaces are fine here
    _stprintf_s(argvalue, _T("-Djava.library.path=%s"), appFolder);
    wcstombs_s(&outlen, argvalueASCII, sizeof(argvalueASCII),
               argvalue, wcslen(argvalue) + 1);
    options[cnt].optionString = _strdup(argvalueASCII);
    cnt++;

    //add app specific JVM parameters
    int idx = 1;
    int found = 0;
    do {
       _stprintf_s(argname, MAX_OPTION_NAME, _T("jvmarg.%d"), idx);
       found = getConfigValue(basedir, argname, argvalue, LAUNCHER_MAXPATH);
       if (found) {
            TCHAR* option = replaceStr(argvalue, _T("$APPDIR"), basedir);
            char* jvmOption = convertToDupedChar(option);
            if (jvmOption != NULL) {
                options[cnt].optionString = jvmOption;
                cnt++;
            }
            idx++;
        }
    } while (found && idx < MAX_OPTIONS);

    cnt = addUserOptions(basedir, options, cnt);

    jvmArgs.version = 0x00010002;
    jvmArgs.options = options;
    jvmArgs.nOptions = cnt;
    jvmArgs.ignoreUnrecognized = JNI_TRUE;

    // Create the JVM
    // NB: need to use ASCII string as UNICODE is not supported
    createProc = (JVM_CREATE) GetProcAddress(jvmLibHandle, "JNI_CreateJavaVM");
    if (createProc == NULL) {
        showError(_T("Failed to locate JNI_CreateJavaVM"), jvmPath);
        return false;
    }

    if ((*createProc)(&jvm, &env, &jvmArgs) < 0) {
        showError(_T("Failed to create JVM"), jvmPath);
        return false;
    }

    if (!getConfigValue(basedir, CONFIG_MAINCLASS_KEY, mainclass, LAUNCHER_MAXPATH)) {
        showError(_T("Package error"), _T("No main class specified. Nothing to launch"));
        return false;
    } else {
           size_t inLen = (size_t) wcslen(mainclass);
           //convert argument to ASCII string as this is what CreateJVM needs
           wcstombs_s(&outlen, mainclassASCII, sizeof(mainclassASCII), mainclass, inLen + 1);
    }

    cls = env->FindClass(mainclassASCII);
    if (cls != NULL) {
        mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V");
         if (mid != NULL) {
            jclass stringClass = env->FindClass("java/lang/String");
            //prepare app arguments if any. Skip value at index 0 - this is path to executable ...
            //NOTE:
            //  - what if user run in non-English/UTF-8 locale? do we need to convert args?
            //  - extend to pass jvm args and debug args (allow them in front, use marker option to separate them?)
            int startArgIndex = countNumberOfSystemArguments(argCount, szArgList);
            jobjectArray args = env->NewObjectArray(argCount - startArgIndex, stringClass, NULL);
            for(int i=startArgIndex; i<argCount; i++) {
                size_t inLen = (size_t) wcslen(szArgList[i]);
                env->SetObjectArrayElement(args, i-startArgIndex, env->NewString((jchar*)szArgList[i], inLen));
            }
            env->CallStaticVoidMethod(cls, mid, args);
        } else {
            showError(_T("no main method in the main class!"), mainclass);
            return false;
        }
    } else {
        showError(_T("no main class."), mainclass);
        return false;
    }

    if (env->ExceptionOccurred()) {
        showError(_T("Failed due to exception from main class."), mainclass);
        env->ExceptionDescribe();
    }

    // If application main() exits quickly but application is run on some other thread
    //  (e.g. Swing app performs invokeLater() in main and exits)
    // then if we return execution to tWinMain it will exit.
    // This will cause process to exit and application will not actually run.
    //
    // To avoid this we are trying to detach jvm from current thread (java.exe does the same)
    // Because we are doing this on the main JVM thread (i.e. one that was used to create JVM)
    // this call will spawn "Destroy Java VM" java thread that will shut JVM once there are
    // no non-daemon threads running, and then return control here.
    // I.e. this will happen when EDT and other app thread will exit.
    if (jvm->DetachCurrentThread() != 0) {
        showError(_T("Detach failed."), NULL);
    }
    jvm->DestroyJavaVM();

    return true;
}