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>
23#include <zircon/status.h>
29#include "flutter/fml/logging.h"
33#include "third_party/dart/runtime/include/dart_tools_api.h"
49constexpr char kTmpPath[] =
"/tmp";
52constexpr zx::duration kIdleNotifyDuration = zx::msec(500);
55void AfterTask(async_loop_t*,
void*) {
61 queue->RunMicrotasks();
65constexpr async_loop_config_t kLoopConfig = {
68 .getter = async_get_default_dispatcher,
69 .setter = async_set_default_dispatcher,
71 .make_default_for_current_thread =
true,
72 .epilogue = &AfterTask,
77std::string GetLabelFromUrl(
const std::string& url) {
78 for (
size_t i = url.length() - 1;
i > 0;
i--) {
80 return url.substr(
i + 1, url.length() - 1);
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);
101 fuchsia::component::runner::ComponentStartInfo start_info,
102 std::shared_ptr<sys::ServiceDirectory> runner_incoming_services,
103 fidl::InterfaceRequest<fuchsia::component::runner::ComponentController>
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)),
112 binding_.set_error_handler([
this](zx_status_t status) { Kill(); });
118 const std::string component_name = GetComponentNameFromUrl(url_);
119 data_path_ =
"pkg/data/" + component_name;
121 zx_status_t idle_timer_status =
123 if (idle_timer_status != ZX_OK) {
124 FML_LOG(INFO) <<
"Idle timer creation failed: "
125 << zx_status_get_string(idle_timer_status);
127 idle_wait_.set_object(idle_timer_.get());
128 idle_wait_.set_trigger(ZX_TIMER_SIGNALED);
129 idle_wait_.Begin(async_get_default_dispatcher());
134 start_info_.clear_runtime_dir();
139 fdio_ns_destroy(namespace_);
140 namespace_ =
nullptr;
148 zx::thread::self()->set_property(ZX_PROP_NAME, label_.c_str(), label_.size());
151 if (!CreateAndBindNamespace()) {
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";
160 FML_LOG(
ERROR) <<
"Failed to set up component controller for " << url_;
167bool DartComponentController::CreateAndBindNamespace() {
168 if (!start_info_.has_ns()) {
169 FML_LOG(
ERROR) <<
"Component start info does not have a namespace.";
173 const zx_status_t ns_create_status = fdio_ns_create(&namespace_);
174 if (ns_create_status != ZX_OK) {
176 << zx_status_get_string(ns_create_status);
183 for (
auto& ns_entry : *start_info_.mutable_ns()) {
186 if (!ns_entry.has_path() || !ns_entry.has_directory()) {
190 if (ns_entry.path() == kTmpPath) {
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());
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) {
205 << zx_status_get_string(ns_bind_status);
210 dart_outgoing_dir_request_ = dart_outgoing_dir_ptr_.NewRequest();
212 fuchsia::io::DirectoryHandle dart_public_dir;
216 fdio_service_connect_at(dart_outgoing_dir_ptr_.channel().get(),
"svc",
217 dart_public_dir.NewRequest().TakeChannel().release());
219#pragma clang diagnostic push
220#pragma clang diagnostic ignored "-Wdeprecated-declarations"
222 auto composed_service_dir = std::make_unique<vfs::ComposedServiceDir>();
223 composed_service_dir->set_fallback(std::move(dart_public_dir));
225#pragma clang diagnostic pop
228 dart_outgoing_dir_ptr_->Clone(
229 fuchsia::io::OpenFlags::DESCRIBE |
230 fuchsia::io::OpenFlags::CLONE_SAME_RIGHTS,
231 dart_outgoing_dir_ptr_to_check_on_open_.NewRequest());
234 std::vector<std::string> other_dirs = {
"debug",
"ctrl"};
236 dart_outgoing_dir_ptr_to_check_on_open_.events().OnOpen =
237 [
this, other_dirs](zx_status_t status,
auto unused) {
238 dart_outgoing_dir_ptr_to_check_on_open_.Unbind();
239 if (status != ZX_OK) {
240 FML_LOG(
ERROR) <<
"could not bind out directory for dart component("
241 << label_ <<
"): " << zx_status_get_string(status);
246 for (
auto& dir_str : other_dirs) {
247 fuchsia::io::DirectoryHandle
dir;
248 auto request =
dir.NewRequest().TakeChannel();
249 auto status = fdio_open_at(
250 dart_outgoing_dir_ptr_.channel().get(), dir_str.c_str(),
251 static_cast<uint32_t
>(fuchsia::io::OpenFlags::DIRECTORY |
252 fuchsia::io::OpenFlags::RIGHT_READABLE),
254 if (status == ZX_OK) {
255 dart_outgoing_dir_->AddEntry(
257 std::make_unique<vfs::RemoteDir>(
dir.TakeChannel()));
259 FML_LOG(
ERROR) <<
"could not add out directory entry(" << dir_str
260 <<
") for flutter component(" << label_
261 <<
"): " << zx_status_get_string(status);
265 dart_outgoing_dir_ptr_to_check_on_open_.set_error_handler(
266 [
this](zx_status_t status) {
267 dart_outgoing_dir_ptr_to_check_on_open_.Unbind();
276 composed_service_dir->AddService(
277 dart::test::Echo::Name_,
278 std::make_unique<vfs::Service>([
this](zx::channel channel,
279 async_dispatcher_t* dispatcher) {
280 echo_binding_.AddBinding(
281 this, fidl::InterfaceRequest<dart::test::Echo>(std::move(channel)));
283 dart_outgoing_dir_->AddEntry(
"svc", std::move(composed_service_dir));
285 if (start_info_.has_outgoing_dir()) {
286 dart_outgoing_dir_->Serve(
287 fuchsia::io::OpenFlags::RIGHT_READABLE |
288 fuchsia::io::OpenFlags::RIGHT_WRITABLE |
289 fuchsia::io::OpenFlags::DIRECTORY,
290 start_info_.mutable_outgoing_dir()->TakeChannel());
296bool DartComponentController::SetUpFromKernel() {
299 namespace_, data_path_ +
"/app.dilplist",
manifest)) {
304 nullptr,
"/pkg/data/isolate_core_snapshot_data.bin",
305 isolate_snapshot_data_)) {
309 std::string str(
reinterpret_cast<const char*
>(
manifest.address()),
314 size_t end = str.find(
"\n", start);
315 if (end == std::string::npos) {
321 std::string
path = data_path_ +
"/" + str.substr(start, end - start);
331 kernel_peices_.emplace_back(std::move(kernel));
334 if (!CreateIsolate(isolate_snapshot_data_.
address(),
341 for (
const auto& kernel : kernel_peices_) {
363bool DartComponentController::SetUpFromAppSnapshot() {
364#if !defined(AOT_RUNTIME)
369 const uint8_t *isolate_data, *isolate_instructions;
370 if (elf_snapshot_.
Load(namespace_, data_path_ +
"/app_aot_snapshot.so")) {
373 if (isolate_data ==
nullptr || isolate_instructions ==
nullptr) {
378 namespace_, data_path_ +
"/isolate_snapshot_data.bin",
379 isolate_snapshot_data_)) {
382 isolate_data = isolate_snapshot_data_.
address();
383 isolate_instructions =
nullptr;
385 return CreateIsolate(isolate_data, isolate_instructions);
389bool DartComponentController::CreateIsolate(
393 char*
error =
nullptr;
396 intptr_t namespace_fd = -1;
414 state->get()->SetIsolate(isolate_);
417 [loop = loop_.get()](
auto callback) {
418 async::PostTask(loop->dispatcher(), std::move(
callback));
420 state->get()->message_handler().Initialize(dispatcher);
422 state->get()->SetReturnCodeCallback(
423 [
this](uint32_t return_code) { return_code_ = return_code; });
429 async::PostTask(loop_->dispatcher(), [loop = loop_.get(),
app =
this] {
430 if (!app->RunDartMain()) {
444 if (return_code_ == 0) {
447 FML_LOG(
ERROR) <<
"Component exited with non-zero return code: "
449 binding_.Close(zx_status_t(fuchsia::component::Error::INTERNAL));
454bool DartComponentController::RunDartMain() {
465 stdout_fd_ = fileno(stdout);
466 stderr_fd_ = fileno(stderr);
469 dart_outgoing_dir_request_.TakeChannel(),
475 if (
error !=
nullptr) {
493 FML_LOG(
ERROR) <<
"Failed to allocate Dart arguments list: "
502 FML_LOG(
ERROR) <<
"Failed to locate user_main in the root library: "
518 fuchsia_lib,
"_runUserMainForDartRunner", {user_main, dart_arguments});
522 if (!dart_state->has_set_return_code()) {
549 Dart_Invoke(builtin_lib, receive_echo_string, 1, &string_to_echo);
552 fidl::StringPtr echo_string;
580void DartComponentController::Stop() {
589 if (dart_state->has_set_return_code()) {
598 if (return_code_ != 0) {
603 idle_start_ = zx::clock::get_monotonic();
605 idle_timer_.set(idle_start_ + kIdleWaitDuration, kIdleSlack);
606 if (status != ZX_OK) {
607 FML_LOG(INFO) <<
"Idle timer set failed: " << zx_status_get_string(status);
611void DartComponentController::OnIdleTimer(async_dispatcher_t* dispatcher,
612 async::WaitBase* wait,
614 const zx_packet_signal* signal) {
615 if ((status != ZX_OK) || !(signal->observed & ZX_TIMER_SIGNALED) ||
621 zx::time deadline = idle_start_ + kIdleWaitDuration;
622 zx::time now = zx::clock::get_monotonic();
623 if (now >= deadline) {
628 idle_timer_.cancel();
631 zx_status_t status = idle_timer_.set(deadline, kIdleSlack);
632 if (status != ZX_OK) {
633 FML_LOG(INFO) <<
"Idle timer set failed: "
634 << zx_status_get_string(status);
637 wait->Begin(dispatcher);
DartComponentController(fuchsia::component::runner::ComponentStartInfo start_info, std::shared_ptr< sys::ServiceDirectory > runner_incoming_services, fidl::InterfaceRequest< fuchsia::component::runner::ComponentController > controller)
~DartComponentController() override
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 void StartForCurrentThread()
static DartState * Current()
DART_EXPORT Dart_Isolate Dart_CreateIsolateGroup(const char *script_uri, const char *name, const uint8_t *isolate_snapshot_data, const uint8_t *isolate_snapshot_instructions, Dart_IsolateFlags *flags, void *isolate_group_data, void *isolate_data, char **error)
DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags *flags)
DART_EXPORT Dart_Handle Dart_GetNonNullableType(Dart_Handle library, Dart_Handle class_name, intptr_t number_of_type_arguments, Dart_Handle *type_arguments)
DART_EXPORT DART_WARN_UNUSED_RESULT char * Dart_IsolateMakeRunnable(Dart_Isolate isolate)
DART_EXPORT void Dart_EnterScope(void)
DART_EXPORT void Dart_ExitScope(void)
DART_EXPORT void Dart_ShutdownIsolate(void)
DART_EXPORT Dart_Handle Dart_NewListOfTypeFilled(Dart_Handle element_type, Dart_Handle fill_object, intptr_t length)
struct _Dart_Handle * Dart_Handle
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
DART_EXPORT Dart_Handle Dart_EmptyString(void)
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_LoadLibraryFromKernel(const uint8_t *kernel_buffer, intptr_t kernel_buffer_size)
DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url)
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_FinalizeLoading(bool complete_futures)
DART_EXPORT void Dart_NotifyIdle(int64_t deadline)
DART_EXPORT Dart_Isolate Dart_CurrentIsolate(void)
DART_EXPORT Dart_Handle Dart_Null(void)
DART_EXPORT bool Dart_IsNull(Dart_Handle object)
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_GetField(Dart_Handle container, Dart_Handle name)
DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate)
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
DART_EXPORT void Dart_ExitIsolate(void)
DART_EXPORT void Dart_SetMessageNotifyCallback(Dart_MessageNotifyCallback message_notify_callback)
DART_EXPORT const char * Dart_GetError(Dart_Handle handle)
DART_EXPORT Dart_Handle Dart_RootLibrary(void)
DART_EXPORT Dart_Handle Dart_SetRootLibrary(Dart_Handle library)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
const uint8_t uint32_t uint32_t GError ** error
#define FML_LOG(severity)
#define FML_CHECK(condition)
const uint8_t * isolate_snapshot_data
const uint8_t * isolate_snapshot_instructions
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)
static void Kill(Thread *thread, JSONStream *js)
std::string EchoString(std::string arg)
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
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 A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
const myers::Point & get(const myers::Segment &)
Dart_Handle ToDart(const T &object)
int GetErrorExitCode(Dart_Handle handle)
bool CheckAndHandleError(Dart_Handle handle)
std::string StdStringFromDart(Dart_Handle handle)
Dart_Handle DartInvokeField(Dart_Handle target, const char *name, std::initializer_list< Dart_Handle > args)
static double time(int loops, Benchmark *bench, Target *target)