Flutter Engine
The Flutter Engine
service_isolate.cc
Go to the documentation of this file.
1// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
6
8#include "vm/dart_api_impl.h"
10#include "vm/dart_entry.h"
11#include "vm/isolate.h"
12#include "vm/lockers.h"
13#include "vm/message.h"
14#include "vm/message_handler.h"
15#include "vm/message_snapshot.h"
16#include "vm/native_arguments.h"
17#include "vm/native_entry.h"
18#include "vm/object.h"
19#include "vm/object_store.h"
20#include "vm/port.h"
21#include "vm/service.h"
22#include "vm/symbols.h"
23#include "vm/thread_pool.h"
24#include "vm/timeline.h"
25
26#if !defined(PRODUCT)
27
28namespace dart {
29
30#define Z (T->zone())
31
32DEFINE_FLAG(bool, trace_service, false, "Trace VM service requests.");
34 trace_service_pause_events,
35 false,
36 "Trace VM service isolate pause events.");
38 trace_service_verbose,
39 false,
40 "Provide extra service tracing information.");
41
42// These must be kept in sync with service/constants.dart
43#define VM_SERVICE_ISOLATE_EXIT_MESSAGE_ID 0
44#define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1
45#define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID 2
46
47#define VM_SERVICE_WEB_SERVER_CONTROL_MESSAGE_ID 3
48#define VM_SERVICE_SERVER_INFO_MESSAGE_ID 4
49
50#define VM_SERVICE_METHOD_CALL_FROM_NATIVE 5
51
53 Dart_Port port_id,
54 intptr_t code,
55 const char* name) {
56 Dart_CObject ccode;
58 ccode.value.as_int32 = code;
59
60 Dart_CObject port_int;
61 port_int.type = Dart_CObject_kInt64;
62 port_int.value.as_int64 = port_id;
63
64 Dart_CObject send_port;
65 send_port.type = Dart_CObject_kSendPort;
66 send_port.value.as_send_port.id = port_id;
67 send_port.value.as_send_port.origin_id = port_id;
68
69 Dart_CObject cname;
71 cname.value.as_string = const_cast<char*>(name);
72
74 values[0] = &ccode;
75 values[1] = &port_int;
76 values[2] = &send_port;
77 values[3] = &cname;
78
81 message.value.as_array.length = 4;
82 message.value.as_array.values = values;
83
86}
87
88static ArrayPtr MakeServerControlMessage(const SendPort& sp,
89 intptr_t code,
90 bool enable,
91 const Bool& silenceOutput) {
92 const Array& list = Array::Handle(Array::New(4));
93 ASSERT(!list.IsNull());
95 list.SetAt(1, sp);
96 list.SetAt(2, Bool::Get(enable));
97 list.SetAt(3, silenceOutput);
98 return list.ptr();
99}
100
103 nullptr;
104Monitor* ServiceIsolate::monitor_ = new Monitor();
106Isolate* ServiceIsolate::isolate_ = nullptr;
109char* ServiceIsolate::server_address_ = nullptr;
111
114 sp, VM_SERVICE_SERVER_INFO_MESSAGE_ID, false /* ignored */,
115 Bool::Handle() /* ignored */));
116 ASSERT(!message.IsNull());
117 PortMap::PostMessage(WriteMessage(/* same_group */ false, message, port_,
119}
120
122 bool enable,
123 const Bool& silenceOutput) {
125 sp, VM_SERVICE_WEB_SERVER_CONTROL_MESSAGE_ID, enable, silenceOutput));
126 ASSERT(!message.IsNull());
127 PortMap::PostMessage(WriteMessage(/* same_group */ false, message, port_,
129}
130
131void ServiceIsolate::SetServerAddress(const char* address) {
132 if (server_address_ != nullptr) {
133 free(server_address_);
134 server_address_ = nullptr;
135 }
136 if (address == nullptr) {
137 return;
138 }
140}
141
144 return isolate_ != nullptr;
145}
146
149 return (port_ != ILLEGAL_PORT) && (isolate_ != nullptr);
150}
151
154 return isolate->origin_id() == origin_;
155}
156
159 return port_;
160}
161
164 while (state_ == kStarting) {
165 ml.Wait();
166 }
167}
168
169bool ServiceIsolate::SendServiceRpc(uint8_t* request_json,
170 intptr_t request_json_length,
171 Dart_Port reply_port,
172 char** error) {
173 // Keep in sync with "sdk/lib/vmservice/vmservice.dart:_handleNativeRpcCall".
174 Dart_CObject opcode;
175 opcode.type = Dart_CObject_kInt32;
177
180 message.value.as_typed_data.type = Dart_TypedData_kUint8;
181 message.value.as_typed_data.length = request_json_length;
182 message.value.as_typed_data.values = request_json;
183
184 Dart_CObject send_port;
185 send_port.type = Dart_CObject_kSendPort;
186 send_port.value.as_send_port.id = reply_port;
188
189 Dart_CObject* request_array[] = {
190 &opcode,
191 &message,
192 &send_port,
193 };
194
195 Dart_CObject request;
196 request.type = Dart_CObject_kArray;
197 request.value.as_array.values = request_array;
198 request.value.as_array.length = ARRAY_SIZE(request_array);
200 Dart_Port service_port = ServiceIsolate::Port();
201 bool success = false;
202 if (service_port != ILLEGAL_PORT) {
203 success = Dart_PostCObject(service_port, &request);
204 if (!success && error != nullptr) {
205 *error = Utils::StrDup("Was unable to post message to service isolate.");
206 }
207 } else {
208 if (error != nullptr) {
209 if (startup_failure_reason_ != nullptr) {
210 *error = OS::SCreate(/*zone=*/nullptr,
211 "Service isolate failed to start up: %s.",
213 } else {
214 *error = Utils::StrDup("No service isolate port was found.");
215 }
216 }
217 }
218 return success;
219}
220
222 if (!IsRunning()) {
223 return false;
224 }
225 Thread* thread = Thread::Current();
226 Isolate* isolate = thread->isolate();
227 if (isolate->is_vm_isolate()) {
228 return false;
229 }
230
231 Dart_Port main_port = Dart_GetMainPortId();
232 if (FLAG_trace_service) {
234 " registered.\n",
235 isolate->name(), main_port);
236 }
237 bool result = SendServiceControlMessage(thread, main_port,
239 isolate->name());
240 isolate->set_is_service_registered(true);
241 return result;
242}
243
245 if (!IsRunning()) {
246 return false;
247 }
248 Thread* thread = Thread::Current();
249 Isolate* isolate = thread->isolate();
250 if (isolate->is_vm_isolate()) {
251 return false;
252 }
253
254 Dart_Port main_port = isolate->main_port();
255 if (FLAG_trace_service) {
257 " deregistered.\n",
258 isolate->name(), main_port);
259 }
260 isolate->set_is_service_registered(false);
261 return SendServiceControlMessage(thread, main_port,
263 isolate->name());
264}
265
267 if (!IsRunning()) {
268 return;
269 }
270 if (FLAG_trace_service) {
272 ": sending service exit message.\n");
273 }
274
278 Dart_CObject* values[1] = {&code};
279
282 message.value.as_array.length = 1;
283 message.value.as_array.values = values;
284
288}
289
292 port_ = port;
293}
294
297 isolate_ = isolate;
298 if (isolate_ != nullptr) {
299 ASSERT(isolate->is_service_isolate());
301 }
302}
303
306 ASSERT(I == T->isolate());
307 ASSERT(I != nullptr);
308 ASSERT(I->name() != nullptr);
309 if (!I->is_service_isolate()) {
310 // Not service isolate.
311 return;
312 }
313 if (Exists()) {
314 // Service isolate already exists.
315 return;
316 }
318}
319
325 isolate_ = nullptr;
326 ml.NotifyAll();
327}
328
333 ml.NotifyAll();
334}
335
342 ml.NotifyAll();
343}
344
346 public:
347 virtual void Run() {
348 ASSERT(Isolate::Current() == nullptr);
349#if defined(SUPPORT_TIMELINE)
350 TimelineBeginEndScope tbes(Timeline::GetVMStream(),
351 "ServiceIsolateStartup");
352#endif // SUPPORT_TIMELINE
353 char* error = nullptr;
354 Isolate* isolate = nullptr;
355
356 const auto create_group_callback = ServiceIsolate::create_group_callback();
357 ASSERT(create_group_callback != nullptr);
358
359 Dart_IsolateFlags api_flags;
360 Isolate::FlagsInitialize(&api_flags);
361 api_flags.is_system_isolate = true;
362 api_flags.is_service_isolate = true;
363 isolate = reinterpret_cast<Isolate*>(
364 create_group_callback(ServiceIsolate::kName, ServiceIsolate::kName,
365 nullptr, nullptr, &api_flags, nullptr, &error));
366 if (isolate == nullptr) {
367 if (FLAG_trace_service) {
369 ": Isolate creation error: %s\n",
370 error);
371 }
372
373 char* formatted_error = OS::SCreate(
374 /*zone=*/nullptr, "Invoking the 'create_group' failed with: '%s'",
375 error);
376
377 free(error);
378 error = nullptr;
379 ServiceIsolate::InitializingFailed(formatted_error);
380 return;
381 }
382
383 bool got_unwind;
384 {
385 ASSERT(Isolate::Current() == nullptr);
386 StartIsolateScope start_scope(isolate);
387 got_unwind = RunMain(isolate);
388 }
389
390 // FinishedInitializing should be called irrespective of whether
391 // running main caused an error or not. Otherwise, other isolates
392 // waiting for service isolate to come up will deadlock.
394
395 if (got_unwind) {
396 ShutdownIsolate(reinterpret_cast<uword>(isolate));
397 return;
398 }
399
400 isolate->message_handler()->Run(isolate->group()->thread_pool(), nullptr,
402 reinterpret_cast<uword>(isolate));
403 }
404
405 protected:
406 static void ShutdownIsolate(uword parameter) {
407 if (FLAG_trace_service) {
408 OS::PrintErr("vm-service: ShutdownIsolate\n");
409 }
410 Dart_EnterIsolate(reinterpret_cast<Dart_Isolate>(parameter));
411 {
412 auto T = Thread::Current();
413 TransitionNativeToVM transition(T);
414 StackZone zone(T);
415 HandleScope handle_scope(T);
416
417 auto I = T->isolate();
418 ASSERT(I->is_service_isolate());
419
420 // Print the error if there is one. This may execute dart code to
421 // print the exception object, so we need to use a StartIsolateScope.
423 error = T->sticky_error();
424 if (!error.IsNull() && !error.IsUnwindError()) {
426 error.ToErrorCString());
427 }
428 error = I->sticky_error();
429 if (!error.IsNull() && !error.IsUnwindError()) {
431 error.ToErrorCString());
432 }
433 }
435 if (FLAG_trace_service) {
437 }
439 }
440
443 ASSERT(I == T->isolate());
444 StackZone zone(T);
445 // Invoke main which will set up the service port.
446 const Library& root_library =
447 Library::Handle(Z, I->group()->object_store()->root_library());
448 if (root_library.IsNull()) {
449 if (FLAG_trace_service) {
451 ": Embedder did not install a script.");
452 }
453 // Service isolate is not supported by embedder.
454 return false;
455 }
456 ASSERT(!root_library.IsNull());
457 const String& entry_name = String::Handle(Z, String::New("main"));
458 ASSERT(!entry_name.IsNull());
459 const Function& entry = Function::Handle(
460 Z, root_library.LookupFunctionAllowPrivate(entry_name));
461 if (entry.IsNull()) {
462 // Service isolate is not supported by embedder.
463 if (FLAG_trace_service) {
465 ": Embedder did not provide a main function.");
466 }
467 return false;
468 }
469 ASSERT(!entry.IsNull());
471 Z, DartEntry::InvokeFunction(entry, Object::empty_array()));
472 if (result.IsError()) {
473 // Service isolate did not initialize properly.
474 if (FLAG_trace_service) {
475 const Error& error = Error::Cast(result);
477 ": Calling main resulted in an error: %s",
478 error.ToErrorCString());
479 }
480 if (result.IsUnwindError()) {
481 return true;
482 }
483 return false;
484 }
485 return false;
486 }
487};
488
490 {
494 ml.NotifyAll();
495 }
496 // Grab the isolate create callback here to avoid race conditions with tests
497 // that change this after Dart_Initialize returns.
499 if (create_group_callback_ == nullptr) {
501 Utils::StrDup("The 'create_group' callback was not provided"));
502 return;
503 }
504 bool task_started = Dart::thread_pool()->Run<RunServiceTask>();
505 ASSERT(task_started);
506}
507
508void ServiceIsolate::KillServiceIsolate() {
509 {
511 if (state_ == kStopped) {
512 return;
513 }
516 ml.NotifyAll();
517 }
519 {
520 MonitorLocker ml(monitor_);
521 while (state_ == kStopping) {
522 ml.Wait();
523 }
525 }
526}
527
529 {
531 while (state_ == kStarting) {
532 ml.Wait();
533 }
534 }
535
536 if (IsRunning()) {
537 {
541 ml.NotifyAll();
542 }
544 {
546 while (state_ == kStopping) {
547 ml.Wait();
548 }
550 }
551 } else {
552 if (isolate_ != nullptr) {
553 // TODO(johnmccutchan,turnidge) When it is possible to properly create
554 // the VMService object and set up its shutdown handler in the service
555 // isolate's main() function, this case will no longer be possible and
556 // can be removed.
557 KillServiceIsolate();
558 }
559 }
560 if (server_address_ != nullptr) {
561 free(server_address_);
562 server_address_ = nullptr;
563 }
564
565 if (startup_failure_reason_ != nullptr) {
567 startup_failure_reason_ = nullptr;
568 }
569}
570
572 Thread* thread = Thread::Current();
573 const Library& vmservice_library =
574 Library::Handle(Library::LookupLibrary(thread, Symbols::DartVMService()));
575 ASSERT(!vmservice_library.IsNull());
576 const String& boot_function_name = String::Handle(String::New("boot"));
577 const Function& boot_function = Function::Handle(
578 vmservice_library.LookupFunctionAllowPrivate(boot_function_name));
579 ASSERT(!boot_function.IsNull());
581 DartEntry::InvokeFunction(boot_function, Object::empty_array()));
582 ASSERT(!result.IsNull());
583 if (result.IsUnwindError() || result.IsUnhandledException()) {
585 }
587 if (result.IsReceivePort()) {
588 port = ReceivePort::Cast(result).Id();
589 }
592}
593
595 const GrowableArray<Dart_Port>& isolate_ports,
596 const GrowableArray<const String*>& isolate_names) {
597 auto thread = Thread::Current();
598 auto zone = thread->zone();
599
600 ASSERT(thread->isolate()->is_service_isolate());
601
602 // Obtain "_registerIsolate" function to call.
603 const String& library_url = Symbols::DartVMService();
604 ASSERT(!library_url.IsNull());
605 const Library& library =
606 Library::Handle(zone, Library::LookupLibrary(thread, library_url));
607 ASSERT(!library.IsNull());
608 const String& function_name =
609 String::Handle(zone, String::New("_registerIsolate"));
610 ASSERT(!function_name.IsNull());
611 const Function& register_function_ =
613 ASSERT(!register_function_.IsNull());
614
615 Integer& port_int = Integer::Handle(zone);
616 SendPort& send_port = SendPort::Handle(zone);
617 Array& args = Array::Handle(zone, Array::New(3));
619
620 ASSERT(isolate_ports.length() == isolate_names.length());
621 for (intptr_t i = 0; i < isolate_ports.length(); ++i) {
622 const Dart_Port port_id = isolate_ports[i];
623 const String& name = *isolate_names[i];
624
625 port_int = Integer::New(port_id);
626 send_port = SendPort::New(port_id);
627 args.SetAt(0, port_int);
628 args.SetAt(1, send_port);
629 args.SetAt(2, name);
630 result = DartEntry::InvokeFunction(register_function_, args);
631 if (FLAG_trace_service) {
632 OS::PrintErr("vm-service: Isolate %s %" Pd64 " registered.\n",
633 name.ToCString(), port_id);
634 }
635 ASSERT(!result.IsError());
636 }
637}
638
640
641} // namespace dart
642
643#endif // !defined(PRODUCT)
static ArrayPtr New(intptr_t len, Heap::Space space=Heap::kNew)
Definition: object.h:10959
void SetAt(intptr_t index, const Object &value) const
Definition: object.h:10880
intptr_t length() const
static const Bool & Get(bool value)
Definition: object.h:10801
static ObjectPtr InvokeFunction(const Function &function, const Array &arguments)
Definition: dart_entry.cc:31
static ThreadPool * thread_pool()
Definition: dart.h:73
static DART_NORETURN void PropagateError(const Error &error)
Definition: exceptions.cc:1003
static IntegerPtr New(const String &str, Heap::Space space=Heap::kNew)
Definition: object.cc:22984
MutatorThreadPool * thread_pool()
Definition: isolate.h:769
@ kInternalKillMsg
Definition: isolate.h:973
static Isolate * Current()
Definition: isolate.h:986
static void KillIfExists(Isolate *isolate, LibMsgId msg_id)
Definition: isolate.cc:3706
MessageHandler * message_handler() const
Definition: isolate.cc:2416
bool is_vm_isolate() const
Definition: isolate.h:1380
static void FlagsInitialize(Dart_IsolateFlags *api_flags)
Definition: isolate.cc:1648
IsolateGroup * group() const
Definition: isolate.h:1037
static Dart_IsolateGroupCreateCallback CreateGroupCallback()
Definition: isolate.h:1203
void set_is_service_registered(bool value)
Definition: isolate.h:1388
Dart_Port origin_id()
Definition: isolate.cc:1990
Dart_Port main_port() const
Definition: isolate.h:1048
const char * name() const
Definition: isolate.h:1043
FunctionPtr LookupFunctionAllowPrivate(const String &name) const
Definition: object.cc:14084
static LibraryPtr LookupLibrary(Thread *thread, const String &url)
Definition: object.cc:14599
bool Run(ThreadPool *pool, StartCallback start_callback, EndCallback end_callback, CallbackData data)
@ kNormalPriority
Definition: message.h:28
Monitor::WaitResult Wait(int64_t millis=Monitor::kNoTimeout)
Definition: lockers.h:172
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static char * SCreate(Zone *zone, const char *format,...) PRINTF_ATTRIBUTE(2
ObjectPtr ptr() const
Definition: object.h:332
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
static bool PostMessage(std::unique_ptr< Message > message, bool before_events=false)
Definition: port.cc:152
static void ShutdownIsolate(uword parameter)
bool RunMain(Isolate *I)
static SendPortPtr New(Dart_Port id, Heap::Space space=Heap::kNew)
Definition: object.cc:25812
static Dart_Port origin_
static void FinishedExiting()
static void ControlWebServer(const SendPort &sp, bool enable, const Bool &silenceOutput)
static void SetServiceIsolate(Isolate *isolate)
static void RequestServerInfo(const SendPort &sp)
static bool SendIsolateStartupMessage()
static void VisitObjectPointers(ObjectPointerVisitor *visitor)
static Monitor * monitor_
static const char * kName
static bool SendServiceControlMessage(Thread *thread, Dart_Port port_id, intptr_t code, const char *name)
static void FinishedInitializing()
static bool SendIsolateShutdownMessage()
static char * server_address_
static Dart_IsolateGroupCreateCallback create_group_callback()
static bool IsServiceIsolateDescendant(Isolate *isolate)
static void RegisterRunningIsolates(const GrowableArray< Dart_Port > &isolate_ports, const GrowableArray< const String * > &isolate_names)
static Dart_Port Port()
static Dart_Port port_
static Dart_IsolateGroupCreateCallback create_group_callback_
static void WaitForServiceIsolateStartup()
static bool SendServiceRpc(uint8_t *request_json, intptr_t request_json_length, Dart_Port reply_port, char **error)
static void SetServerAddress(const char *address)
static void InitializingFailed(char *error)
static void SetServicePort(Dart_Port port)
static Isolate * isolate_
static void MaybeMakeServiceIsolate(Isolate *isolate)
static void SendServiceExitMessage()
static void BootVmServiceLibrary()
static char * startup_failure_reason_
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition: object.cc:23698
bool Run(Args &&... args)
Definition: thread_pool.h:45
Zone * zone() const
Definition: thread_state.h:37
static Thread * Current()
Definition: thread.h:362
Isolate * isolate() const
Definition: thread.h:534
static char * StrDup(const char *s)
Dart_Isolate(* Dart_IsolateGroupCreateCallback)(const char *script_uri, const char *main, const char *package_root, const char *package_config, Dart_IsolateFlags *flags, void *isolate_data, char **error)
Definition: dart_api.h:654
#define ILLEGAL_PORT
Definition: dart_api.h:1535
int64_t Dart_Port
Definition: dart_api.h:1525
struct _Dart_Isolate * Dart_Isolate
Definition: dart_api.h:88
@ Dart_TypedData_kUint8
Definition: dart_api.h:2615
#define DART_VM_SERVICE_ISOLATE_NAME
Definition: dart_api.h:3888
@ Dart_CObject_kInt64
@ Dart_CObject_kTypedData
@ Dart_CObject_kSendPort
@ Dart_CObject_kString
@ Dart_CObject_kArray
@ Dart_CObject_kInt32
#define ASSERT(E)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
Win32Message message
Definition: dart_vm.cc:33
const char *const name
DART_EXPORT Dart_Port Dart_GetMainPortId()
DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate)
uintptr_t uword
Definition: globals.h:501
static ArrayPtr MakeServerControlMessage(const SendPort &sp, intptr_t code, bool enable, const Bool &silenceOutput)
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
std::unique_ptr< Message > WriteMessage(bool same_group, const Object &obj, Dart_Port dest_port, Message::Priority priority)
std::unique_ptr< Message > WriteApiMessage(Zone *zone, Dart_CObject *obj, Dart_Port dest_port, Message::Priority priority)
DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject *message)
const char *const function_name
DART_EXPORT void Dart_ShutdownIsolate()
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service port
Definition: switches.h:87
#define Pd64
Definition: globals.h:416
#define T
Definition: precompiler.cc:65
bool is_service_isolate
Definition: dart_api.h:593
bool is_system_isolate
Definition: dart_api.h:592
Definition: SkMD5.cpp:134
struct _Dart_CObject::@86::@87 as_send_port
union _Dart_CObject::@86 value
Dart_CObject_Type type
const char * as_string
struct _Dart_CObject::@86::@89 as_array
struct _Dart_CObject ** values
Dart_Port origin_id
#define VM_SERVICE_WEB_SERVER_CONTROL_MESSAGE_ID
#define VM_SERVICE_ISOLATE_EXIT_MESSAGE_ID
#define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID
#define Z
#define VM_SERVICE_METHOD_CALL_FROM_NATIVE
#define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID
#define VM_SERVICE_SERVER_INFO_MESSAGE_ID
#define ARRAY_SIZE(array)
Definition: globals.h:72