Flutter Engine
 
Loading...
Searching...
No Matches
dart_component_controller.cc
Go to the documentation of this file.
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
6
7#include <fcntl.h>
8#include <lib/async-loop/loop.h>
9#include <lib/async/cpp/task.h>
10#include <lib/async/default.h>
11#include <lib/fdio/directory.h>
12#include <lib/fdio/fd.h>
13#include <lib/fdio/namespace.h>
14#include <lib/fidl/cpp/string.h>
15#include <lib/sys/cpp/service_directory.h>
16#include <lib/vfs/cpp/composed_service_dir.h>
17#include <lib/vfs/cpp/remote_dir.h>
18#include <lib/zx/clock.h>
19#include <lib/zx/thread.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <unistd.h>
23#include <zircon/status.h>
24
25#include <regex>
26#include <utility>
27
28#include "dart_api.h"
29#include "flutter/fml/logging.h"
33#include "third_party/dart/runtime/include/dart_tools_api.h"
40
41#include "builtin_libraries.h"
42
43using tonic::ToDart;
44
45namespace dart_runner {
46
47namespace {
48
49constexpr char kTmpPath[] = "/tmp";
50
51constexpr zx::duration kIdleWaitDuration = zx::sec(2);
52constexpr zx::duration kIdleNotifyDuration = zx::msec(500);
53constexpr zx::duration kIdleSlack = zx::sec(1);
54
55void AfterTask(async_loop_t*, void*) {
58 // Verify that the queue exists, as this method could have been called back as
59 // part of the exit routine, after the destruction of the microtask queue.
60 if (queue) {
61 queue->RunMicrotasks();
62 }
63}
64
65constexpr async_loop_config_t kLoopConfig = {
66 .default_accessors =
67 {
68 .getter = async_get_default_dispatcher,
69 .setter = async_set_default_dispatcher,
70 },
71 .make_default_for_current_thread = true,
72 .epilogue = &AfterTask,
73};
74
75// Find the last path of the component.
76// fuchsia-pkg://fuchsia.com/hello_dart#meta/hello_dart.cmx -> hello_dart.cmx
77std::string GetLabelFromUrl(const std::string& url) {
78 for (size_t i = url.length() - 1; i > 0; i--) {
79 if (url[i] == '/') {
80 return url.substr(i + 1, url.length() - 1);
81 }
82 }
83 return url;
84}
85
86// Find the name of the component.
87// fuchsia-pkg://fuchsia.com/hello_dart#meta/hello_dart.cm -> hello_dart
88std::string GetComponentNameFromUrl(const std::string& url) {
89 const std::string label = GetLabelFromUrl(url);
90 for (size_t i = 0; i < label.length(); ++i) {
91 if (label[i] == '.') {
92 return label.substr(0, i);
93 }
94 }
95 return label;
96}
97
98} // namespace
99
101 fuchsia::component::runner::ComponentStartInfo start_info,
102 std::shared_ptr<sys::ServiceDirectory> runner_incoming_services,
103 fidl::InterfaceRequest<fuchsia::component::runner::ComponentController>
104 controller)
105 : loop_(new async::Loop(&kLoopConfig)),
106 label_(GetLabelFromUrl(start_info.resolved_url())),
107 url_(start_info.resolved_url()),
108 runner_incoming_services_(std::move(runner_incoming_services)),
109 dart_outgoing_dir_(new vfs::PseudoDir()),
110 start_info_(std::move(start_info)),
111 binding_(this, std::move(controller)) {
112 binding_.set_error_handler([this](zx_status_t status) { Kill(); });
113
114 // TODO(fxb/84537): This data path is configured based how we build Flutter
115 // applications in tree currently, but the way we build the Flutter
116 // application may change. We should avoid assuming the data path and let the
117 // CML file specify this data path instead.
118 const std::string component_name = GetComponentNameFromUrl(url_);
119 data_path_ = "pkg/data/" + component_name;
120
121 zx_status_t idle_timer_status =
122 zx::timer::create(ZX_TIMER_SLACK_LATE, ZX_CLOCK_MONOTONIC, &idle_timer_);
123 if (idle_timer_status != ZX_OK) {
124 FML_LOG(INFO) << "Idle timer creation failed: "
125 << zx_status_get_string(idle_timer_status);
126 } else {
127 idle_wait_.set_object(idle_timer_.get());
128 idle_wait_.set_trigger(ZX_TIMER_SIGNALED);
129 idle_wait_.Begin(async_get_default_dispatcher());
130 }
131
132 // Close the runtime_dir channel if we don't intend to serve it. Otherwise any
133 // access to the runtime_dir will hang forever.
134 start_info_.clear_runtime_dir();
135}
136
138 if (namespace_) {
139 fdio_ns_destroy(namespace_);
140 namespace_ = nullptr;
141 }
142 close(stdout_fd_);
143 close(stderr_fd_);
144}
145
147 // Name the thread after the url of the component being launched.
148 zx::thread::self()->set_property(ZX_PROP_NAME, label_.c_str(), label_.size());
149 Dart_SetThreadName(label_.c_str());
150
151 if (!CreateAndBindNamespace()) {
152 return false;
153 }
154
155 if (SetUpFromAppSnapshot()) {
156 FML_LOG(INFO) << url_ << " is running from an app snapshot";
157 } else if (SetUpFromKernel()) {
158 FML_LOG(INFO) << url_ << " is running from kernel";
159 } else {
160 FML_LOG(ERROR) << "Failed to set up component controller for " << url_;
161 return false;
162 }
163
164 return true;
165}
166
167bool DartComponentController::CreateAndBindNamespace() {
168 if (!start_info_.has_ns()) {
169 FML_LOG(ERROR) << "Component start info does not have a namespace.";
170 return false;
171 }
172
173 const zx_status_t ns_create_status = fdio_ns_create(&namespace_);
174 if (ns_create_status != ZX_OK) {
175 FML_LOG(ERROR) << "Failed to create namespace: "
176 << zx_status_get_string(ns_create_status);
177 }
178
179 dart_utils::BindTemp(namespace_);
180
181 // Bind each directory in start_info's namespace to the controller's namespace
182 // instance.
183 for (auto& ns_entry : *start_info_.mutable_ns()) {
184 // TODO(akbiggs): Under what circumstances does a namespace entry not have a
185 // path or directory? Should we log an error for these?
186 if (!ns_entry.has_path() || !ns_entry.has_directory()) {
187 continue;
188 }
189
190 if (ns_entry.path() == kTmpPath) {
191 // /tmp is covered by a locally served virtual filesystem.
192 continue;
193 }
194
195 // We move ownership of the directory & path since RAII is used to keep
196 // the handle open.
197 fidl::InterfaceHandle<::fuchsia::io::Directory> dir =
198 std::move(*ns_entry.mutable_directory());
199 const std::string path = std::move(*ns_entry.mutable_path());
200
201 const zx_status_t ns_bind_status =
202 fdio_ns_bind(namespace_, path.c_str(), dir.TakeChannel().release());
203 if (ns_bind_status != ZX_OK) {
204 FML_LOG(ERROR) << "Failed to bind " << path << " to namespace: "
205 << zx_status_get_string(ns_bind_status);
206 return false;
207 }
208 }
209
210 dart_outgoing_dir_request_ = dart_outgoing_dir_ptr_.NewRequest();
211
212 fuchsia::io::DirectoryHandle dart_public_dir;
213 {
214 auto request = dart_public_dir.NewRequest().TakeChannel();
215 const zx_status_t status =
216 fdio_open3_at(dart_outgoing_dir_ptr_.channel().get(), "svc",
217 uint64_t{fuchsia::io::PERM_READABLE}, request.release());
218 if (status != ZX_OK) {
219 FML_LOG(ERROR) << "Failed to open /svc in outgoing directory: "
220 << zx_status_get_string(status);
221 return false;
222 }
223 }
224
225 auto composed_service_dir = std::make_unique<vfs::ComposedServiceDir>();
226 composed_service_dir->SetFallback(
227 fidl::ClientEnd<fuchsia_io::Directory>(dart_public_dir.TakeChannel()));
228
229 // Request an event from the directory to ensure it is servicing requests.
230 dart_outgoing_dir_ptr_->Open(
231 ".",
232 fuchsia::io::Flags::PROTOCOL_NODE |
233 fuchsia::io::Flags::FLAG_SEND_REPRESENTATION,
234 {}, dart_outgoing_dir_ptr_to_check_on_open_.NewRequest().TakeChannel());
235
236 // Collect our standard set of directories.
237 std::vector<std::string> other_dirs = {"debug", "ctrl"};
238
239 dart_outgoing_dir_ptr_to_check_on_open_.events().OnRepresentation =
240 [this, other_dirs](auto unused) {
241 dart_outgoing_dir_ptr_to_check_on_open_.Unbind();
242 // add other directories as RemoteDirs.
243 for (auto& dir_str : other_dirs) {
244 fuchsia::io::DirectoryHandle dir;
245 auto request = dir.NewRequest().TakeChannel();
246 const zx_status_t status = fdio_open3_at(
247 dart_outgoing_dir_ptr_.channel().get(), dir_str.c_str(),
248 uint64_t{fuchsia::io::Flags::PROTOCOL_DIRECTORY |
249 fuchsia::io::PERM_READABLE},
250 request.release());
251 if (status == ZX_OK) {
252 dart_outgoing_dir_->AddEntry(
253 dir_str.c_str(),
254 std::make_unique<vfs::RemoteDir>(dir.TakeChannel()));
255 } else {
256 FML_LOG(ERROR) << "could not add out directory entry(" << dir_str
257 << ") for flutter component(" << label_
258 << "): " << zx_status_get_string(status);
259 }
260 }
261 };
262 dart_outgoing_dir_ptr_to_check_on_open_.set_error_handler(
263 [this](zx_status_t status) {
264 dart_outgoing_dir_ptr_to_check_on_open_.Unbind();
265 });
266
267 // Expose the "Echo" service here on behalf of the running dart program, so
268 // that integration tests can make use of it.
269 //
270 // The flutter/engine repository doesn't support connecting to FIDL from Dart,
271 // so for the tests sake we connect to the FIDL from C++ here and proxy the
272 // Echo to dart using native hooks.
273 composed_service_dir->AddService(
274 dart::test::Echo::Name_,
275 std::make_unique<vfs::Service>([this](zx::channel channel,
276 async_dispatcher_t* dispatcher) {
277 echo_binding_.AddBinding(
278 this, fidl::InterfaceRequest<dart::test::Echo>(std::move(channel)));
279 }));
280 dart_outgoing_dir_->AddEntry("svc", std::move(composed_service_dir));
281
282 if (start_info_.has_outgoing_dir()) {
283 fidl::ServerEnd<fuchsia_io::Directory> server_end{
284 start_info_.mutable_outgoing_dir()->TakeChannel()};
285 dart_outgoing_dir_->Serve(
286 fuchsia_io::wire::kPermReadable | fuchsia_io::wire::kPermWritable,
287 std::move(server_end));
288 }
289
290 return true;
291}
292
293bool DartComponentController::SetUpFromKernel() {
296 namespace_, data_path_ + "/app.dilplist", manifest)) {
297 return false;
298 }
299
301 nullptr, "/pkg/data/isolate_core_snapshot_data.bin",
302 isolate_snapshot_data_)) {
303 return false;
304 }
305
306 std::string str(reinterpret_cast<const char*>(manifest.address()),
307 manifest.size());
308 Dart_Handle library = Dart_Null();
309
310 for (size_t start = 0; start < manifest.size();) {
311 size_t end = str.find("\n", start);
312 if (end == std::string::npos) {
313 FML_LOG(ERROR) << "Malformed manifest";
314 Dart_ExitScope();
315 return false;
316 }
317
318 std::string path = data_path_ + "/" + str.substr(start, end - start);
319 start = end + 1;
320
323 kernel)) {
324 FML_LOG(ERROR) << "Cannot load kernel from namespace: " << path;
325 Dart_ExitScope();
326 return false;
327 }
328 kernel_peices_.emplace_back(std::move(kernel));
329 }
330
331 if (!CreateIsolate(isolate_snapshot_data_.address(),
332 /*isolate_snapshot_instructions=*/nullptr)) {
333 return false;
334 }
335
336 Dart_EnterScope();
337
338 for (const auto& kernel : kernel_peices_) {
339 library = Dart_LoadLibraryFromKernel(kernel.address(), kernel.size());
340 if (Dart_IsError(library)) {
341 FML_LOG(ERROR) << "Cannot load library from kernel: "
342 << Dart_GetError(library);
343 Dart_ExitScope();
344 return false;
345 }
346 }
347
348 Dart_SetRootLibrary(library);
349
350 Dart_Handle result = Dart_FinalizeLoading(false);
351 if (Dart_IsError(result)) {
352 FML_LOG(ERROR) << "Failed to FinalizeLoading: " << Dart_GetError(result);
353 Dart_ExitScope();
354 return false;
355 }
356
357 return true;
358}
359
360bool DartComponentController::SetUpFromAppSnapshot() {
361#if !defined(AOT_RUNTIME)
362 return false;
363#else
364 // Load the ELF snapshot as available, and fall back to a blobs snapshot
365 // otherwise.
366 const uint8_t *isolate_data, *isolate_instructions;
367 if (elf_snapshot_.Load(namespace_, data_path_ + "/app_aot_snapshot.so")) {
368 isolate_data = elf_snapshot_.IsolateData();
369 isolate_instructions = elf_snapshot_.IsolateInstrs();
370 if (isolate_data == nullptr || isolate_instructions == nullptr) {
371 return false;
372 }
373 } else {
375 namespace_, data_path_ + "/isolate_snapshot_data.bin",
376 isolate_snapshot_data_)) {
377 return false;
378 }
379 isolate_data = isolate_snapshot_data_.address();
380 isolate_instructions = nullptr;
381 }
382 return CreateIsolate(isolate_data, isolate_instructions);
383#endif // defined(AOT_RUNTIME)
384}
385
386bool DartComponentController::CreateIsolate(
387 const uint8_t* isolate_snapshot_data,
388 const uint8_t* isolate_snapshot_instructions) {
389 // Create the isolate from the snapshot.
390 char* error = nullptr;
391
392 // TODO(dart_runner): Pass if we start using tonic's loader.
393 intptr_t namespace_fd = -1;
394
395 // Freed in IsolateShutdownCallback.
396 auto state = new std::shared_ptr<tonic::DartState>(new tonic::DartState(
397 namespace_fd, [this](Dart_Handle result) { MessageEpilogue(result); }));
398
399 Dart_IsolateFlags isolate_flags;
400 Dart_IsolateFlagsInitialize(&isolate_flags);
401 isolate_flags.null_safety = true;
402
403 isolate_ = Dart_CreateIsolateGroup(
404 url_.c_str(), label_.c_str(), isolate_snapshot_data,
405 isolate_snapshot_instructions, &isolate_flags, state, state, &error);
406 if (!isolate_) {
407 FML_LOG(ERROR) << "Dart_CreateIsolateGroup failed: " << error;
408 return false;
409 }
410
411 state->get()->SetIsolate(isolate_);
412
414 [loop = loop_.get()](auto callback) {
415 async::PostTask(loop->dispatcher(), std::move(callback));
416 };
417 state->get()->message_handler().Initialize(dispatcher);
418
419 state->get()->SetReturnCodeCallback(
420 [this](uint32_t return_code) { return_code_ = return_code; });
421
422 return true;
423}
424
426 async::PostTask(loop_->dispatcher(), [loop = loop_.get(), app = this] {
427 if (!app->RunDartMain()) {
428 loop->Quit();
429 }
430 });
431 loop_->Run();
432
433 if (binding_.is_bound()) {
434 // From the documentation for ComponentController, ZX_OK should be sent when
435 // the ComponentController receives a termination request. However, if the
436 // component exited with a non-zero return code, we indicate this by sending
437 // an INTERNAL epitaph instead.
438 //
439 // TODO(fxb/86666): Communicate return code from the ComponentController
440 // once v2 has support.
441 if (return_code_ == 0) {
442 binding_.Close(ZX_OK);
443 } else {
444 FML_LOG(ERROR) << "Component exited with non-zero return code: "
445 << return_code_;
446 binding_.Close(zx_status_t(fuchsia::component::Error::INTERNAL));
447 }
448 }
449}
450
451bool DartComponentController::RunDartMain() {
452 FML_CHECK(namespace_ != nullptr);
453 Dart_EnterScope();
454
456
457 // TODO(fxb/88384): Create a file descriptor for each component that is
458 // launched and listen for anything that is written to the component. When
459 // something is written to the component, forward that message along to the
460 // Fuchsia logger and decorate it with the tag that it came from the
461 // component.
462 stdout_fd_ = fileno(stdout);
463 stderr_fd_ = fileno(stderr);
464
465 InitBuiltinLibrariesForIsolate(url_, namespace_, stdout_fd_, stderr_fd_,
466 dart_outgoing_dir_request_.TakeChannel(),
467 false /* service_isolate */);
468
469 Dart_ExitScope();
470 Dart_ExitIsolate();
471 char* error = Dart_IsolateMakeRunnable(isolate_);
472 if (error != nullptr) {
473 Dart_EnterIsolate(isolate_);
474 Dart_ShutdownIsolate();
475 FML_LOG(ERROR) << "Unable to make isolate runnable: " << error;
476 free(error);
477 return false;
478 }
479 Dart_EnterIsolate(isolate_);
480 Dart_EnterScope();
481
482 // TODO(fxb/88383): Support argument passing.
483 Dart_Handle corelib = Dart_LookupLibrary(ToDart("dart:core"));
484 Dart_Handle string_type =
485 Dart_GetNonNullableType(corelib, ToDart("String"), 0, NULL);
486 Dart_Handle dart_arguments =
487 Dart_NewListOfTypeFilled(string_type, Dart_EmptyString(), 0);
488
489 if (Dart_IsError(dart_arguments)) {
490 FML_LOG(ERROR) << "Failed to allocate Dart arguments list: "
491 << Dart_GetError(dart_arguments);
492 Dart_ExitScope();
493 return false;
494 }
495
496 Dart_Handle user_main = Dart_GetField(Dart_RootLibrary(), ToDart("main"));
497
498 if (Dart_IsError(user_main)) {
499 FML_LOG(ERROR) << "Failed to locate user_main in the root library: "
500 << Dart_GetError(user_main);
501 Dart_ExitScope();
502 return false;
503 }
504
505 Dart_Handle fuchsia_lib = Dart_LookupLibrary(tonic::ToDart("dart:fuchsia"));
506
507 if (Dart_IsError(fuchsia_lib)) {
508 FML_LOG(ERROR) << "Failed to locate dart:fuchsia: "
509 << Dart_GetError(fuchsia_lib);
510 Dart_ExitScope();
511 return false;
512 }
513
514 Dart_Handle main_result = tonic::DartInvokeField(
515 fuchsia_lib, "_runUserMainForDartRunner", {user_main, dart_arguments});
516
517 if (Dart_IsError(main_result)) {
518 auto dart_state = tonic::DartState::Current();
519 if (!dart_state->has_set_return_code()) {
520 // The program hasn't set a return code meaning this exit is unexpected.
521 FML_LOG(ERROR) << Dart_GetError(main_result);
522 return_code_ = tonic::GetErrorExitCode(main_result);
523
524 dart_utils::HandleIfException(runner_incoming_services_, url_,
525 main_result);
526 }
527 Dart_ExitScope();
528 return false;
529 }
530
531 Dart_ExitScope();
532 return true;
533}
534
535void DartComponentController::EchoString(fidl::StringPtr value,
536 EchoStringCallback callback) {
537 Dart_EnterScope();
538
539 Dart_Handle builtin_lib = Dart_LookupLibrary(ToDart("dart:fuchsia.builtin"));
541
542 Dart_Handle receive_echo_string = ToDart("_receiveEchoString");
543 Dart_Handle string_to_echo =
544 value.has_value() ? tonic::ToDart(*value) : Dart_Null();
545 Dart_Handle result =
546 Dart_Invoke(builtin_lib, receive_echo_string, 1, &string_to_echo);
548
549 fidl::StringPtr echo_string;
550 if (!Dart_IsNull(result)) {
551 echo_string = tonic::StdStringFromDart(result);
552 }
553 callback(std::move(echo_string));
554
555 Dart_ExitScope();
556}
557
558void DartComponentController::Kill() {
559 if (Dart_CurrentIsolate()) {
562 if (queue) {
563 queue->Destroy();
564 }
565
566 loop_->Quit();
567
568 // TODO(rosswang): The docs warn of threading issues if doing this again,
569 // but without this, attempting to shut down the isolate finalizes app
570 // contexts that can't tell a shutdown is in progress and so fatal.
571 Dart_SetMessageNotifyCallback(nullptr);
572
573 Dart_ShutdownIsolate();
574 }
575}
576
577void DartComponentController::Stop() {
578 Kill();
579}
580
581void DartComponentController::MessageEpilogue(Dart_Handle result) {
582 auto dart_state = tonic::DartState::Current();
583 // If the Dart program has set a return code, then it is intending to shut
584 // down by way of a fatal error, and so there is no need to override
585 // return_code_.
586 if (dart_state->has_set_return_code()) {
587 Dart_ShutdownIsolate();
588 return;
589 }
590
591 dart_utils::HandleIfException(runner_incoming_services_, url_, result);
592
593 // Otherwise, see if there was any other error.
594 return_code_ = tonic::GetErrorExitCode(result);
595 if (return_code_ != 0) {
596 Dart_ShutdownIsolate();
597 return;
598 }
599
600 idle_start_ = zx::clock::get_monotonic();
601 zx_status_t status =
602 idle_timer_.set(idle_start_ + kIdleWaitDuration, kIdleSlack);
603 if (status != ZX_OK) {
604 FML_LOG(INFO) << "Idle timer set failed: " << zx_status_get_string(status);
605 }
606}
607
608void DartComponentController::OnIdleTimer(async_dispatcher_t* dispatcher,
609 async::WaitBase* wait,
610 zx_status_t status,
611 const zx_packet_signal* signal) {
612 if ((status != ZX_OK) || !(signal->observed & ZX_TIMER_SIGNALED) ||
613 !Dart_CurrentIsolate()) {
614 // Timer closed or isolate shutdown.
615 return;
616 }
617
618 zx::time deadline = idle_start_ + kIdleWaitDuration;
619 zx::time now = zx::clock::get_monotonic();
620 if (now >= deadline) {
621 // No Dart message has been processed for kIdleWaitDuration: assume we'll
622 // stay idle for kIdleNotifyDuration.
623 Dart_NotifyIdle((now + kIdleNotifyDuration).get());
624 idle_start_ = zx::time(0);
625 idle_timer_.cancel(); // De-assert signal.
626 } else {
627 // Early wakeup or message pushed idle time forward: reschedule.
628 zx_status_t status = idle_timer_.set(deadline, kIdleSlack);
629 if (status != ZX_OK) {
630 FML_LOG(INFO) << "Idle timer set failed: "
631 << zx_status_get_string(status);
632 }
633 }
634 wait->Begin(dispatcher); // ignore errors
635}
636
637void DartComponentController::handle_unknown_method(uint64_t ordinal,
638 bool method_has_response) {
639 FML_LOG(ERROR) << "Unknown method called on DartComponentController. "
640 "Ordinal: "
641 << ordinal;
642}
643
644} // namespace dart_runner
DartComponentController(fuchsia::component::runner::ComponentStartInfo start_info, std::shared_ptr< sys::ServiceDirectory > runner_incoming_services, fidl::InterfaceRequest< fuchsia::component::runner::ComponentController > controller)
bool Load(fdio_ns_t *namespc, const std::string &path)
const uint8_t * IsolateData() const
const uint8_t * IsolateInstrs() const
static bool LoadFromNamespace(fdio_ns_t *namespc, const std::string &path, MappedResource &resource, bool executable=false)
const uint8_t * address() const
std::function< void(std::function< void(void)>)> TaskDispatcher
static DartMicrotaskQueue * GetForCurrentThread()
static DartState * Current()
Definition dart_state.cc:56
int32_t value
VkQueue queue
Definition main.cc:71
const gchar * channel
const uint8_t uint32_t uint32_t GError ** error
FlutterDesktopBinaryReply callback
#define FML_LOG(severity)
Definition logging.h:101
#define FML_CHECK(condition)
Definition logging.h:104
void InitBuiltinLibrariesForIsolate(const std::string &script_uri, fdio_ns_t *namespc, int stdoutfd, int stderrfd, zx::channel directory_request, bool service_isolate)
void HandleIfException(std::shared_ptr<::sys::ServiceDirectory > services, const std::string &component_url, Dart_Handle result)
void BindTemp(fdio_ns_t *ns)
Definition tempfs.cc:23
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
Definition switch_defs.h:52
Definition ref_ptr.h:261
Dart_Handle ToDart(const T &object)
int GetErrorExitCode(Dart_Handle handle)
Definition dart_error.cc:68
bool CheckAndHandleError(Dart_Handle handle)
Definition dart_error.cc:33
std::string StdStringFromDart(Dart_Handle handle)
Dart_Handle DartInvokeField(Dart_Handle target, const char *name, std::initializer_list< Dart_Handle > args)
fidl::Binding< fuchsia::ui::composition::ChildViewWatcher > binding_
const size_t start
const size_t end