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/runtime/dart_service_isolate.h"
6
7#include <algorithm>
8#include <cstring>
9
10#include "flutter/fml/logging.h"
11#include "flutter/fml/posix_wrappers.h"
12#include "flutter/runtime/embedder_resources.h"
13#include "third_party/dart/runtime/include/dart_api.h"
14#include "third_party/tonic/converter/dart_converter.h"
15#include "third_party/tonic/dart_library_natives.h"
16#include "third_party/tonic/logging/dart_error.h"
17
18#define RETURN_ERROR_HANDLE(handle) \
19 if (Dart_IsError(handle)) { \
20 return handle; \
21 }
22
23#define SHUTDOWN_ON_ERROR(handle) \
24 if (Dart_IsError(handle)) { \
25 *error = fml::strdup(Dart_GetError(handle)); \
26 Dart_ExitScope(); \
27 Dart_ShutdownIsolate(); \
28 return false; \
29 }
30
31namespace flutter {
32namespace {
33
34static Dart_LibraryTagHandler g_embedder_tag_handler;
35static tonic::DartLibraryNatives* g_natives;
36static std::string g_vm_service_uri;
37
38Dart_NativeFunction GetNativeFunction(Dart_Handle name,
39 int argument_count,
40 bool* auto_setup_scope) {
41 FML_CHECK(g_natives);
42 return g_natives->GetNativeFunction(name, argument_count, auto_setup_scope);
43}
44
45const uint8_t* GetSymbol(Dart_NativeFunction native_function) {
46 FML_CHECK(g_natives);
47 return g_natives->GetSymbol(native_function);
48}
49
50} // namespace
51
52std::mutex DartServiceIsolate::callbacks_mutex_;
53
54std::set<std::unique_ptr<DartServiceIsolate::DartVMServiceServerStateCallback>>
55 DartServiceIsolate::callbacks_;
56
57void DartServiceIsolate::NotifyServerState(Dart_NativeArguments args) {
58 Dart_Handle exception = nullptr;
59 std::string uri =
60 tonic::DartConverter<std::string>::FromArguments(args, index: 0, exception);
61
62 if (exception) {
63 return;
64 }
65
66 g_vm_service_uri = uri;
67
68 // Collect callbacks to fire in a separate collection and invoke them outside
69 // the lock.
70 std::vector<DartServiceIsolate::DartVMServiceServerStateCallback>
71 callbacks_to_fire;
72 {
73 std::scoped_lock lock(callbacks_mutex_);
74 for (auto& callback : callbacks_) {
75 callbacks_to_fire.push_back(x: *callback.get());
76 }
77 }
78
79 for (const auto& callback_to_fire : callbacks_to_fire) {
80 callback_to_fire(uri);
81 }
82}
83
84DartServiceIsolate::CallbackHandle DartServiceIsolate::AddServerStatusCallback(
85 const DartServiceIsolate::DartVMServiceServerStateCallback& callback) {
86 if (!callback) {
87 return 0;
88 }
89
90 auto callback_pointer =
91 std::make_unique<DartServiceIsolate::DartVMServiceServerStateCallback>(
92 args: callback);
93
94 auto handle = reinterpret_cast<CallbackHandle>(callback_pointer.get());
95
96 {
97 std::scoped_lock lock(callbacks_mutex_);
98 callbacks_.insert(v: std::move(callback_pointer));
99 }
100
101 if (!g_vm_service_uri.empty()) {
102 callback(g_vm_service_uri);
103 }
104
105 return handle;
106}
107
108bool DartServiceIsolate::RemoveServerStatusCallback(
109 CallbackHandle callback_handle) {
110 std::scoped_lock lock(callbacks_mutex_);
111 auto found = std::find_if(
112 first: callbacks_.begin(), last: callbacks_.end(),
113 pred: [callback_handle](const auto& item) {
114 return reinterpret_cast<CallbackHandle>(item.get()) == callback_handle;
115 });
116
117 if (found == callbacks_.end()) {
118 return false;
119 }
120
121 callbacks_.erase(p: found);
122 return true;
123}
124
125void DartServiceIsolate::Shutdown(Dart_NativeArguments args) {
126 // NO-OP.
127}
128
129bool DartServiceIsolate::Startup(const std::string& server_ip,
130 intptr_t server_port,
131 Dart_LibraryTagHandler embedder_tag_handler,
132 bool disable_origin_check,
133 bool disable_service_auth_codes,
134 bool enable_service_port_fallback,
135 char** error) {
136 Dart_Isolate isolate = Dart_CurrentIsolate();
137 FML_CHECK(isolate);
138
139 // Remember the embedder's library tag handler.
140 g_embedder_tag_handler = embedder_tag_handler;
141 FML_CHECK(g_embedder_tag_handler);
142
143 // Setup native entries.
144 if (!g_natives) {
145 g_natives = new tonic::DartLibraryNatives();
146 g_natives->Register(entries: {
147 {.symbol: "VMServiceIO_NotifyServerState", .native_function: NotifyServerState, .argument_count: 1, .auto_setup_scope: true},
148 {.symbol: "VMServiceIO_Shutdown", .native_function: Shutdown, .argument_count: 0, .auto_setup_scope: true},
149 });
150 }
151
152 Dart_Handle uri = Dart_NewStringFromCString(str: "dart:vmservice_io");
153 Dart_Handle library = Dart_LookupLibrary(url: uri);
154 SHUTDOWN_ON_ERROR(library);
155 Dart_Handle result = Dart_SetRootLibrary(library);
156 SHUTDOWN_ON_ERROR(result);
157 result = Dart_SetNativeResolver(library, resolver: GetNativeFunction, symbol: GetSymbol);
158 SHUTDOWN_ON_ERROR(result);
159
160 library = Dart_RootLibrary();
161 SHUTDOWN_ON_ERROR(library);
162
163 // Set the HTTP server's ip.
164 result = Dart_SetField(container: library, name: Dart_NewStringFromCString(str: "_ip"),
165 value: Dart_NewStringFromCString(str: server_ip.c_str()));
166 SHUTDOWN_ON_ERROR(result);
167 // If we have a port specified, start the server immediately.
168 bool auto_start = server_port >= 0;
169 if (server_port < 0) {
170 // Adjust server_port to port 0 which will result in the first available
171 // port when the HTTP server is started.
172 server_port = 0;
173 }
174 // Set the HTTP's servers port.
175 result = Dart_SetField(container: library, name: Dart_NewStringFromCString(str: "_port"),
176 value: Dart_NewInteger(value: server_port));
177 SHUTDOWN_ON_ERROR(result);
178 result = Dart_SetField(container: library, name: Dart_NewStringFromCString(str: "_autoStart"),
179 value: Dart_NewBoolean(value: auto_start));
180 SHUTDOWN_ON_ERROR(result);
181 result =
182 Dart_SetField(container: library, name: Dart_NewStringFromCString(str: "_originCheckDisabled"),
183 value: Dart_NewBoolean(value: disable_origin_check));
184 SHUTDOWN_ON_ERROR(result);
185 result =
186 Dart_SetField(container: library, name: Dart_NewStringFromCString(str: "_authCodesDisabled"),
187 value: Dart_NewBoolean(value: disable_service_auth_codes));
188 SHUTDOWN_ON_ERROR(result);
189 result = Dart_SetField(
190 container: library, name: Dart_NewStringFromCString(str: "_enableServicePortFallback"),
191 value: Dart_NewBoolean(value: enable_service_port_fallback));
192 SHUTDOWN_ON_ERROR(result);
193
194 // Make runnable.
195 Dart_ExitScope();
196 Dart_ExitIsolate();
197 *error = Dart_IsolateMakeRunnable(isolate);
198 if (*error) {
199 Dart_EnterIsolate(isolate);
200 Dart_ShutdownIsolate();
201 return false;
202 }
203 Dart_EnterIsolate(isolate);
204 Dart_EnterScope();
205
206 return true;
207}
208
209} // namespace flutter
210

source code of flutter_engine/flutter/runtime/dart_service_isolate.cc