|
81 | 81 | #include <android/log.h>
|
82 | 82 | #include <jni.h>
|
83 | 83 |
|
| 84 | +typedef struct |
| 85 | +{ |
| 86 | + const char *java_type_name; |
| 87 | + jobject class_loader; |
| 88 | +} RegisterFromThreadContext; |
| 89 | + |
84 | 90 | typedef void (*CB)(JNIEnv *env, jobject self);
|
85 | 91 |
|
86 | 92 | static JavaVM *gvm;
|
@@ -113,9 +119,9 @@ _get_env (const char *where)
|
113 | 119 | }
|
114 | 120 |
|
115 | 121 | static jobject
|
116 |
| -_create_java_instance (JNIEnv *env) |
| 122 | +_create_java_instance (JNIEnv *env, const char *class_name) |
117 | 123 | {
|
118 |
| - jclass Object_class = (*env)->FindClass (env, "java/lang/Object"); |
| 124 | + jclass Object_class = (*env)->FindClass (env, class_name); |
119 | 125 | jmethodID Object_ctor = (*env)->GetMethodID (env, Object_class, "<init>", "()V");
|
120 | 126 |
|
121 | 127 | jobject instance = (*env)->NewObject (env, Object_class, Object_ctor);
|
@@ -154,7 +160,7 @@ _call_cb_from_new_thread (void *cb)
|
154 | 160 | }
|
155 | 161 |
|
156 | 162 | /* 5: Execution of T enters managed code... */
|
157 |
| - jobject instance = _create_java_instance (env); |
| 163 | + jobject instance = _create_java_instance (env, "java/lang/Object"); |
158 | 164 | _cb (env, instance);
|
159 | 165 |
|
160 | 166 | return NULL;
|
@@ -200,3 +206,116 @@ rt_invoke_callback_on_new_thread (CB cb)
|
200 | 206 | return 0;
|
201 | 207 | }
|
202 | 208 |
|
| 209 | +/* We return -2 for errors, because -1 is reserved for the pthreads PTHREAD_CANCELED special value, indicating that the |
| 210 | + * thread was canceled. */ |
| 211 | +static int |
| 212 | +_register_type_from_new_thread (void *data) |
| 213 | +{ |
| 214 | + RegisterFromThreadContext *context = (RegisterFromThreadContext*)data; |
| 215 | + |
| 216 | + if (context == NULL) { |
| 217 | + return -100; |
| 218 | + } |
| 219 | + |
| 220 | + JNIEnv *env = _get_env ("_register_type_from_new_thread"); |
| 221 | + |
| 222 | + if ((*env)->PushLocalFrame (env, 4) < 0) { |
| 223 | + __android_log_print (ANDROID_LOG_INFO, "XA/RuntimeTest", "FAILURE: unable to create a local reference frame!"); |
| 224 | + |
| 225 | + if ((*env)->ExceptionOccurred (env)) { |
| 226 | + (*env)->ExceptionDescribe (env); |
| 227 | + (*env)->ExceptionClear (env); |
| 228 | + } |
| 229 | + |
| 230 | + return -101; |
| 231 | + } |
| 232 | + |
| 233 | + int ret = 0; |
| 234 | + jclass ClassLoader_class = (*env)->FindClass (env, "java/lang/ClassLoader"); |
| 235 | + if (ClassLoader_class == NULL) { |
| 236 | + ret = -102; |
| 237 | + __android_log_print (ANDROID_LOG_INFO, "XA/RuntimeTest", "FAILURE: unable to find the 'java/lang/ClassLoader' class!"); |
| 238 | + goto cleanup; |
| 239 | + } |
| 240 | + |
| 241 | + jmethodID loadClass = (*env)->GetMethodID (env, ClassLoader_class, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); |
| 242 | + if (loadClass == NULL) { |
| 243 | + ret = -103; |
| 244 | + __android_log_print (ANDROID_LOG_INFO, "XA/RuntimeTest", "FAILURE: unable to get id of method 'loadClass' in the 'java/lang/ClassLoader' class!"); |
| 245 | + goto cleanup; |
| 246 | + } |
| 247 | + |
| 248 | + jstring klass_name = (*env)->NewStringUTF (env, context->java_type_name); |
| 249 | + jobject loaded_class = (*env)->CallObjectMethod (env, context->class_loader, loadClass, klass_name); |
| 250 | + |
| 251 | + if ((*env)->ExceptionOccurred (env) != NULL) { |
| 252 | + __android_log_print (ANDROID_LOG_INFO, "XA/RuntimeTest", "FAILURE: class '%s' cannot be loaded, Java exception thrown!", context->java_type_name); |
| 253 | + (*env)->ExceptionDescribe (env); |
| 254 | + (*env)->ExceptionClear (env); |
| 255 | + ret = -104; |
| 256 | + goto cleanup; |
| 257 | + } |
| 258 | + |
| 259 | + if (loaded_class == NULL) { |
| 260 | + ret = -105; |
| 261 | + __android_log_print (ANDROID_LOG_INFO, "XA/RuntimeTest", "FAILURE: 'java/lang/ClassLoader' wasn't able to load the '%s' class!", context->java_type_name); |
| 262 | + goto cleanup; |
| 263 | + } |
| 264 | + |
| 265 | + jmethodID Object_ctor = (*env)->GetMethodID (env, loaded_class, "<init>", "()V"); |
| 266 | + if (Object_ctor == NULL) { |
| 267 | + ret = -106; |
| 268 | + __android_log_print (ANDROID_LOG_INFO, "XA/RuntimeTest", "FAILURE: unable to find the '%s' class constructor!", context->java_type_name); |
| 269 | + goto cleanup; |
| 270 | + } |
| 271 | + |
| 272 | + jobject instance = (*env)->NewObject (env, loaded_class, Object_ctor); |
| 273 | + |
| 274 | + if ((*env)->ExceptionOccurred (env) != NULL || instance == NULL) { |
| 275 | + __android_log_print (ANDROID_LOG_INFO, "XA/RuntimeTest", "FAILURE: instance of class '%s' wasn't created!", context->java_type_name); |
| 276 | + (*env)->ExceptionDescribe (env); |
| 277 | + (*env)->ExceptionClear (env); |
| 278 | + ret = -107; |
| 279 | + } |
| 280 | + |
| 281 | + if (instance == NULL) { |
| 282 | + ret = -108; |
| 283 | + __android_log_print (ANDROID_LOG_INFO, "XA/RuntimeTest", "FAILURE: unable to create instance of the '%s' class!", context->java_type_name); |
| 284 | + } |
| 285 | + |
| 286 | + cleanup: |
| 287 | + (*env)->PopLocalFrame (env, NULL); |
| 288 | + |
| 289 | + return ret; |
| 290 | +} |
| 291 | + |
| 292 | +JNIEXPORT int JNICALL |
| 293 | +rt_register_type_on_new_thread (const char *java_type_name, jobject class_loader) |
| 294 | +{ |
| 295 | + JNIEnv *env = _get_env ("rt_register_type_on_new_thread"); |
| 296 | + pthread_t t; |
| 297 | + RegisterFromThreadContext context = { |
| 298 | + java_type_name, |
| 299 | + class_loader, |
| 300 | + }; |
| 301 | + |
| 302 | + int r = pthread_create (&t, NULL, _register_type_from_new_thread, &context); |
| 303 | + |
| 304 | + if (r) { |
| 305 | + __android_log_print (ANDROID_LOG_INFO, "XA/RuntimeTest", "RegisterOnNewThread: pthread_create() failed! %i: %s", r, strerror (r)); |
| 306 | + return -200; |
| 307 | + } |
| 308 | + |
| 309 | + void *tr; |
| 310 | + if (pthread_join (t, &tr) != 0) { |
| 311 | + __android_log_print (ANDROID_LOG_INFO, "XA/RuntimeTest", "RegisterOnNewThread: pthread_join() failed! %i: %s", r, strerror (r)); |
| 312 | + return -201; |
| 313 | + } |
| 314 | + |
| 315 | + if ((int)tr == -1 /* PTHREAD_CANCELED - not defined in bionic */) { |
| 316 | + __android_log_print (ANDROID_LOG_INFO, "XA/RuntimeTest", "RegisterOnNewThread: worker thread was canceled"); |
| 317 | + return -202; |
| 318 | + } |
| 319 | + |
| 320 | + return (int)tr; |
| 321 | +} |
0 commit comments