@@ -21,8 +21,26 @@ extern "C"
21
21
// / for invoke result compare
22
22
static jclass gStrCls ;
23
23
24
- static std::map<jobject, jclass> objectGlobalCache;
25
- static std::map<jobject, int > referenceCount;
24
+ // / key is jobject, value is pai which contain jclass and reference count
25
+ static std::map<jobject, std::pair<jclass, int > > objectGlobalReference;
26
+
27
+ // / protect objectGlobalReference
28
+ std::mutex globalReferenceMtx;
29
+
30
+ void _addGlobalObject (jobject globalObject, jclass globalClass)
31
+ {
32
+ std::lock_guard<std::mutex> lockGuard (globalReferenceMtx);
33
+ std::pair<jclass, int > objPair = std::make_pair (globalClass, 0 );
34
+ objectGlobalReference[globalObject] = objPair;
35
+ }
36
+
37
+ jclass _getGlobalClass (jobject globalObject)
38
+ {
39
+ std::lock_guard<std::mutex> lockGuard (globalReferenceMtx);
40
+ auto it = objectGlobalReference.find (globalObject);
41
+ auto cls = it != objectGlobalReference.end () ? it->second .first : nullptr ;
42
+ return cls;
43
+ }
26
44
27
45
void _detachThreadDestructor (void *arg)
28
46
{
@@ -31,6 +49,7 @@ extern "C"
31
49
detachKey = 0 ;
32
50
}
33
51
52
+ // / each thread attach once
34
53
JNIEnv *_getEnv ()
35
54
{
36
55
if (gJvm == nullptr )
@@ -77,6 +96,7 @@ extern "C"
77
96
gFindClassMethod = env->GetMethodID (classLoaderClass, " findClass" ,
78
97
" (Ljava/lang/String;)Ljava/lang/Class;" );
79
98
99
+ // / cache string class
80
100
jclass strCls = env->FindClass (" java/lang/String" );
81
101
gStrCls = static_cast <jclass>(env->NewGlobalRef (strCls));
82
102
@@ -94,6 +114,7 @@ extern "C"
94
114
jclass nativeClass = nullptr ;
95
115
nativeClass = env->FindClass (name);
96
116
jthrowable exception = env->ExceptionOccurred ();
117
+ // / class loader not found class
97
118
if (exception)
98
119
{
99
120
env->ExceptionClear ();
@@ -106,6 +127,7 @@ extern "C"
106
127
}
107
128
108
129
// / fill all arguments to jvalues
130
+ // / when argument is string the stringTypeBitmask's bit is 1
109
131
void _fillArgs (void **arguments, char **argumentTypes, jvalue *argValues, int argumentCount, uint32_t stringTypeBitmask)
110
132
{
111
133
JNIEnv *env = _getEnv ();
@@ -161,7 +183,7 @@ extern "C"
161
183
jclass cls = _findClass (env, targetClassName);
162
184
jobject newObj = _newObject (cls, arguments, argumentTypes, argumentCount, stringTypeBitmask);
163
185
jobject gObj = env->NewGlobalRef (newObj);
164
- objectGlobalCache[ gObj ] = static_cast <jclass>(env->NewGlobalRef (cls));
186
+ _addGlobalObject ( gObj , static_cast <jclass>(env->NewGlobalRef (cls) ));
165
187
166
188
env->DeleteLocalRef (newObj);
167
189
env->DeleteLocalRef (cls);
@@ -171,12 +193,18 @@ extern "C"
171
193
// / invoke native method
172
194
void *invokeNativeMethod (void *objPtr, char *methodName, void **arguments, char **dataTypes, int argumentCount, char *returnType, uint32_t stringTypeBitmask)
173
195
{
196
+ auto object = static_cast <jobject>(objPtr);
197
+ jclass cls = _getGlobalClass (object);
198
+ if (cls == nullptr )
199
+ {
200
+ // / maybe use cache pointer but jobject is release
201
+ DNError (" invokeNativeMethod not find class, check pointer and jobject lifecycle is same" );
202
+ return nullptr ;
203
+ }
204
+
174
205
void *nativeInvokeResult = nullptr ;
175
206
JNIEnv *env = _getEnv ();
176
207
177
- auto object = static_cast <jobject>(objPtr);
178
- jclass cls = objectGlobalCache[object];
179
-
180
208
auto *argValues = new jvalue[argumentCount];
181
209
if (argumentCount > 0 )
182
210
{
@@ -203,14 +231,14 @@ extern "C"
203
231
{
204
232
// / mark the last pointer as string
205
233
// / dart will check this pointer
206
- dataTypes[argumentCount] = (char *) " java.lang.String" ;
234
+ dataTypes[argumentCount] = (char *)" java.lang.String" ;
207
235
nativeInvokeResult = convertToDartUtf16 (env, (jstring)obj);
208
236
}
209
237
else
210
238
{
211
239
jclass objCls = env->GetObjectClass (obj);
212
240
jobject gObj = env->NewGlobalRef (obj);
213
- objectGlobalCache[ gObj ] = static_cast <jclass>(env->NewGlobalRef (objCls));
241
+ _addGlobalObject ( gObj , static_cast <jclass>(env->NewGlobalRef (objCls) ));
214
242
nativeInvokeResult = gObj ;
215
243
216
244
env->DeleteLocalRef (objCls);
@@ -257,50 +285,45 @@ extern "C"
257
285
return Dart_InitializeApiDL (data);
258
286
}
259
287
260
- // / retain native object
261
- void _retain (void *objPtr)
262
- {
263
- auto object = static_cast <jobject>(objPtr);
264
- auto it = referenceCount.find (object);
265
- int refCount = it == referenceCount.end () ? 1 : referenceCount[object] + 1 ;
266
- referenceCount[object] = refCount;
267
- }
268
-
269
- // / do release native object
270
- void _releaseTargetObject (void *objPtr)
271
- {
272
- JNIEnv *env = _getEnv ();
273
- auto object = static_cast <jobject>(objPtr);
274
- env->DeleteGlobalRef (objectGlobalCache[object]);
275
- objectGlobalCache.erase (object);
276
- env->DeleteGlobalRef (object);
277
- }
278
-
279
- // / check reference count, if no reference exits then release
280
- void _release (void *objPtr)
288
+ // / reference counter
289
+ void _updateObjectReference (jobject globalObject, bool isRetain)
281
290
{
282
- auto object = static_cast <jobject>(objPtr);
283
- if (referenceCount.find (object) == referenceCount.end ())
291
+ std::lock_guard<std::mutex> lockGuard (globalReferenceMtx);
292
+ DNDebug (" _updateObjectReference %s" , isRetain ? " retain" : " release" );
293
+ auto it = objectGlobalReference.find (globalObject);
294
+ if (it == objectGlobalReference.end ())
284
295
{
285
- DNError (" release error not contain object" );
296
+ DNError (" _updateObjectReference %s error not contain this object!!! " , isRetain ? " retain " : " release " );
286
297
return ;
287
298
}
288
- int count = referenceCount[object];
289
- if (count <= 1 )
299
+
300
+ if (isRetain )
290
301
{
291
- referenceCount.erase (object);
292
- _releaseTargetObject (objPtr);
302
+ // / dart object retain this dart object
303
+ // / reference++
304
+ it->second .second += 1 ;
293
305
return ;
294
306
}
295
- referenceCount[object] = count - 1 ;
307
+
308
+ // / release reference--
309
+ it->second .second -= 1 ;
310
+
311
+ // / no dart object retained this native object
312
+ if (it->second .second <= 0 )
313
+ {
314
+ JNIEnv *env = _getEnv ();
315
+ env->DeleteGlobalRef (it->second .first );
316
+ objectGlobalReference.erase (it);
317
+ env->DeleteGlobalRef (globalObject);
318
+ }
296
319
}
297
320
298
321
// / release native object from cache
299
322
static void RunFinalizer (void *isolate_callback_data,
300
323
Dart_WeakPersistentHandle handle,
301
324
void *peer)
302
325
{
303
- _release ( peer);
326
+ _updateObjectReference ( static_cast <jobject>( peer), false );
304
327
}
305
328
306
329
// / retain native object
@@ -311,7 +334,7 @@ extern "C"
311
334
DNError (" Dart_IsError_DL" );
312
335
return ;
313
336
}
314
- _retain ( objPtr);
337
+ _updateObjectReference ( static_cast <jobject>( objPtr), true );
315
338
intptr_t size = 8 ;
316
339
Dart_NewWeakPersistentHandle_DL (h, objPtr, size, RunFinalizer);
317
340
}
@@ -367,17 +390,16 @@ extern "C"
367
390
auto argTypeString = (jstring)env->GetObjectArrayElement (argumentTypes, i);
368
391
auto argument = env->GetObjectArrayElement (argumentsArray, i);
369
392
dataTypes[i] = (char *)env->GetStringUTFChars (argTypeString, 0 );
370
-
371
393
if (strcmp (dataTypes[i], " java.lang.String" ) == 0 )
372
394
{
373
- arguments[i] = (jstring) argument == nullptr ? reinterpret_cast <uint16_t *>((char *)" " )
395
+ arguments[i] = (jstring)argument == nullptr ? reinterpret_cast <uint16_t *>((char *)" " )
374
396
: convertToDartUtf16 (env, (jstring)argument);
375
397
}
376
398
else
377
399
{
378
400
jclass objCls = env->GetObjectClass (argument);
379
401
jobject gObj = env->NewGlobalRef (argument);
380
- objectGlobalCache[ gObj ] = static_cast <jclass>(env->NewGlobalRef (objCls));
402
+ _addGlobalObject ( gObj , static_cast <jclass>(env->NewGlobalRef (objCls) ));
381
403
arguments[i] = gObj ;
382
404
383
405
env->DeleteLocalRef (objCls);
@@ -398,7 +420,7 @@ extern "C"
398
420
399
421
const Work work = [dartObjectAddress, dataTypes, arguments, argumentCount, funName, &sem, isSemInitSuccess]() {
400
422
NativeMethodCallback methodCallback = getCallbackMethod (dartObjectAddress, funName);
401
- void *target = getDartObject (dartObjectAddress) ;
423
+ void *target = ( void *)dartObjectAddress ;
402
424
if (methodCallback != nullptr && target != nullptr )
403
425
{
404
426
methodCallback (target, funName, arguments, dataTypes, argumentCount);
@@ -422,9 +444,9 @@ extern "C"
422
444
{
423
445
callbackResult = convertToJavaUtf16 (env, (char *)arguments[argumentCount], nullptr , 0 );
424
446
}
425
- else
447
+ else if ( strcmp (returnType, " void " ) != 0 )
426
448
{
427
- callbackResult = (jobject) arguments[argumentCount];
449
+ callbackResult = (jobject)arguments[argumentCount];
428
450
}
429
451
}
430
452
sem_destroy (&sem);
0 commit comments