Note that there are some explanatory texts on larger screens.

plurals
  1. POcallback from pthread through JNI failing
    text
    copied!<p>I'm trying to call back through JNI from a <code>pthread</code> created in a C++ class. With the following code. I can trigger a button press from my Android app and my <code>callbackStringJNI()</code> works fine. The creation of the <code>pthread</code> is triggered by a button press passed down through JNI. If the function/thread created by <code>pthread</code> attempts a asynchronous call of <code>callbackStringJNI()</code>, I do get the passed string in the Android app <code>messageMe()</code>(viewed only when breaking in debugger), but if I try to use the string(IE, display something on the UI), the application breaks on Android source 'Handler.class' function <code>joinThreadPool</code> and then if I resume again I hit the 'exception' in the Android code below:</p> <p>Android API Error Code:</p> <pre><code>public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class&lt;? extends Handler&gt; klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &amp;&amp; (klass.getModifiers() &amp; Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException(//////////Hits here - this message is never actually displayed though. "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; } </code></pre> <p>I can copy the string to another variable as seen in the <code>messageMe()</code>, but I still can't use the string in a <code>Toast</code> or even a <code>TextView</code>. I am quite stumped at this time as to why I can not callback from a <code>pthread</code>, any suggestions are welcome.</p> <p>Android Java:</p> <pre><code> package com.example.somecontrol1; public class MainActivity extends Activity { // load the library - name matches jni/Android.mk static { System.loadLibrary("ndkfoo"); } private native String inintNativeClass(); private native String SetUpSocketNC(); private native void initJNICallback(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initJNICallback(); inintNativeClass(); public void messageMe(String text) { String teststr = text; Toast.makeText(getApplicationContext(), teststr, Toast.LENGTH_LONG).show(); //appendTextAndScroll(text, gtv); } } </code></pre> <p>In the below code, when <code>getJNIEnv()</code> is called and the execution came from a button press, <code>JNI_OK</code> is the result. When the call comes from the callback in pthread, <code>JNI_EDETACHED</code> is the result and <code>AttachCurrentThread()</code> succeeds.</p> <p>JNI C ndkfoo.c</p> <pre><code>#include &lt;jni.h&gt; #include "testSocketClassWrapper.hpp" static JavaVM* cachedJVM; static jobject g_javaObj; static jclass cachedclassID; void *m_GBLpmyCSocket = NULL; jint JNI_OnLoad(JavaVM *jvm, void *reserved) { cachedJVM = jvm; JNIEnv* env; if ((*jvm)-&gt;GetEnv(jvm, (void **)&amp;env, JNI_VERSION_1_4) != JNI_OK) { LOGD("GETENVFAILEDONLOAD"); return -1; } return JNI_VERSION_1_4; } void Java_com_example_somecontrol1_MainActivity_initJNICallback(JNIEnv* env, jobject jobj) { //LOGD("Java_org_test_games_Wrapper_initJNIBridge()"); g_javaObj = (*env)-&gt;NewGlobalRef(env, jobj); jclass storeclassID = (*env)-&gt;FindClass(env, "com/example/somecontrol1/MainActivity"); if ( (*env)-&gt;ExceptionCheck(env) == JNI_TRUE ){ (*env)-&gt;ExceptionDescribe(env); LOGD("got into exception describe"); } cachedclassID = (jclass)(*env)-&gt;NewGlobalRef(env, storeclassID); if ( (*env)-&gt;ExceptionCheck(env) == JNI_TRUE ){ (*env)-&gt;ExceptionDescribe(env); LOGD("got into exception describe"); } } jstring Java_com_example_somecontrol1_MainActivity_inintNativeClass(JNIEnv * env, jobject object){ m_GBLpmyCSocket = (void *)MyClass_create(); return (*env)-&gt;NewStringUTF(env, "launched class"); } typedef struct JniMethodInfo_ { JNIEnv* env; jclass classID; jmethodID methodID; } JniMethodInfo; static JNIEnv* getJNIEnv()//was JNIEnv { //JavaVM* jvm = cocos2d::JniHelper::getJavaVM(); if (NULL == cachedJVM) { LOGD("Failed to get JNIEnv. JniHelper::getJavaVM() is NULL"); return NULL; } JNIEnv *env = NULL; // get jni environment jint ret = (*cachedJVM)-&gt;GetEnv(cachedJVM, (void**)&amp;env, JNI_VERSION_1_4); switch (ret) { case JNI_OK : // Success! LOGD("getenv successA"); return env; case JNI_EDETACHED : // Thread not attached LOGD("thread not attached"); // TODO : If calling AttachCurrentThread() on a native thread // must call DetachCurrentThread() in future. // see: http://developer.android.com/guide/practices/design/jni.html if ((*cachedJVM)-&gt;AttachCurrentThread(cachedJVM, &amp;env, NULL) &lt; 0) { LOGD("Failed to get the environment using AttachCurrentThread()"); return NULL; } else { // Success : Attached and obtained JNIEnv! LOGD("getenv successB"); return env; } case JNI_EVERSION : // Cannot recover from this error LOGD("JNI interface version 1.4 not supported"); default : LOGD("Failed to get the environment using GetEnv()"); return NULL; } } static bool getMethodInfo(JniMethodInfo *methodinfo, const char *methodName, const char *paramCode) { jmethodID methodID = 0; JNIEnv *pEnv = 0; bool bRet = false; do { pEnv = getJNIEnv(); if (! pEnv) { LOGD("getJNIEnv Break Called"); break; } //jclass classID = getClassID(pEnv); //jclass classID = cachedclassID; //methodID = (*pEnv)-&gt;GetMethodID(pEnv, classID, methodName, paramCode); methodID = (*pEnv)-&gt;GetMethodID(pEnv, cachedclassID, methodName, paramCode); if (! methodID) { LOGD("Failed to find method id of %s", methodName); break; } //methodinfo-&gt;classID = classID; methodinfo-&gt;env = pEnv; methodinfo-&gt;methodID = methodID; bRet = true; } while (0); return bRet; } void callbackStringJNI(const char *newstr) { LOGD("callbackStringJNI"); JniMethodInfo methodInfo; if (! getMethodInfo(&amp;methodInfo, "messageMe", "(Ljava/lang/String;)V")) { LOGD("Cannot find method!"); return; } jstring jstr = (*methodInfo.env)-&gt;NewStringUTF(methodInfo.env, newstr); (*methodInfo.env)-&gt;CallVoidMethod(methodInfo.env, g_javaObj, methodInfo.methodID, jstr); } </code></pre> <p>Class wrapper</p> <pre><code>//file testSocketClassWrapper.cpp #include "testSocketClassWrapper.hpp" #include "testSocketClass.hpp" extern "C" void* MyClass_create() { return new mYNewClass; } extern "C" void MyClass_release(void* myclass) { delete static_cast&lt;mYNewClass*&gt;(myclass); } extern "C" void MyClass_sendCommandToSerialDevice(void* myclass, int cmd, int params, int id) { static_cast&lt;mYNewClass*&gt;(myclass)-&gt;sendCommandToSerialDevice(cmd,params,id); } extern "C" void SetUpSocket(void* myclass, int cmd, int params, int id) { static_cast&lt;mYNewClass*&gt;(myclass)-&gt;SetUpSocket(cmd,params,id); } extern "C" void Startcntl(void* myclass, int cmd, int params, int id) { static_cast&lt;mYNewClass*&gt;(myclass)-&gt;Startcntl(); } extern "C" void Stopcntl(void* myclass, int cmd, int params, int id) { static_cast&lt;mYNewClass*&gt;(myclass)-&gt;Stopcntl(); } </code></pre> <p>C++ class</p> <pre><code>//file testSocketClass.cpp void mYNewClass::SetUpSocket(int Command, int Parameters, int DeviceID){ thread1 = 0; iret1 = 0; iret1 = pthread_create( &amp;thread1, NULL, &amp;mYNewClass::thread_helper, this); } void mYNewClass::Startcntl(){ callbackStringJNI("sent start");//////this works. } </code></pre> <p>C++ header</p> <pre><code>//file testSocketClass.hpp extern "C" { void callbackStringJNI(const char *); } class mYNewClass{ public: void *threadfunc(void) { LOGD("in thread"); while(1){ LOGD("thread looping"); callbackStringJNI("readata start"); LOGD("sleep"); sleep(30); } LOGD("after callbackStringJNI");////this does not work return(0); } static void *thread_helper(void *context) { return ((mYNewClass *)context)-&gt;threadfunc(); } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload