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