6
6
#include < map>
7
7
#include < string>
8
8
#include < regex>
9
+ #include < dart_api_dl.h>
9
10
10
11
extern " C" {
11
12
@@ -53,8 +54,22 @@ jclass findClass(JNIEnv *env, const char *name) {
53
54
env->NewStringUTF (name)));
54
55
}
55
56
56
- // todo 泄漏
57
+ typedef void (*NativeMethodCallback)(
58
+ void *targetPtr,
59
+ char *funNamePtr,
60
+ void **args,
61
+ char **argTypes,
62
+ int argCount
63
+ );
64
+
57
65
static std::map<jobject, jclass> cache;
66
+ static std::map<jobject, int > referenceCount;
67
+
68
+ // todo too many cache
69
+ // for callback
70
+ static std::map<void *, jobject> callbackObjCache;
71
+ static std::map<jlong, std::map<std::string, NativeMethodCallback>> callbackManagerCache;
72
+ static std::map<jlong, void *> targetCache;
58
73
59
74
void *createTargetClass (char *targetClassName) {
60
75
JNIEnv *curEnv;
@@ -101,14 +116,25 @@ void releaseTargetClass(void *classPtr) {
101
116
}
102
117
}
103
118
104
- char *findReturnType (JNIEnv *curEnv, jclass cls, jobject object, char * methondName, char **argType) {
105
- jclass nativeClass = curEnv->FindClass (" com/dartnative/dart_native/DartNative" );
106
- jmethodID nativeMethodID = curEnv->GetStaticMethodID (nativeClass,
107
- " getMethodReturnType" , " (Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/String;" );
108
-
109
- // jobjectArray stringArray = new jobjectArray()
119
+ void retain (void *classPtr) {
120
+ jobject object = static_cast <jobject>(classPtr);
121
+ int refCount = referenceCount[object] == NULL ? 1 : referenceCount[object] + 1 ;
122
+ referenceCount[object] = refCount;
123
+ }
110
124
111
- // curEnv->CallStaticObjectMethodA(nativeClass, nativeMethodID, argType);
125
+ void release (void *classPtr) {
126
+ jobject object = static_cast <jobject>(classPtr);
127
+ if (referenceCount[object] == NULL ) {
128
+ NSLog (" not contain object" );
129
+ return ;
130
+ }
131
+ int count = referenceCount[object];
132
+ if (count <= 1 ) {
133
+ releaseTargetClass (classPtr);
134
+ referenceCount[object] = NULL ;
135
+ return ;
136
+ }
137
+ referenceCount[object] = count - 1 ;
112
138
}
113
139
114
140
char *spliceChar (char *dest, char *src) {
@@ -135,7 +161,7 @@ void fillArgs(void **args, char **argTypes, jvalue *argValues, JNIEnv *curEnv) {
135
161
argValues[index].l = curEnv->NewStringUTF ((char *)*args);
136
162
}
137
163
else {
138
- jobject object = static_cast <jobject>(*args);
164
+ jobject object = callbackObjCache. count (*args) ? callbackObjCache[*args] : static_cast <jobject>(*args);
139
165
argValues[index].l = object;
140
166
}
141
167
}
@@ -248,5 +274,166 @@ void *invokeNativeMethodNeo(void *classPtr, char *methodName, void **args, char
248
274
return nativeInvokeResult;
249
275
}
250
276
277
+ void registerCallbackManager (jlong targetAddr, char *functionName, void *callback) {
278
+ std::map<std::string, NativeMethodCallback> methodsMap;
279
+ if (!callbackManagerCache.count (targetAddr)) {
280
+ methodsMap[functionName] = (NativeMethodCallback) callback;
281
+ callbackManagerCache[targetAddr] = methodsMap;
282
+ return ;
283
+ }
284
+
285
+ methodsMap = callbackManagerCache[targetAddr];
286
+ methodsMap[functionName] = (NativeMethodCallback) callback;
287
+ callbackManagerCache[targetAddr] = methodsMap;
288
+ }
289
+
290
+ NativeMethodCallback getCallbackMethod (jlong targetAddr, char *functionName) {
291
+ if (!callbackManagerCache.count (targetAddr)) {
292
+ NSLog (" getCallbackMethod error not register %s" , functionName);
293
+ return NULL ;
294
+ }
295
+ std::map<std::string, NativeMethodCallback> methodsMap = callbackManagerCache[targetAddr];
296
+ return methodsMap[functionName];
297
+ }
298
+
299
+ void registerNativeCallback (void *target, char * targetName, char *funName, void *callback) {
300
+ JNIEnv *curEnv;
301
+ bool bShouldDetach = false ;
302
+ auto error = gJvm ->GetEnv ((void **) &curEnv, JNI_VERSION_1_6);
303
+ if (error < 0 ) {
304
+ error = gJvm ->AttachCurrentThread (&curEnv, nullptr );
305
+ bShouldDetach = true ;
306
+ NSLog (" AttachCurrentThread : %d" , error);
307
+ }
308
+
309
+ jclass callbackManager = findClass (curEnv, " com/dartnative/dart_native/CallbackManager" );
310
+ jmethodID registerCallback = curEnv->GetStaticMethodID (callbackManager, " registerCallback" , " (JLjava/lang/String;)Ljava/lang/Object;" );
311
+ jlong targetAddr = (jlong)target;
312
+ jvalue *argValues = new jvalue[2 ];
313
+ argValues[0 ].j = targetAddr;
314
+ argValues[1 ].l = curEnv->NewStringUTF (targetName);
315
+ jobject callbackOJ = curEnv->NewGlobalRef (curEnv->CallStaticObjectMethodA (callbackManager, registerCallback, argValues));
316
+ callbackObjCache[target] = callbackOJ;
317
+ targetCache[targetAddr] = target;
318
+
319
+ registerCallbackManager (targetAddr, funName, callback);
320
+ curEnv->DeleteLocalRef (callbackManager);
321
+ free (argValues);
322
+ if (bShouldDetach) {
323
+ gJvm ->DetachCurrentThread ();
324
+ }
325
+ }
326
+
327
+ // Dart extensions
328
+ Dart_Port native_callback_send_port;
329
+
330
+ intptr_t InitDartApiDL (void *data, Dart_Port port) {
331
+ native_callback_send_port = port;
332
+ return Dart_InitializeApiDL (data);
333
+ }
334
+
335
+ static void RunFinalizer (void *isolate_callback_data,
336
+ Dart_WeakPersistentHandle handle,
337
+ void *peer) {
338
+ NSLog (" finalizer" );
339
+ release (peer);
340
+ }
341
+
342
+ void PassObjectToCUseDynamicLinking (Dart_Handle h, void *classPtr) {
343
+ if (Dart_IsError_DL (h)) {
344
+ return ;
345
+ }
346
+ NSLog (" retain" );
347
+ retain (classPtr);
348
+ intptr_t size = 8 ;
349
+ Dart_NewWeakPersistentHandle_DL (h, classPtr, size, RunFinalizer);
350
+ }
351
+
352
+ typedef std::function<void ()> Work;
353
+
354
+ void NotifyDart (Dart_Port send_port, const Work* work) {
355
+ const intptr_t work_addr = reinterpret_cast <intptr_t >(work);
356
+
357
+ Dart_CObject dart_object;
358
+ dart_object.type = Dart_CObject_kInt64;
359
+ dart_object.value .as_int64 = work_addr;
360
+
361
+ const bool result = Dart_PostCObject_DL (send_port, &dart_object);
362
+ if (!result) {
363
+ NSLog (" Native callback to Dart failed! Invalid port or isolate died" );
364
+ }
365
+ }
366
+
367
+ void ExecuteCallback (Work* work_ptr) {
368
+ const Work work = *work_ptr;
369
+ work ();
370
+ delete work_ptr;
371
+ }
372
+
373
+ JNIEXPORT void JNICALL Java_com_dartnative_dart_1native_CallbackInvocationHandler_hookCallback (JNIEnv *env,
374
+ jclass clazz,
375
+ jlong dartObject,
376
+ jstring fun_name,
377
+ jint arg_count,
378
+ jobjectArray arg_types,
379
+ jobjectArray args) {
380
+ jsize argTypeLength = env->GetArrayLength (arg_types);
381
+ char **argTypes = new char *[argTypeLength];
382
+ void **arguments = new void *[argTypeLength];
383
+ for (int i = 0 ; i < argTypeLength; ++i) {
384
+ jobject argType = env->GetObjectArrayElement (arg_types, i);
385
+ jobject argument = env->GetObjectArrayElement (args, i);
386
+
387
+ jstring argTypeString = (jstring) argType;
388
+ argTypes[i] = (char *) env->GetStringUTFChars (argTypeString, 0 );
389
+ env->DeleteLocalRef (argTypeString);
390
+ // todo optimization
391
+ if (strcmp (argTypes[i], " I" ) == 0 ) {
392
+ jclass cls = env->FindClass (" java/lang/Integer" );
393
+ if (env->IsInstanceOf (argument, cls) == JNI_TRUE) {
394
+ jmethodID integerToInt = env->GetMethodID (cls, " intValue" , " ()I" );
395
+ jint result = env->CallIntMethod (argument, integerToInt);
396
+ arguments[i] = (void *) result;
397
+ }
398
+ env->DeleteLocalRef (cls);
399
+ }
400
+ else if (strcmp (argTypes[i], " F" ) == 0 ) {
401
+ jclass cls = env->FindClass (" java/lang/Float" );
402
+ if (env->IsInstanceOf (argument, cls) == JNI_TRUE) {
403
+ jmethodID toJfloat = env->GetMethodID (cls, " floatValue" , " ()F" );
404
+ jfloat result = env->CallFloatMethod (argument, toJfloat);
405
+ float templeFloat = (float ) result;
406
+ memcpy (&arguments[i], &templeFloat, sizeof (float ));
407
+ }
408
+ env->DeleteLocalRef (cls);
409
+ }
410
+ else if (strcmp (argTypes[i], " D" ) == 0 ) {
411
+ jclass cls = env->FindClass (" java/lang/Double" );
412
+ if (env->IsInstanceOf (argument, cls) == JNI_TRUE) {
413
+ jmethodID toJfloat = env->GetMethodID (cls, " doubleValue" , " ()D" );
414
+ jdouble result = env->CallDoubleMethod (argument, toJfloat);
415
+ double templeDouble = (double ) result;
416
+ memcpy (&arguments[i], &templeDouble, sizeof (double ));
417
+ }
418
+ env->DeleteLocalRef (cls);
419
+ }
420
+ else if (strcmp (argTypes[i], " Ljava/lang/String;" ) == 0 ) {
421
+ jstring argString = (jstring) argument;
422
+ arguments[i] = (char *) env->GetStringUTFChars (argString, 0 );
423
+ env->DeleteLocalRef (argString);
424
+ }
425
+ }
426
+ char *funName = (char *) env->GetStringUTFChars (fun_name, 0 );
427
+ const Work work = [dartObject, argTypes, arguments, arg_count, funName]() {
428
+ NativeMethodCallback methodCallback = getCallbackMethod (dartObject, funName);
429
+ void *target = targetCache[dartObject];
430
+ if (methodCallback != NULL && target != nullptr ) {
431
+ methodCallback (target, funName, arguments, argTypes, arg_count);
432
+ }
433
+ };
434
+ const Work* work_ptr = new Work (work);
435
+ NotifyDart (native_callback_send_port, work_ptr);
436
+ }
437
+
251
438
}
252
439
0 commit comments