• 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/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