2

I'm trying to call from c>java, to open a URL (i.e. launch web browser). I have the code working in java to launch the url (it is a method of my main activity). It was working when I just did the call on the same thread, however, since I have made the call from another thread, it's broken.

I get the following errors: http://pastie.org/4696174

09-10 15:59:49.405: W/dalvikvm(31430): JNI WARNING: threadid=11 using env from threadid=1
09-10 15:59:49.405: E/dalvikvm(31430): JNI ERROR: env->self != thread-self (0x12988 vs. 0x200fb0); auto-correcting
09-10 15:59:49.405: W/dalvikvm(31430): JNI WARNING: threadid=11 using env from threadid=1
09-10 15:59:49.405: W/dalvikvm(31430): JNI WARNING: 0x41578910 is not a valid JNI reference
09-10 15:59:49.405: W/dalvikvm(31430):              in Lcom/mrqwak/app/AppRenderer;.onDrawFrameN:()V (CallVoidMethodV)
09-10 15:59:49.415: I/dalvikvm(31430): "GLThread 876" prio=5 tid=11 RUNNABLE
09-10 15:59:49.415: I/dalvikvm(31430):   | group="main" sCount=0 dsCount=0 obj=0x4157b270 self=0x200fb0
09-10 15:59:49.415: I/dalvikvm(31430):   | sysTid=31443 nice=0 sched=0/0 cgrp=default handle=1986128
09-10 15:59:49.420: I/dalvikvm(31430):   | schedstat=( 1035202257 457143963 4029 ) utm=80 stm=23 core=0
09-10 15:59:49.420: I/dalvikvm(31430):   at com.mrqwak.app.AppRenderer.onDrawFrameN(Native Method)
09-10 15:59:49.420: I/dalvikvm(31430):   at com.mrqwak.app.AppRenderer.onDrawFrame(AppActivity.java:289)
09-10 15:59:49.425: I/dalvikvm(31430):   at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1462)
09-10 15:59:49.425: I/dalvikvm(31430):   at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1216)
09-10 15:59:49.425: E/dalvikvm(31430): VM aborting
09-10 15:59:49.430: A/libc(31430): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1)

Here is my c code: http://pastie.org/4696207

I call this from c>java, on main UI thread, as main activity is created:

JNIEnv*     g_envApp            =   0;
jobject     g_objApp            =   0;
jclass      g_classApp          =   0;
jmethodID   g_methodOpenURL     =   0;

JNIEXPORT void JNICALL Java_com_mrqwak_app_AppActivity_onCreateN(JNIEnv *env, jobject obj)
{
    g_envApp = env;
    g_objApp = obj;
    g_classApp = env->GetObjectClass(obj);
    if (g_classApp)
    {
        g_methodOpenURL = env->GetMethodID(g_classApp,"openURL","(Ljava/lang/String;)V");
    }
}

I call this later, from c>java, NOT on main UI thead, when user presses a button to open a url:

extern  JNIEnv*     g_envApp;
extern  jobject     g_objApp;
extern  jclass      g_classApp;
extern  jmethodID   g_methodOpenURL;

void cHTTP::OpenURL(const char* psURL)
{
    if (g_methodOpenURL)
    {
        jstring jstr = g_envApp->NewStringUTF(psURL);
        g_envApp->CallVoidMethod(g_objApp,g_methodOpenURL,jstr);
    }
}

Thanks,

cosmic4z
  • 21
  • 1
  • 4
  • On Wikipedea: A JNI interface pointer (JNIEnv*) is passed as an argument for each native function mapped to a Java method, allowing for interaction with the JNI environment within the native method. This JNI interface pointer can be stored, but remains valid only in the current thread. Other threads must first call AttachCurrentThread() to attach themselves to the VM and obtain a JNI interface pointer... So I believe I need to AttachCurrentThread in C? – cosmic4z Sep 10 '12 at 16:58

1 Answers1

2

I believe you need to attach to the UI thread - jobjects aren't share-able across threads - something to this effect:

JNIEnv *env;
jvm->AttachCurrentThread(&env, 0);
jmethodID mid = env->GetMethodID(g_classApp, "openURL", "(Ljava/lang/string)V");
env->CallVoidMethod(g_objApp, mid, url);

And in your first call to JNI, where you set those other variables, add a jvm object:

JavaVM  *jvm;
...
env->GetJavaVM(&jvm);
JRaymond
  • 11,625
  • 5
  • 37
  • 40
  • Thank you JRaymond. Just need to work out how to get a hold of 'jvm'? – cosmic4z Sep 10 '12 at 17:02
  • Just seen: http://stackoverflow.com/questions/7268450/calling-java-class-member-from-native-c-c-code - Do I need to create JNI_OnLoad in c? Is it called automatically? – cosmic4z Sep 10 '12 at 17:04
  • @cosmic4z Added a bit about the JVM – JRaymond Sep 10 '12 at 17:06
  • @cosmic4z I don't, but I'm using c++ and accessing my library with `JNIEXPORT` calls. but at any rate it JNI_Onload gets called automatically when the .so is loaded from Java – JRaymond Sep 10 '12 at 17:08
  • okay, thanks again. I got the JVM okay, from JNI_OnLoad, it now launches and seems to open the correct URL (it's in the address bar in the browser), however, still doesn't load page. Get following error: 09-10 18:22:54.840: W/dalvikvm(3968): JNI WARNING: threadid=11 using env from threadid=1 09-10 18:22:54.840: E/dalvikvm(3968): JNI ERROR: env->self != thread-self (0x12988 vs. 0x200fb0); auto-correcting – cosmic4z Sep 10 '12 at 17:25
  • Hmm, maybe something wrong with my network. I can't seem to access my website (www.mrqwak.com), can get SO and google, so maybe my site is down!? – cosmic4z Sep 10 '12 at 17:27
  • are you trying to use your old env in the new thread? I think that's where your warning is coming from - JNI associates `JNIEnv`s on a per-thread basis. Can't speak as to your network troubles :) – JRaymond Sep 10 '12 at 17:31
  • I'm saving the JavaVM in JNI_OnLoad, and using it here: JNIEnv *env; g_JVM->AttachCurrentThread(&env,0); jmethodID mid = env->GetMethodID(g_classApp, "openURL", "(Ljava/lang/String;)V"); if (mid) { jstring jstr = g_envApp->NewStringUTF(psURL); env->CallVoidMethod(g_objApp, mid, jstr); } – cosmic4z Sep 10 '12 at 17:42