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 "third_party/tonic/logging/dart_error.h"
12#include "tonic/converter/dart_converter.h"
13
14namespace flutter {
15namespace testing {
16
17TestDartNativeResolver::TestDartNativeResolver() = default;
18
19TestDartNativeResolver::~TestDartNativeResolver() = default;
20
21void TestDartNativeResolver::AddNativeCallback(std::string name,
22 Dart_NativeFunction callback) {
23 native_callbacks_[name] = callback;
24}
25
26Dart_NativeFunction TestDartNativeResolver::ResolveCallback(
27 std::string name) const {
28 auto found = native_callbacks_.find(name);
29 if (found == native_callbacks_.end()) {
30 return nullptr;
31 }
32
33 return found->second;
34}
35
36static std::mutex gIsolateResolversMutex;
37static std::map<Dart_Isolate, std::weak_ptr<TestDartNativeResolver>>
38 gIsolateResolvers;
39
40Dart_NativeFunction TestDartNativeResolver::DartNativeEntryResolverCallback(
41 Dart_Handle dart_name,
42 int num_of_arguments,
43 bool* auto_setup_scope) {
44 auto name = tonic::StdStringFromDart(dart_name);
45
46 std::scoped_lock lock(gIsolateResolversMutex);
47 auto found = gIsolateResolvers.find(Dart_CurrentIsolate());
48 if (found == gIsolateResolvers.end()) {
49 FML_LOG(ERROR) << "Could not resolve native method for :" << name;
50 return nullptr;
51 }
52
53 if (auto resolver = found->second.lock()) {
54 return resolver->ResolveCallback(std::move(name));
55 } else {
56 gIsolateResolvers.erase(found);
57 }
58
59 FML_LOG(ERROR) << "Could not resolve native method for :" << name;
60 return nullptr;
61}
62
63static const uint8_t* DartNativeEntrySymbolCallback(
64 Dart_NativeFunction function) {
65 return reinterpret_cast<const uint8_t*>("¯\\_(ツ)_/¯");
66}
67
68void TestDartNativeResolver::SetNativeResolverForIsolate() {
69 FML_CHECK(!Dart_IsError(Dart_RootLibrary()));
70 auto result = Dart_SetNativeResolver(Dart_RootLibrary(),
71 DartNativeEntryResolverCallback,
72 DartNativeEntrySymbolCallback);
73 FML_CHECK(!tonic::LogIfError(result))
74 << "Could not set native resolver in test.";
75
76 std::scoped_lock lock(gIsolateResolversMutex);
77 gIsolateResolvers[Dart_CurrentIsolate()] = shared_from_this();
78
79 std::vector<Dart_Isolate> isolates_with_dead_resolvers;
80 for (const auto& entry : gIsolateResolvers) {
81 if (!entry.second.lock()) {
82 isolates_with_dead_resolvers.push_back(entry.first);
83 }
84 }
85
86 for (const auto& dead_isolate : isolates_with_dead_resolvers) {
87 gIsolateResolvers.erase(dead_isolate);
88 }
89}
90
91} // namespace testing
92} // namespace flutter
93