• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/testing/test_dart_native_resolver.h"
6 
7 #include <mutex>
8 #include <vector>
9 
10 #include "flutter/fml/logging.h"
11 #include "flutter/fml/synchronization/thread_annotations.h"
12 #include "third_party/tonic/logging/dart_error.h"
13 #include "tonic/converter/dart_converter.h"
14 
15 namespace flutter {
16 namespace testing {
17 
18 TestDartNativeResolver::TestDartNativeResolver() = default;
19 
20 TestDartNativeResolver::~TestDartNativeResolver() = default;
21 
AddNativeCallback(std::string name,Dart_NativeFunction callback)22 void TestDartNativeResolver::AddNativeCallback(std::string name,
23                                                Dart_NativeFunction callback) {
24   native_callbacks_[name] = callback;
25 }
26 
ResolveCallback(std::string name) const27 Dart_NativeFunction TestDartNativeResolver::ResolveCallback(
28     std::string name) const {
29   auto found = native_callbacks_.find(name);
30   if (found == native_callbacks_.end()) {
31     return nullptr;
32   }
33 
34   return found->second;
35 }
36 
37 static std::mutex gIsolateResolversMutex;
38 static std::map<Dart_Isolate, std::weak_ptr<TestDartNativeResolver>>
39     gIsolateResolvers FML_GUARDED_BY(gIsolateResolversMutex);
40 
DartNativeEntryResolverCallback(Dart_Handle dart_name,int num_of_arguments,bool * auto_setup_scope)41 Dart_NativeFunction TestDartNativeResolver::DartNativeEntryResolverCallback(
42     Dart_Handle dart_name,
43     int num_of_arguments,
44     bool* auto_setup_scope) {
45   auto name = tonic::StdStringFromDart(dart_name);
46 
47   std::scoped_lock lock(gIsolateResolversMutex);
48   auto found = gIsolateResolvers.find(Dart_CurrentIsolate());
49   if (found == gIsolateResolvers.end()) {
50     FML_LOG(ERROR) << "Could not resolve native method for :" << name;
51     return nullptr;
52   }
53 
54   if (auto resolver = found->second.lock()) {
55     return resolver->ResolveCallback(std::move(name));
56   } else {
57     gIsolateResolvers.erase(found);
58   }
59 
60   FML_LOG(ERROR) << "Could not resolve native method for :" << name;
61   return nullptr;
62 }
63 
DartNativeEntrySymbolCallback(Dart_NativeFunction function)64 static const uint8_t* DartNativeEntrySymbolCallback(
65     Dart_NativeFunction function) {
66   return reinterpret_cast<const uint8_t*>("¯\\_(ツ)_/¯");
67 }
68 
SetNativeResolverForIsolate()69 void TestDartNativeResolver::SetNativeResolverForIsolate() {
70   FML_CHECK(!Dart_IsError(Dart_RootLibrary()));
71   auto result = Dart_SetNativeResolver(Dart_RootLibrary(),
72                                        DartNativeEntryResolverCallback,
73                                        DartNativeEntrySymbolCallback);
74   FML_CHECK(!tonic::LogIfError(result))
75       << "Could not set native resolver in test.";
76 
77   std::scoped_lock lock(gIsolateResolversMutex);
78   gIsolateResolvers[Dart_CurrentIsolate()] = shared_from_this();
79 
80   std::vector<Dart_Isolate> isolates_with_dead_resolvers;
81   for (const auto& entry : gIsolateResolvers) {
82     if (!entry.second.lock()) {
83       isolates_with_dead_resolvers.push_back(entry.first);
84     }
85   }
86 
87   for (const auto& dead_isolate : isolates_with_dead_resolvers) {
88     gIsolateResolvers.erase(dead_isolate);
89   }
90 }
91 
92 }  // namespace testing
93 }  // namespace flutter
94