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/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 | |
31 | namespace flutter { |
32 | namespace { |
33 | |
34 | static Dart_LibraryTagHandler g_embedder_tag_handler; |
35 | static tonic::DartLibraryNatives* g_natives; |
36 | static std::string g_observatory_uri; |
37 | |
38 | Dart_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 | |
45 | const uint8_t* GetSymbol(Dart_NativeFunction native_function) { |
46 | FML_CHECK(g_natives); |
47 | return g_natives->GetSymbol(native_function); |
48 | } |
49 | |
50 | } // namespace |
51 | |
52 | std::mutex DartServiceIsolate::callbacks_mutex_; |
53 | |
54 | std::set<std::unique_ptr<DartServiceIsolate::ObservatoryServerStateCallback>> |
55 | DartServiceIsolate::callbacks_; |
56 | |
57 | void DartServiceIsolate::NotifyServerState(Dart_NativeArguments args) { |
58 | Dart_Handle exception = nullptr; |
59 | std::string uri = |
60 | tonic::DartConverter<std::string>::FromArguments(args, 0, exception); |
61 | |
62 | if (exception) { |
63 | return; |
64 | } |
65 | |
66 | g_observatory_uri = uri; |
67 | |
68 | // Collect callbacks to fire in a separate collection and invoke them outside |
69 | // the lock. |
70 | std::vector<DartServiceIsolate::ObservatoryServerStateCallback> |
71 | callbacks_to_fire; |
72 | { |
73 | std::scoped_lock lock(callbacks_mutex_); |
74 | for (auto& callback : callbacks_) { |
75 | callbacks_to_fire.push_back(*callback.get()); |
76 | } |
77 | } |
78 | |
79 | for (const auto& callback_to_fire : callbacks_to_fire) { |
80 | callback_to_fire(uri); |
81 | } |
82 | } |
83 | |
84 | DartServiceIsolate::CallbackHandle DartServiceIsolate::AddServerStatusCallback( |
85 | const DartServiceIsolate::ObservatoryServerStateCallback& callback) { |
86 | if (!callback) { |
87 | return 0; |
88 | } |
89 | |
90 | auto callback_pointer = |
91 | std::make_unique<DartServiceIsolate::ObservatoryServerStateCallback>( |
92 | callback); |
93 | |
94 | auto handle = reinterpret_cast<CallbackHandle>(callback_pointer.get()); |
95 | |
96 | { |
97 | std::scoped_lock lock(callbacks_mutex_); |
98 | callbacks_.insert(std::move(callback_pointer)); |
99 | } |
100 | |
101 | if (!g_observatory_uri.empty()) { |
102 | callback(g_observatory_uri); |
103 | } |
104 | |
105 | return handle; |
106 | } |
107 | |
108 | bool DartServiceIsolate::RemoveServerStatusCallback( |
109 | CallbackHandle callback_handle) { |
110 | std::scoped_lock lock(callbacks_mutex_); |
111 | auto found = std::find_if( |
112 | callbacks_.begin(), callbacks_.end(), |
113 | [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(found); |
122 | return true; |
123 | } |
124 | |
125 | void DartServiceIsolate::Shutdown(Dart_NativeArguments args) { |
126 | // NO-OP. |
127 | } |
128 | |
129 | bool DartServiceIsolate::Startup(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({ |
147 | {"VMServiceIO_NotifyServerState" , NotifyServerState, 1, true}, |
148 | {"VMServiceIO_Shutdown" , Shutdown, 0, true}, |
149 | }); |
150 | } |
151 | |
152 | Dart_Handle uri = Dart_NewStringFromCString("dart:vmservice_io" ); |
153 | Dart_Handle library = Dart_LookupLibrary(uri); |
154 | SHUTDOWN_ON_ERROR(library); |
155 | Dart_Handle result = Dart_SetRootLibrary(library); |
156 | SHUTDOWN_ON_ERROR(result); |
157 | result = Dart_SetNativeResolver(library, GetNativeFunction, GetSymbol); |
158 | SHUTDOWN_ON_ERROR(result); |
159 | |
160 | // Make runnable. |
161 | Dart_ExitScope(); |
162 | Dart_ExitIsolate(); |
163 | *error = Dart_IsolateMakeRunnable(isolate); |
164 | if (*error) { |
165 | Dart_EnterIsolate(isolate); |
166 | Dart_ShutdownIsolate(); |
167 | return false; |
168 | } |
169 | Dart_EnterIsolate(isolate); |
170 | Dart_EnterScope(); |
171 | |
172 | library = Dart_RootLibrary(); |
173 | SHUTDOWN_ON_ERROR(library); |
174 | |
175 | // Set the HTTP server's ip. |
176 | result = Dart_SetField(library, Dart_NewStringFromCString("_ip" ), |
177 | Dart_NewStringFromCString(server_ip.c_str())); |
178 | SHUTDOWN_ON_ERROR(result); |
179 | // If we have a port specified, start the server immediately. |
180 | bool auto_start = server_port >= 0; |
181 | if (server_port < 0) { |
182 | // Adjust server_port to port 0 which will result in the first available |
183 | // port when the HTTP server is started. |
184 | server_port = 0; |
185 | } |
186 | // Set the HTTP's servers port. |
187 | result = Dart_SetField(library, Dart_NewStringFromCString("_port" ), |
188 | Dart_NewInteger(server_port)); |
189 | SHUTDOWN_ON_ERROR(result); |
190 | result = Dart_SetField(library, Dart_NewStringFromCString("_autoStart" ), |
191 | Dart_NewBoolean(auto_start)); |
192 | SHUTDOWN_ON_ERROR(result); |
193 | result = |
194 | Dart_SetField(library, Dart_NewStringFromCString("_originCheckDisabled" ), |
195 | Dart_NewBoolean(disable_origin_check)); |
196 | SHUTDOWN_ON_ERROR(result); |
197 | result = |
198 | Dart_SetField(library, Dart_NewStringFromCString("_authCodesDisabled" ), |
199 | Dart_NewBoolean(disable_service_auth_codes)); |
200 | SHUTDOWN_ON_ERROR(result); |
201 | result = Dart_SetField( |
202 | library, Dart_NewStringFromCString("_enableServicePortFallback" ), |
203 | Dart_NewBoolean(enable_service_port_fallback)); |
204 | SHUTDOWN_ON_ERROR(result); |
205 | return true; |
206 | } |
207 | |
208 | } // namespace flutter |
209 | |