Skip to content

Commit 7f6b275

Browse files
Merge pull request #56 from dart-native/feature/android_string
Feature/android string
2 parents aab880d + 9546328 commit 7f6b275

File tree

3 files changed

+74
-64
lines changed

3 files changed

+74
-64
lines changed

dart_native/android/src/main/jni/dart_native.cpp

Lines changed: 67 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,26 @@ extern "C"
2121
/// for invoke result compare
2222
static jclass gStrCls;
2323

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+
}
2644

2745
void _detachThreadDestructor(void *arg)
2846
{
@@ -31,6 +49,7 @@ extern "C"
3149
detachKey = 0;
3250
}
3351

52+
/// each thread attach once
3453
JNIEnv *_getEnv()
3554
{
3655
if (gJvm == nullptr)
@@ -77,6 +96,7 @@ extern "C"
7796
gFindClassMethod = env->GetMethodID(classLoaderClass, "findClass",
7897
"(Ljava/lang/String;)Ljava/lang/Class;");
7998

99+
/// cache string class
80100
jclass strCls = env->FindClass("java/lang/String");
81101
gStrCls = static_cast<jclass>(env->NewGlobalRef(strCls));
82102

@@ -94,6 +114,7 @@ extern "C"
94114
jclass nativeClass = nullptr;
95115
nativeClass = env->FindClass(name);
96116
jthrowable exception = env->ExceptionOccurred();
117+
/// class loader not found class
97118
if (exception)
98119
{
99120
env->ExceptionClear();
@@ -106,6 +127,7 @@ extern "C"
106127
}
107128

108129
/// fill all arguments to jvalues
130+
/// when argument is string the stringTypeBitmask's bit is 1
109131
void _fillArgs(void **arguments, char **argumentTypes, jvalue *argValues, int argumentCount, uint32_t stringTypeBitmask)
110132
{
111133
JNIEnv *env = _getEnv();
@@ -161,7 +183,7 @@ extern "C"
161183
jclass cls = _findClass(env, targetClassName);
162184
jobject newObj = _newObject(cls, arguments, argumentTypes, argumentCount, stringTypeBitmask);
163185
jobject gObj = env->NewGlobalRef(newObj);
164-
objectGlobalCache[gObj] = static_cast<jclass>(env->NewGlobalRef(cls));
186+
_addGlobalObject(gObj, static_cast<jclass>(env->NewGlobalRef(cls)));
165187

166188
env->DeleteLocalRef(newObj);
167189
env->DeleteLocalRef(cls);
@@ -171,12 +193,18 @@ extern "C"
171193
/// invoke native method
172194
void *invokeNativeMethod(void *objPtr, char *methodName, void **arguments, char **dataTypes, int argumentCount, char *returnType, uint32_t stringTypeBitmask)
173195
{
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+
174205
void *nativeInvokeResult = nullptr;
175206
JNIEnv *env = _getEnv();
176207

177-
auto object = static_cast<jobject>(objPtr);
178-
jclass cls = objectGlobalCache[object];
179-
180208
auto *argValues = new jvalue[argumentCount];
181209
if (argumentCount > 0)
182210
{
@@ -203,14 +231,14 @@ extern "C"
203231
{
204232
/// mark the last pointer as string
205233
/// dart will check this pointer
206-
dataTypes[argumentCount] = (char *) "java.lang.String";
234+
dataTypes[argumentCount] = (char *)"java.lang.String";
207235
nativeInvokeResult = convertToDartUtf16(env, (jstring)obj);
208236
}
209237
else
210238
{
211239
jclass objCls = env->GetObjectClass(obj);
212240
jobject gObj = env->NewGlobalRef(obj);
213-
objectGlobalCache[gObj] = static_cast<jclass>(env->NewGlobalRef(objCls));
241+
_addGlobalObject(gObj, static_cast<jclass>(env->NewGlobalRef(objCls)));
214242
nativeInvokeResult = gObj;
215243

216244
env->DeleteLocalRef(objCls);
@@ -257,50 +285,45 @@ extern "C"
257285
return Dart_InitializeApiDL(data);
258286
}
259287

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)
281290
{
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())
284295
{
285-
DNError("release error not contain object");
296+
DNError("_updateObjectReference %s error not contain this object!!!", isRetain ? "retain" : "release");
286297
return;
287298
}
288-
int count = referenceCount[object];
289-
if (count <= 1)
299+
300+
if (isRetain)
290301
{
291-
referenceCount.erase(object);
292-
_releaseTargetObject(objPtr);
302+
/// dart object retain this dart object
303+
/// reference++
304+
it->second.second += 1;
293305
return;
294306
}
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+
}
296319
}
297320

298321
/// release native object from cache
299322
static void RunFinalizer(void *isolate_callback_data,
300323
Dart_WeakPersistentHandle handle,
301324
void *peer)
302325
{
303-
_release(peer);
326+
_updateObjectReference(static_cast<jobject>(peer), false);
304327
}
305328

306329
/// retain native object
@@ -311,7 +334,7 @@ extern "C"
311334
DNError("Dart_IsError_DL");
312335
return;
313336
}
314-
_retain(objPtr);
337+
_updateObjectReference(static_cast<jobject>(objPtr), true);
315338
intptr_t size = 8;
316339
Dart_NewWeakPersistentHandle_DL(h, objPtr, size, RunFinalizer);
317340
}
@@ -367,17 +390,16 @@ extern "C"
367390
auto argTypeString = (jstring)env->GetObjectArrayElement(argumentTypes, i);
368391
auto argument = env->GetObjectArrayElement(argumentsArray, i);
369392
dataTypes[i] = (char *)env->GetStringUTFChars(argTypeString, 0);
370-
371393
if (strcmp(dataTypes[i], "java.lang.String") == 0)
372394
{
373-
arguments[i] = (jstring) argument == nullptr ? reinterpret_cast<uint16_t *>((char *)"")
395+
arguments[i] = (jstring)argument == nullptr ? reinterpret_cast<uint16_t *>((char *)"")
374396
: convertToDartUtf16(env, (jstring)argument);
375397
}
376398
else
377399
{
378400
jclass objCls = env->GetObjectClass(argument);
379401
jobject gObj = env->NewGlobalRef(argument);
380-
objectGlobalCache[gObj] = static_cast<jclass>(env->NewGlobalRef(objCls));
402+
_addGlobalObject(gObj, static_cast<jclass>(env->NewGlobalRef(objCls)));
381403
arguments[i] = gObj;
382404

383405
env->DeleteLocalRef(objCls);
@@ -398,7 +420,7 @@ extern "C"
398420

399421
const Work work = [dartObjectAddress, dataTypes, arguments, argumentCount, funName, &sem, isSemInitSuccess]() {
400422
NativeMethodCallback methodCallback = getCallbackMethod(dartObjectAddress, funName);
401-
void *target = getDartObject(dartObjectAddress);
423+
void *target = (void *)dartObjectAddress;
402424
if (methodCallback != nullptr && target != nullptr)
403425
{
404426
methodCallback(target, funName, arguments, dataTypes, argumentCount);
@@ -422,9 +444,9 @@ extern "C"
422444
{
423445
callbackResult = convertToJavaUtf16(env, (char *)arguments[argumentCount], nullptr, 0);
424446
}
425-
else
447+
else if (strcmp(returnType, "void") != 0)
426448
{
427-
callbackResult = (jobject) arguments[argumentCount];
449+
callbackResult = (jobject)arguments[argumentCount];
428450
}
429451
}
430452
sem_destroy(&sem);

dart_native/android/src/main/jni/dn_callback.cpp

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
#include "dn_log.h"
77
#include "dn_type_convert.h"
88

9-
static std::map<jlong, void *> targetCache;
9+
/// key is dart object pointer address, value is dart port
1010
static std::map<jlong, int64_t> dartPortCache;
11-
static std::map<void *, jobject> callbackObjCache;
11+
/// key is dart object pointer, value is native proxy object
12+
static std::map<void *, jobject> nativeProxyObjectCache;
13+
/// key is dart object pointer address, value is method
1214
static std::map<jlong, std::map<std::string, NativeMethodCallback>> callbackFunctionCache;
1315

1416
void registerCallbackManager(jlong dartObjectAddress, char *functionName, void *callback)
@@ -31,22 +33,21 @@ void registerCallbackManager(jlong dartObjectAddress, char *functionName, void *
3133
void doRegisterNativeCallback(void *dartObject, jobject nativeProxyObject, char *funName, void *callback, Dart_Port dartPort)
3234
{
3335
auto dartObjectAddress = (jlong) dartObject;
34-
callbackObjCache[dartObject] = nativeProxyObject;
35-
targetCache[dartObjectAddress] = dartObject;
36+
nativeProxyObjectCache[dartObject] = nativeProxyObject;
3637
dartPortCache[dartObjectAddress] = dartPort;
3738

3839
registerCallbackManager(dartObjectAddress, funName, callback);
3940
}
4041

4142
jobject getNativeCallbackProxyObject(void *dartObject)
4243
{
43-
if (callbackObjCache.find(dartObject) == callbackObjCache.end())
44+
if (nativeProxyObjectCache.find(dartObject) == nativeProxyObjectCache.end())
4445
{
4546
DNInfo("getNativeCallbackProxyObject: not contain this dart object");
4647
return nullptr;
4748
}
4849

49-
return callbackObjCache[dartObject];
50+
return nativeProxyObjectCache[dartObject];
5051
}
5152

5253
Dart_Port getCallbackDartPort(jlong dartObjectAddress)
@@ -60,17 +61,6 @@ Dart_Port getCallbackDartPort(jlong dartObjectAddress)
6061
return dartPortCache[dartObjectAddress];
6162
}
6263

63-
void *getDartObject(jlong dartObjectAddress)
64-
{
65-
if (targetCache.find(dartObjectAddress) == targetCache.end())
66-
{
67-
DNInfo("getDartObject: targetCache not contain this dart object %d", dartObjectAddress);
68-
return nullptr;
69-
}
70-
71-
return targetCache[dartObjectAddress];
72-
}
73-
7464
NativeMethodCallback getCallbackMethod(jlong dartObjectAddress, char *functionName)
7565
{
7666
if (!callbackFunctionCache.count(dartObjectAddress))

dart_native/android/src/main/jni/dn_callback.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ extern "C"
2424

2525
Dart_Port getCallbackDartPort(jlong dartObjectAddress);
2626

27-
void *getDartObject(jlong dartObjectAddress);
28-
2927
NativeMethodCallback getCallbackMethod(jlong dartObjectAddress, char *functionName);
3028

3129
#ifdef __cplusplus

0 commit comments

Comments
 (0)