@@ -16,6 +16,8 @@ extern "C" {
16
16
static JavaVM *gJvm = nullptr ;
17
17
static jobject gClassLoader ;
18
18
static jmethodID gFindClassMethod ;
19
+ static JNIEnv *gCurEnv = nullptr ;
20
+ static pthread_key_t detachKey = 0 ;
19
21
20
22
typedef void (*NativeMethodCallback)(
21
23
void *targetPtr,
@@ -46,18 +48,33 @@ JNIEnv *getEnv() {
46
48
return env;
47
49
}
48
50
51
+ void detachThreadDestructor (void * arg) {
52
+ NSLog (" detach from current thread" );
53
+ gJvm ->DetachCurrentThread ();
54
+ detachKey = 0 ;
55
+ }
56
+
57
+ void attachThread () {
58
+ if (detachKey == 0 ) {
59
+ NSLog (" attach to current thread" );
60
+ pthread_key_create (&detachKey, detachThreadDestructor);
61
+ gJvm ->AttachCurrentThread (&gCurEnv , NULL );
62
+ pthread_setspecific (detachKey, nullptr );
63
+ }
64
+ }
65
+
49
66
JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM *pjvm, void *reserved) {
50
67
NSLog (" JNI_OnLoad" );
51
68
gJvm = pjvm; // cache the JavaVM pointer
52
- auto env = getEnv ();
69
+ gCurEnv = getEnv ();
53
70
// replace with one of your classes in the line below
54
- auto randomClass = env ->FindClass (" com/dartnative/dart_native/DartNativePlugin" );
55
- jclass classClass = env ->GetObjectClass (randomClass);
56
- auto classLoaderClass = env ->FindClass (" java/lang/ClassLoader" );
57
- auto getClassLoaderMethod = env ->GetMethodID (classClass, " getClassLoader" ,
71
+ auto randomClass = gCurEnv ->FindClass (" com/dartnative/dart_native/DartNativePlugin" );
72
+ jclass classClass = gCurEnv ->GetObjectClass (randomClass);
73
+ auto classLoaderClass = gCurEnv ->FindClass (" java/lang/ClassLoader" );
74
+ auto getClassLoaderMethod = gCurEnv ->GetMethodID (classClass, " getClassLoader" ,
58
75
" ()Ljava/lang/ClassLoader;" );
59
- gClassLoader = env ->NewGlobalRef (env ->CallObjectMethod (randomClass, getClassLoaderMethod));
60
- gFindClassMethod = env ->GetMethodID (classLoaderClass, " findClass" ,
76
+ gClassLoader = gCurEnv ->NewGlobalRef (gCurEnv ->CallObjectMethod (randomClass, getClassLoaderMethod));
77
+ gFindClassMethod = gCurEnv ->GetMethodID (classLoaderClass, " findClass" ,
61
78
" (Ljava/lang/String;)Ljava/lang/Class;" );
62
79
63
80
NSLog (" JNI_OnLoad finish" );
@@ -77,18 +94,20 @@ char *generateSignature(char **argTypes) {
77
94
if (argTypes != nullptr )
78
95
{
79
96
for (; *argTypes; ++argTypes, ++argCount) {
80
- signature = spliceChar (signature, *argTypes);
97
+ char *templeSignature = spliceChar (signature, *argTypes);
98
+ signature = templeSignature;
99
+ free (templeSignature);
81
100
}
82
101
}
83
102
return spliceChar (signature, const_cast <char *>(" )" ));
84
103
}
85
104
86
- void fillArgs (void **args, char **argTypes, jvalue *argValues, JNIEnv *curEnv ) {
105
+ void fillArgs (void **args, char **argTypes, jvalue *argValues) {
87
106
for (jsize index (0 ); *argTypes ; ++args, ++index, ++argTypes) {
88
107
char *argType = *argTypes;
89
108
if (strlen (argType) > 1 ) {
90
109
if (strcmp (argType, " Ljava/lang/String;" ) == 0 ) {
91
- argValues[index].l = curEnv ->NewStringUTF ((char *)*args);
110
+ argValues[index].l = gCurEnv ->NewStringUTF ((char *)*args);
92
111
}
93
112
else {
94
113
jobject object = callbackObjCache.count (*args) ? callbackObjCache[*args] : static_cast <jobject>(*args);
@@ -137,61 +156,38 @@ jclass findClass(JNIEnv *env, const char *name) {
137
156
return nativeClass;
138
157
}
139
158
140
- jobject newObject (JNIEnv *env, jclass cls, void **args, char **argTypes) {
159
+ jobject newObject (jclass cls, void **args, char **argTypes) {
141
160
char *signature = generateSignature (argTypes);
142
161
jvalue *argValues = new jvalue[strlen (signature) - 2 ];
143
162
if (strlen (signature) - 2 > 0 ) {
144
- fillArgs (args, argTypes, argValues, env );
163
+ fillArgs (args, argTypes, argValues);
145
164
}
146
- jmethodID constructor = env->GetMethodID (cls, " <init>" , spliceChar (signature, const_cast <char *>(" V" )));
147
- jobject newObj = env->NewObjectA (cls, constructor, argValues);
165
+ char *constructorSig = spliceChar (signature, const_cast <char *>(" V" ));
166
+ jmethodID constructor = gCurEnv ->GetMethodID (cls, " <init>" , constructorSig);
167
+ jobject newObj = gCurEnv ->NewObjectA (cls, constructor, argValues);
148
168
free (argValues);
169
+ free (constructorSig);
149
170
return newObj;
150
171
}
151
172
152
173
void *createTargetClass (char *targetClassName, void **args, char **argTypes) {
153
- JNIEnv *curEnv;
154
- bool bShouldDetach = false ;
155
-
156
- auto error = gJvm ->GetEnv ((void **) &curEnv, JNI_VERSION_1_6);
157
- if (error < 0 ) {
158
- error = gJvm ->AttachCurrentThread (&curEnv, nullptr );
159
- bShouldDetach = true ;
160
- NSLog (" AttachCurrentThread : %d" , error);
161
- }
162
-
163
- jclass cls = findClass (curEnv, targetClassName);
174
+ attachThread ();
164
175
165
- jobject newObj = curEnv->NewGlobalRef (newObject (curEnv, cls, args, argTypes));
166
- cache[newObj] = static_cast <jclass>(curEnv->NewGlobalRef (cls));
176
+ jclass cls = findClass (gCurEnv , targetClassName);
167
177
168
-
169
- if (bShouldDetach) {
170
- gJvm ->DetachCurrentThread ();
171
- }
178
+ jobject newObj = gCurEnv ->NewGlobalRef (newObject (cls, args, argTypes));
179
+ cache[newObj] = static_cast <jclass>(gCurEnv ->NewGlobalRef (cls));
172
180
173
181
return newObj;
174
182
}
175
183
176
184
177
185
void releaseTargetClass (void *classPtr) {
178
- JNIEnv *curEnv;
179
- bool bShouldDetach = false ;
180
-
181
- auto error = gJvm ->GetEnv ((void **) &curEnv, JNI_VERSION_1_6);
182
- if (error < 0 ) {
183
- error = gJvm ->AttachCurrentThread (&curEnv, nullptr );
184
- bShouldDetach = true ;
185
- NSLog (" AttachCurrentThread : %d" , error);
186
- }
186
+ attachThread ();
187
187
188
188
jobject object = static_cast <jobject>(classPtr);
189
189
cache.erase (object);
190
- curEnv->DeleteGlobalRef (object);
191
-
192
- if (bShouldDetach) {
193
- gJvm ->DetachCurrentThread ();
194
- }
190
+ gCurEnv ->DeleteGlobalRef (object);
195
191
}
196
192
197
193
void retain (void *classPtr) {
@@ -216,82 +212,75 @@ void release(void *classPtr) {
216
212
}
217
213
218
214
void *invokeNativeMethodNeo (void *classPtr, char *methodName, void **args, char **argTypes, char *returnType) {
219
- JNIEnv *curEnv;
220
- bool bShouldDetach = false ;
221
215
void *nativeInvokeResult = nullptr ;
222
216
223
- auto error = gJvm ->GetEnv ((void **) &curEnv, JNI_VERSION_1_6);
224
- if (error < 0 ) {
225
- gJvm ->AttachCurrentThread (&curEnv, nullptr );
226
- bShouldDetach = true ;
227
- }
217
+ attachThread ();
228
218
jobject object = static_cast <jobject>(classPtr);
229
219
jclass cls = cache[object];
230
220
char *signature = generateSignature (argTypes);
231
221
jvalue *argValues = new jvalue[strlen (signature) - 2 ];
232
222
if ((strlen (signature) - 2 ) > 0 ) {
233
- fillArgs (args, argTypes, argValues, curEnv );
223
+ fillArgs (args, argTypes, argValues);
234
224
}
235
- jmethodID method = curEnv->GetMethodID (cls, methodName, spliceChar (signature, returnType));
236
- NSLog (" call method: %s descriptor: %s" , methodName, spliceChar(signature, returnType));
225
+ char *methodSignature = spliceChar (signature, returnType);
226
+ jmethodID method = gCurEnv ->GetMethodID (cls, methodName, methodSignature);
227
+ NSLog (" call method: %s descriptor: %s" , methodName, methodSignature);
237
228
238
- if (strlen (returnType) > 1 ) {
229
+ if (strlen (returnType) > 1 ) {
239
230
if (strcmp (returnType, " Ljava/lang/String;" ) == 0 ) {
240
- jstring javaString = (jstring)curEnv ->CallObjectMethodA (object, method, argValues);
231
+ jstring javaString = (jstring)gCurEnv ->CallObjectMethodA (object, method, argValues);
241
232
jboolean isCopy = JNI_FALSE;
242
- nativeInvokeResult = (char *) curEnv ->GetStringUTFChars (javaString, &isCopy);
233
+ nativeInvokeResult = (char *) gCurEnv ->GetStringUTFChars (javaString, &isCopy);
243
234
}
244
235
else {
245
- jobject obj = curEnv ->NewGlobalRef (curEnv ->CallObjectMethodA (object, method, argValues));
246
- jclass objCls = curEnv ->GetObjectClass (obj);
236
+ jobject obj = gCurEnv ->NewGlobalRef (gCurEnv ->CallObjectMethodA (object, method, argValues));
237
+ jclass objCls = gCurEnv ->GetObjectClass (obj);
247
238
// store class value
248
- cache[obj] = static_cast <jclass>(curEnv ->NewGlobalRef (objCls));
239
+ cache[obj] = static_cast <jclass>(gCurEnv ->NewGlobalRef (objCls));
249
240
nativeInvokeResult = obj;
250
241
}
251
242
}
252
243
else if (strcmp (returnType, " C" ) == 0 ) {
253
- auto nativeChar = curEnv ->CallCharMethodA (object, method, argValues);
244
+ auto nativeChar = gCurEnv ->CallCharMethodA (object, method, argValues);
254
245
nativeInvokeResult = (void *) nativeChar;
255
246
}
256
247
else if (strcmp (returnType, " I" ) == 0 ) {
257
- auto nativeInt = curEnv ->CallIntMethodA (object, method, argValues);
248
+ auto nativeInt = gCurEnv ->CallIntMethodA (object, method, argValues);
258
249
nativeInvokeResult = (void *) nativeInt;
259
250
}
260
251
else if (strcmp (returnType, " D" ) == 0 ) {
261
- auto nativeDouble = curEnv ->CallDoubleMethodA (object, method, argValues);
252
+ auto nativeDouble = gCurEnv ->CallDoubleMethodA (object, method, argValues);
262
253
double cDouble = (double ) nativeDouble;
263
254
memcpy (&nativeInvokeResult, &cDouble, sizeof (double ));
264
255
}
265
256
else if (strcmp (returnType, " F" ) == 0 ) {
266
- auto nativeDouble = curEnv ->CallFloatMethodA (object, method, argValues);
257
+ auto nativeDouble = gCurEnv ->CallFloatMethodA (object, method, argValues);
267
258
float cDouble = (float ) nativeDouble;
268
259
memcpy (&nativeInvokeResult, &cDouble, sizeof (float ));
269
260
}
270
261
else if (strcmp (returnType, " B" ) == 0 ) {
271
- auto nativeByte = curEnv ->CallByteMethodA (object, method, argValues);
262
+ auto nativeByte = gCurEnv ->CallByteMethodA (object, method, argValues);
272
263
nativeInvokeResult = (void *) nativeByte;
273
264
}
274
265
else if (strcmp (returnType, " S" ) == 0 ) {
275
- auto nativeShort = curEnv ->CallShortMethodA (object, method, argValues);
266
+ auto nativeShort = gCurEnv ->CallShortMethodA (object, method, argValues);
276
267
nativeInvokeResult = (void *) nativeShort;
277
268
}
278
269
else if (strcmp (returnType, " J" ) == 0 ) {
279
- auto nativeLong = curEnv ->CallLongMethodA (object, method, argValues);
270
+ auto nativeLong = gCurEnv ->CallLongMethodA (object, method, argValues);
280
271
nativeInvokeResult = (void *) nativeLong;
281
272
}
282
273
else if (strcmp (returnType, " Z" ) == 0 ) {
283
- auto nativeBool = curEnv ->CallBooleanMethodA (object, method, argValues);
274
+ auto nativeBool = gCurEnv ->CallBooleanMethodA (object, method, argValues);
284
275
nativeInvokeResult = (void *) nativeBool;
285
276
}
286
277
else if (strcmp (returnType, " V" ) == 0 ) {
287
- curEnv ->CallVoidMethodA (object, method, argValues);
278
+ gCurEnv ->CallVoidMethodA (object, method, argValues);
288
279
}
289
280
290
281
free (argValues);
282
+ free (methodSignature);
291
283
free (signature);
292
- if (bShouldDetach) {
293
- gJvm ->DetachCurrentThread ();
294
- }
295
284
return nativeInvokeResult;
296
285
}
297
286
@@ -318,31 +307,21 @@ NativeMethodCallback getCallbackMethod(jlong targetAddr, char *functionName) {
318
307
}
319
308
320
309
void registerNativeCallback (void *target, char * targetName, char *funName, void *callback) {
321
- JNIEnv *curEnv;
322
- bool bShouldDetach = false ;
323
- auto error = gJvm ->GetEnv ((void **) &curEnv, JNI_VERSION_1_6);
324
- if (error < 0 ) {
325
- error = gJvm ->AttachCurrentThread (&curEnv, nullptr );
326
- bShouldDetach = true ;
327
- NSLog (" AttachCurrentThread : %d" , error);
328
- }
310
+ attachThread ();
329
311
330
- jclass callbackManager = findClass (curEnv , " com/dartnative/dart_native/CallbackManager" );
331
- jmethodID registerCallback = curEnv ->GetStaticMethodID (callbackManager, " registerCallback" , " (JLjava/lang/String;)Ljava/lang/Object;" );
312
+ jclass callbackManager = findClass (gCurEnv , " com/dartnative/dart_native/CallbackManager" );
313
+ jmethodID registerCallback = gCurEnv ->GetStaticMethodID (callbackManager, " registerCallback" , " (JLjava/lang/String;)Ljava/lang/Object;" );
332
314
jlong targetAddr = (jlong)target;
333
315
jvalue *argValues = new jvalue[2 ];
334
316
argValues[0 ].j = targetAddr;
335
- argValues[1 ].l = curEnv ->NewStringUTF (targetName);
336
- jobject callbackOJ = curEnv ->NewGlobalRef (curEnv ->CallStaticObjectMethodA (callbackManager, registerCallback, argValues));
317
+ argValues[1 ].l = gCurEnv ->NewStringUTF (targetName);
318
+ jobject callbackOJ = gCurEnv ->NewGlobalRef (gCurEnv ->CallStaticObjectMethodA (callbackManager, registerCallback, argValues));
337
319
callbackObjCache[target] = callbackOJ;
338
320
targetCache[targetAddr] = target;
339
321
340
322
registerCallbackManager (targetAddr, funName, callback);
341
- curEnv ->DeleteLocalRef (callbackManager);
323
+ gCurEnv ->DeleteLocalRef (callbackManager);
342
324
free (argValues);
343
- if (bShouldDetach) {
344
- gJvm ->DetachCurrentThread ();
345
- }
346
325
}
347
326
348
327
// Dart extensions
@@ -407,10 +386,9 @@ JNIEXPORT jobject JNICALL Java_com_dartnative_dart_1native_CallbackInvocationHan
407
386
char **argTypes = new char *[argTypeLength + 1 ];
408
387
void **arguments = new void *[argTypeLength];
409
388
for (int i = 0 ; i < argTypeLength; ++i) {
410
- jobject argType = env->GetObjectArrayElement (arg_types, i);
389
+ jstring argTypeString = (jstring) env->GetObjectArrayElement (arg_types, i);
411
390
jobject argument = env->GetObjectArrayElement (args, i);
412
391
413
- jstring argTypeString = (jstring) argType;
414
392
argTypes[i] = (char *) env->GetStringUTFChars (argTypeString, 0 );
415
393
env->DeleteLocalRef (argTypeString);
416
394
// todo optimization
@@ -451,7 +429,7 @@ JNIEXPORT jobject JNICALL Java_com_dartnative_dart_1native_CallbackInvocationHan
451
429
}
452
430
char *returnType = (char *) env->GetStringUTFChars (return_type, 0 );
453
431
argTypes[argTypeLength] = returnType;
454
- const Work work = [dartObject, argTypes, arguments, arg_count, funName, &sem, isSemInitSuccess, return_type ]() {
432
+ const Work work = [dartObject, argTypes, arguments, arg_count, funName, &sem, isSemInitSuccess]() {
455
433
NativeMethodCallback methodCallback = getCallbackMethod (dartObject, funName);
456
434
void *target = targetCache[dartObject];
457
435
if (methodCallback != NULL && target != nullptr ) {
@@ -469,10 +447,12 @@ JNIEXPORT jobject JNICALL Java_com_dartnative_dart_1native_CallbackInvocationHan
469
447
jobject callbackResult = NULL ;
470
448
471
449
if (isSemInitSuccess) {
472
- NSLog (" wait" );
450
+ NSLog (" wait work execute " );
473
451
sem_wait (&sem);
474
452
// todo optimization
475
- if (strcmp (returnType, " Ljava/lang/String;" ) == 0 ) {
453
+ if (returnType == nullptr ) {
454
+ NSLog (" void" );
455
+ } else if (strcmp (returnType, " Ljava/lang/String;" ) == 0 ) {
476
456
callbackResult = env->NewStringUTF ((char *) arguments[0 ]);
477
457
} else if (strcmp (returnType, " Z" ) == 0 ) {
478
458
jclass booleanClass = env->FindClass (" java/lang/Boolean" );
@@ -483,9 +463,10 @@ JNIEXPORT jobject JNICALL Java_com_dartnative_dart_1native_CallbackInvocationHan
483
463
sem_destroy (&sem);
484
464
}
485
465
466
+ free (returnType);
486
467
free (funName);
487
- free (argTypes);
488
468
free (arguments);
469
+ free (argTypes);
489
470
490
471
return callbackResult;
491
472
}
0 commit comments