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