From 8b04b3888189bc0218131ae7eea79367a8ab4f33 Mon Sep 17 00:00:00 2001 From: Chase Latta <638538+chaselatta@users.noreply.github.com> Date: Thu, 8 Jul 2021 15:19:21 -0700 Subject: [PATCH] [fuchsia] make dart_runner work with cfv2 (#27226) Adds support for running the dart runner as a CFv2 component. The runner has been refactored to launch in both a v1 environemnt as well as a v2 environment. --- ci/licenses_golden/licenses_flutter | 5 + .../dart-pkg/fuchsia/sdk_ext/fuchsia.cc | 11 +- shell/platform/fuchsia/dart_runner/BUILD.gn | 2 + .../dart_runner/dart_component_controller.cc | 454 ++++++++++++------ .../dart_runner/dart_component_controller.h | 149 ++++-- .../fuchsia/dart_runner/dart_runner.cc | 48 +- .../fuchsia/dart_runner/dart_runner.h | 12 +- shell/platform/fuchsia/dart_runner/main.cc | 1 + .../fuchsia/dart_runner/meta/common.shard.cml | 39 ++ .../meta/dart_aot_product_runner.cml | 24 + .../dart_runner/meta/dart_aot_runner.cml | 24 + .../meta/dart_jit_product_runner.cml | 26 + .../dart_runner/meta/dart_jit_runner.cml | 26 + tools/fuchsia/devshell/serve.sh | 16 + tools/fuchsia/fuchsia_archive.gni | 4 + 15 files changed, 654 insertions(+), 187 deletions(-) create mode 100644 shell/platform/fuchsia/dart_runner/meta/common.shard.cml create mode 100644 shell/platform/fuchsia/dart_runner/meta/dart_aot_product_runner.cml create mode 100644 shell/platform/fuchsia/dart_runner/meta/dart_aot_runner.cml create mode 100644 shell/platform/fuchsia/dart_runner/meta/dart_jit_product_runner.cml create mode 100644 shell/platform/fuchsia/dart_runner/meta/dart_jit_runner.cml diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index f4feab78c7..8322c3ac1f 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1348,9 +1348,14 @@ FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/logging.h FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/main.cc FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/aot_product_runtime FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/aot_runtime +FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/common.shard.cml +FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/dart_aot_product_runner.cml FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/dart_aot_product_runner.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/dart_aot_runner.cml FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/dart_aot_runner.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/dart_jit_product_runner.cml FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/dart_jit_product_runner.cmx +FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/dart_jit_runner.cml FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/dart_jit_runner.cmx FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/dart_zircon_test.cmx FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/jit_product_runtime diff --git a/shell/platform/fuchsia/dart-pkg/fuchsia/sdk_ext/fuchsia.cc b/shell/platform/fuchsia/dart-pkg/fuchsia/sdk_ext/fuchsia.cc index 2857a5a7c3..fa96c417b0 100644 --- a/shell/platform/fuchsia/dart-pkg/fuchsia/sdk_ext/fuchsia.cc +++ b/shell/platform/fuchsia/dart-pkg/fuchsia/sdk_ext/fuchsia.cc @@ -117,10 +117,13 @@ void Initialize(fidl::InterfaceHandle environment, dart_state->class_library().add_provider("fuchsia", std::move(fuchsia_class_provider)); - result = Dart_SetField( - library, ToDart("_environment"), - ToDart(zircon::dart::Handle::Create(environment.TakeChannel()))); - FML_CHECK(!tonic::LogIfError(result)); + // v2 components do not use the environment + if (environment) { + result = Dart_SetField( + library, ToDart("_environment"), + ToDart(zircon::dart::Handle::Create(environment.TakeChannel()))); + FML_CHECK(!tonic::LogIfError(result)); + } if (directory_request) { result = Dart_SetField( diff --git a/shell/platform/fuchsia/dart_runner/BUILD.gn b/shell/platform/fuchsia/dart_runner/BUILD.gn index eb1e0e0ac8..6e08b011a8 100644 --- a/shell/platform/fuchsia/dart_runner/BUILD.gn +++ b/shell/platform/fuchsia/dart_runner/BUILD.gn @@ -58,6 +58,7 @@ template("runner") { "//flutter/fml", "//flutter/shell/platform/fuchsia/dart-pkg/fuchsia", "//flutter/shell/platform/fuchsia/dart-pkg/zircon", + "$fuchsia_sdk_root/fidl:fuchsia.component.runner", "$fuchsia_sdk_root/pkg:async", "$fuchsia_sdk_root/pkg:async-cpp", "$fuchsia_sdk_root/pkg:async-default", @@ -209,6 +210,7 @@ template("jit_runner_package") { binary = "dart_jit${product_suffix}_runner" cmx_file = rebase_path("meta/dart_jit${product_suffix}_runner.cmx") + cml_file = rebase_path("meta/dart_jit${product_suffix}_runner.cml") libraries = common_libs diff --git a/shell/platform/fuchsia/dart_runner/dart_component_controller.cc b/shell/platform/fuchsia/dart_runner/dart_component_controller.cc index dd9b16bd65..6ccd33f863 100644 --- a/shell/platform/fuchsia/dart_runner/dart_component_controller.cc +++ b/shell/platform/fuchsia/dart_runner/dart_component_controller.cc @@ -37,6 +37,7 @@ #include "third_party/tonic/logging/dart_error.h" #include "builtin_libraries.h" +#include "flutter/fml/logging.h" #include "logging.h" using tonic::ToDart; @@ -78,63 +79,29 @@ std::string GetLabelFromURL(const std::string& url) { return url; } -} // namespace - -DartComponentController::DartComponentController( - fuchsia::sys::Package package, - fuchsia::sys::StartupInfo startup_info, - std::shared_ptr runner_incoming_services, - fidl::InterfaceRequest controller) - : loop_(new async::Loop(&kLoopConfig)), - label_(GetLabelFromURL(package.resolved_url)), - url_(std::move(package.resolved_url)), - package_(std::move(package)), - startup_info_(std::move(startup_info)), - runner_incoming_services_(runner_incoming_services), - binding_(this) { - for (size_t i = 0; i < startup_info_.program_metadata->size(); ++i) { - auto pg = startup_info_.program_metadata->at(i); - if (pg.key.compare(kDataKey) == 0) { - data_path_ = "pkg/" + pg.value; +// Find the name of the component. +// fuchsia-pkg://fuchsia.com/hello_dart#meta/hello_dart.cm -> hello_dart +std::string GetComponentNameFromUrl(const std::string& url) { + auto label = GetLabelFromURL(url); + for (size_t i = 0; i < label.length(); ++i) { + if (label[i] == '.') { + return label.substr(0, i); } } - if (data_path_.empty()) { - FX_LOGF(ERROR, LOG_TAG, "Could not find a /pkg/data directory for %s", - url_.c_str()); - return; - } - if (controller.is_valid()) { - binding_.Bind(std::move(controller)); - binding_.set_error_handler([this](zx_status_t status) { Kill(); }); - } - - zx_status_t status = - zx::timer::create(ZX_TIMER_SLACK_LATE, ZX_CLOCK_MONOTONIC, &idle_timer_); - if (status != ZX_OK) { - FX_LOGF(INFO, LOG_TAG, "Idle timer creation failed: %s", - zx_status_get_string(status)); - } else { - idle_wait_.set_object(idle_timer_.get()); - idle_wait_.set_trigger(ZX_TIMER_SIGNALED); - idle_wait_.Begin(async_get_default_dispatcher()); - } + return label; } -DartComponentController::~DartComponentController() { - if (namespace_) { - fdio_ns_destroy(namespace_); - namespace_ = nullptr; - } - close(stdoutfd_); - close(stderrfd_); -} +} // namespace bool DartComponentController::Setup() { // Name the thread after the url of the component being launched. zx::thread::self()->set_property(ZX_PROP_NAME, label_.c_str(), label_.size()); Dart_SetThreadName(label_.c_str()); - if (!SetupNamespace()) { + namespace_ = PrepareNamespace(); + + if (namespace_ == nullptr) { + FX_LOG(ERROR, LOG_TAG, "Failed to create namespace"); return false; } @@ -156,42 +123,33 @@ bool DartComponentController::Setup() { constexpr char kTmpPath[] = "/tmp"; constexpr char kServiceRootPath[] = "/svc"; -bool DartComponentController::SetupNamespace() { - fuchsia::sys::FlatNamespace* flat = &startup_info_.flat_namespace; - zx_status_t status = fdio_ns_create(&namespace_); +DartComponentController::DartComponentController( + std::string resolved_url, + std::shared_ptr runner_incoming_services) + : runner_incoming_services_(runner_incoming_services), + loop_(new async::Loop(&kLoopConfig)), + label_(GetLabelFromURL(resolved_url)), + url_(resolved_url) { + zx_status_t status = + zx::timer::create(ZX_TIMER_SLACK_LATE, ZX_CLOCK_MONOTONIC, &idle_timer_); if (status != ZX_OK) { - FX_LOG(ERROR, LOG_TAG, "Failed to create namespace"); - return false; + FX_LOGF(INFO, LOG_TAG, "Idle timer creation failed: %s", + zx_status_get_string(status)); + } else { + idle_wait_.set_object(idle_timer_.get()); + idle_wait_.set_trigger(ZX_TIMER_SIGNALED); + idle_wait_.Begin(async_get_default_dispatcher()); } +} - dart_utils::RunnerTemp::SetupComponent(namespace_); - - for (size_t i = 0; i < flat->paths.size(); ++i) { - if (flat->paths.at(i) == kTmpPath) { - // /tmp is covered by the local memfs. - continue; - } - - zx::channel dir; - if (flat->paths.at(i) == kServiceRootPath) { - // clone /svc so component_context can still use it below - dir = zx::channel(fdio_service_clone(flat->directories.at(i).get())); - } else { - dir = std::move(flat->directories.at(i)); - } - - zx_handle_t dir_handle = dir.release(); - const char* path = flat->paths.at(i).data(); - status = fdio_ns_bind(namespace_, path, dir_handle); - if (status != ZX_OK) { - FX_LOGF(ERROR, LOG_TAG, "Failed to bind %s to namespace: %s", - flat->paths.at(i).c_str(), zx_status_get_string(status)); - zx_handle_close(dir_handle); - return false; - } +DartComponentController::~DartComponentController() { + if (namespace_) { + fdio_ns_destroy(namespace_); + namespace_ = nullptr; } - return true; + close(stdoutfd_); + close(stderrfd_); } bool DartComponentController::SetupFromKernel() { @@ -200,12 +158,12 @@ bool DartComponentController::SetupFromKernel() { namespace_, data_path_ + "/app.dilplist", manifest)) { return false; } - if (!dart_utils::MappedResource::LoadFromNamespace( nullptr, "/pkg/data/isolate_core_snapshot_data.bin", isolate_snapshot_data_)) { return false; } + if (!dart_utils::MappedResource::LoadFromNamespace( nullptr, "/pkg/data/isolate_core_snapshot_instructions.bin", isolate_snapshot_instructions_, true /* executable */)) { @@ -222,6 +180,7 @@ bool DartComponentController::SetupFromKernel() { std::string str(reinterpret_cast(manifest.address()), manifest.size()); Dart_Handle library = Dart_Null(); + for (size_t start = 0; start < manifest.size();) { size_t end = str.find("\n", start); if (end == std::string::npos) { @@ -250,6 +209,7 @@ bool DartComponentController::SetupFromKernel() { kernel_peices_.emplace_back(std::move(kernel)); } + Dart_SetRootLibrary(library); Dart_Handle result = Dart_FinalizeLoading(false); @@ -292,22 +252,6 @@ bool DartComponentController::SetupFromAppSnapshot() { #endif // defined(AOT_RUNTIME) } -int DartComponentController::SetupFileDescriptor( - fuchsia::sys::FileDescriptorPtr fd) { - if (!fd) { - return -1; - } - // fd->handle1 and fd->handle2 are no longer used. - int outfd = -1; - zx_status_t status = fdio_fd_create(fd->handle0.release(), &outfd); - if (status != ZX_OK) { - FX_LOGF(ERROR, LOG_TAG, "Failed to extract output fd: %s", - zx_status_get_string(status)); - return -1; - } - return outfd; -} - bool DartComponentController::CreateIsolate( const uint8_t* isolate_snapshot_data, const uint8_t* isolate_snapshot_instructions) { @@ -316,6 +260,7 @@ bool DartComponentController::CreateIsolate( // TODO(dart_runner): Pass if we start using tonic's loader. intptr_t namespace_fd = -1; + // Freed in IsolateShutdownCallback. auto state = new std::shared_ptr(new tonic::DartState( namespace_fd, [this](Dart_Handle result) { MessageEpilogue(result); })); @@ -323,6 +268,7 @@ bool DartComponentController::CreateIsolate( isolate_ = Dart_CreateIsolateGroup( url_.c_str(), label_.c_str(), isolate_snapshot_data, isolate_snapshot_instructions, nullptr /* flags */, state, state, &error); + if (!isolate_) { FX_LOGF(ERROR, LOG_TAG, "Dart_CreateIsolateGroup failed: %s", error); return false; @@ -353,41 +299,22 @@ void DartComponentController::Run() { } bool DartComponentController::Main() { + FML_CHECK(namespace_ != nullptr); Dart_EnterScope(); tonic::DartMicrotaskQueue::StartForCurrentThread(); - std::vector arguments = - startup_info_.launch_info.arguments.value_or(std::vector()); + std::vector arguments = GetArguments(); - stdoutfd_ = SetupFileDescriptor(std::move(startup_info_.launch_info.out)); - stderrfd_ = SetupFileDescriptor(std::move(startup_info_.launch_info.err)); - auto directory_request = - std::move(startup_info_.launch_info.directory_request); + stdoutfd_ = GetStdoutFileDescriptor(); + stderrfd_ = GetStderrFileDescriptor(); - auto* flat = &startup_info_.flat_namespace; - std::unique_ptr svc; - for (size_t i = 0; i < flat->paths.size(); ++i) { - zx::channel dir; - if (flat->paths.at(i) == kServiceRootPath) { - svc = std::make_unique( - std::move(flat->directories.at(i))); - break; - } - } - if (!svc) { - FX_LOG(ERROR, LOG_TAG, "Unable to get /svc for dart component"); + if (!PrepareBuiltinLibraries()) { + FX_LOG(ERROR, LOG_TAG, + "Unable to prepare builtin libraries for dart component"); return false; } - fidl::InterfaceHandle environment; - svc->Connect(environment.NewRequest()); - - InitBuiltinLibrariesForIsolate( - url_, namespace_, stdoutfd_, stderrfd_, std::move(environment), - std::move(directory_request), false /* service_isolate */); - namespace_ = nullptr; - Dart_ExitScope(); Dart_ExitIsolate(); char* error = Dart_IsolateMakeRunnable(isolate_); @@ -420,6 +347,7 @@ bool DartComponentController::Main() { Dart_Handle main_result = Dart_Invoke(Dart_RootLibrary(), ToDart("main"), dart_utils::ArraySize(argv), argv); + if (Dart_IsError(main_result)) { auto dart_state = tonic::DartState::Current(); if (!dart_state->has_set_return_code()) { @@ -438,34 +366,6 @@ bool DartComponentController::Main() { return true; } -void DartComponentController::Kill() { - if (Dart_CurrentIsolate()) { - tonic::DartMicrotaskQueue* queue = - tonic::DartMicrotaskQueue::GetForCurrentThread(); - if (queue) { - queue->Destroy(); - } - - loop_->Quit(); - - // TODO(rosswang): The docs warn of threading issues if doing this again, - // but without this, attempting to shut down the isolate finalizes app - // contexts that can't tell a shutdown is in progress and so fatal. - Dart_SetMessageNotifyCallback(nullptr); - - Dart_ShutdownIsolate(); - } -} - -void DartComponentController::Detach() { - binding_.set_error_handler([](zx_status_t status) {}); -} - -void DartComponentController::SendReturnCode() { - binding_.events().OnTerminated(return_code_, - fuchsia::sys::TerminationReason::EXITED); -} - const zx::duration kIdleWaitDuration = zx::sec(2); const zx::duration kIdleNotifyDuration = zx::msec(500); const zx::duration kIdleSlack = zx::sec(1); @@ -527,4 +427,260 @@ void DartComponentController::OnIdleTimer(async_dispatcher_t* dispatcher, wait->Begin(dispatcher); // ignore errors } +void DartComponentController::Shutdown() { + if (Dart_CurrentIsolate()) { + tonic::DartMicrotaskQueue* queue = + tonic::DartMicrotaskQueue::GetForCurrentThread(); + if (queue) { + queue->Destroy(); + } + + loop_->Quit(); + + // TODO(rosswang): The docs warn of threading issues if doing this again, + // but without this, attempting to shut down the isolate finalizes app + // contexts that can't tell a shutdown is in progress and so fatal. + Dart_SetMessageNotifyCallback(nullptr); + + Dart_ShutdownIsolate(); + } +} + +/// DartComponentController_v1 +DartComponentController_v1::DartComponentController_v1( + fuchsia::sys::Package package, + fuchsia::sys::StartupInfo startup_info, + std::shared_ptr runner_incoming_services, + fidl::InterfaceRequest controller) + : DartComponentController::DartComponentController( + std::move(package.resolved_url), + runner_incoming_services), + package_(std::move(package)), + startup_info_(std::move(startup_info)), + binding_(this) { + for (size_t i = 0; i < startup_info_.program_metadata->size(); ++i) { + auto pg = startup_info_.program_metadata->at(i); + if (pg.key.compare(kDataKey) == 0) { + data_path_ = "pkg/" + pg.value; + } + } + + if (data_path_.empty()) { + FX_LOGF(ERROR, LOG_TAG, "Could not find a /pkg/data directory for %s", + url_.c_str()); + return; + } + if (controller.is_valid()) { + binding_.Bind(std::move(controller)); + binding_.set_error_handler([this](zx_status_t status) { Kill(); }); + } +} + +DartComponentController_v1::~DartComponentController_v1() {} + +void DartComponentController_v1::Kill() { + Shutdown(); +} + +void DartComponentController_v1::Detach() { + binding_.set_error_handler([](zx_status_t status) {}); +} + +void DartComponentController_v1::SendReturnCode() { + binding_.events().OnTerminated(return_code_, + fuchsia::sys::TerminationReason::EXITED); +} + +fdio_ns_t* DartComponentController_v1::PrepareNamespace() { + fdio_ns_t* ns; + zx_status_t status = fdio_ns_create(&ns); + if (status != ZX_OK) { + return nullptr; + } + + fuchsia::sys::FlatNamespace* flat = &startup_info_.flat_namespace; + + dart_utils::RunnerTemp::SetupComponent(ns); + + for (size_t i = 0; i < flat->paths.size(); ++i) { + if (flat->paths.at(i) == kTmpPath) { + // /tmp is covered by the local memfs. + continue; + } + + zx::channel dir; + if (flat->paths.at(i) == kServiceRootPath) { + // clone /svc so component_context can still use it below + dir = zx::channel(fdio_service_clone(flat->directories.at(i).get())); + } else { + dir = std::move(flat->directories.at(i)); + } + + zx_handle_t dir_handle = dir.release(); + const char* path = flat->paths.at(i).data(); + zx_status_t status = fdio_ns_bind(ns, path, dir_handle); + if (status != ZX_OK) { + FX_LOGF(ERROR, LOG_TAG, "Failed to bind %s to namespace: %s", + flat->paths.at(i).c_str(), zx_status_get_string(status)); + zx_handle_close(dir_handle); + return nullptr; + } + } + + return ns; +} + +int DartComponentController_v1::GetStdoutFileDescriptor() { + return SetupFileDescriptor(std::move(startup_info_.launch_info.out)); +} + +int DartComponentController_v1::GetStderrFileDescriptor() { + return SetupFileDescriptor(std::move(startup_info_.launch_info.err)); +} + +int DartComponentController_v1::SetupFileDescriptor( + fuchsia::sys::FileDescriptorPtr fd) { + if (!fd) { + return -1; + } + // fd->handle1 and fd->handle2 are no longer used. + int outfd = -1; + zx_status_t status = fdio_fd_create(fd->handle0.release(), &outfd); + if (status != ZX_OK) { + FX_LOGF(ERROR, LOG_TAG, "Failed to extract output fd: %s", + zx_status_get_string(status)); + return -1; + } + return outfd; +} + +bool DartComponentController_v1::PrepareBuiltinLibraries() { + auto directory_request = + std::move(startup_info_.launch_info.directory_request); + + auto* flat = &startup_info_.flat_namespace; + std::unique_ptr svc; + for (size_t i = 0; i < flat->paths.size(); ++i) { + zx::channel dir; + if (flat->paths.at(i) == kServiceRootPath) { + svc = std::make_unique( + std::move(flat->directories.at(i))); + break; + } + } + if (!svc) { + return false; + } + + fidl::InterfaceHandle environment; + svc->Connect(environment.NewRequest()); + + InitBuiltinLibrariesForIsolate( + url_, namespace_, stdoutfd_, stderrfd_, std::move(environment), + std::move(directory_request), false /* service_isolate */); + + return true; +} + +std::vector DartComponentController_v1::GetArguments() { + return startup_info_.launch_info.arguments.value_or( + std::vector()); +} + +/// DartComponentController_v2 +DartComponentController_v2::DartComponentController_v2( + fuchsia::component::runner::ComponentStartInfo start_info, + std::shared_ptr runner_incoming_services, + fidl::InterfaceRequest + controller) + : DartComponentController::DartComponentController( + std::move(start_info.resolved_url()), + runner_incoming_services), + start_info_(std::move(start_info)), + binding_(this) { + auto name = GetComponentNameFromUrl(url_); + data_path_ = "pkg/data/" + name; + + if (controller.is_valid()) { + binding_.Bind(std::move(controller)); + binding_.set_error_handler([this](zx_status_t status) { Kill(); }); + } +} + +DartComponentController_v2::~DartComponentController_v2() {} + +void DartComponentController_v2::Kill() { + binding_.set_error_handler([](zx_status_t status) {}); + Shutdown(); +} + +void DartComponentController_v2::Stop() { + Kill(); +} + +void DartComponentController_v2::SendReturnCode() { + if (binding_.is_bound()) { + binding_.Close(return_code_); + } +} + +fdio_ns_t* DartComponentController_v2::PrepareNamespace() { + fdio_ns_t* ns; + zx_status_t status = fdio_ns_create(&ns); + if (status != ZX_OK) { + return nullptr; + } + + if (!start_info_.has_ns()) { + return nullptr; + } + + dart_utils::RunnerTemp::SetupComponent(ns); + + for (auto& ns_entry : *start_info_.mutable_ns()) { + if (!ns_entry.has_path() || !ns_entry.has_directory()) { + continue; + } + + if (ns_entry.path() == kTmpPath) { + // /tmp is covered by the local memfs. + continue; + } + + auto dir = std::move(*ns_entry.mutable_directory()); + auto path = std::move(*ns_entry.mutable_path()); + + zx_status_t status = + fdio_ns_bind(ns, path.c_str(), dir.TakeChannel().release()); + if (status != ZX_OK) { + FX_LOGF(ERROR, LOG_TAG, "Failed to bind %s to namespace: %s", + path.c_str(), zx_status_get_string(status)); + return nullptr; + } + } + + return ns; +} + +int DartComponentController_v2::GetStdoutFileDescriptor() { + return fileno(stdout); +} + +int DartComponentController_v2::GetStderrFileDescriptor() { + return fileno(stderr); +} + +bool DartComponentController_v2::PrepareBuiltinLibraries() { + auto dir = std::move(*start_info_.mutable_outgoing_dir()); + InitBuiltinLibrariesForIsolate(url_, namespace_, stdoutfd_, stderrfd_, + nullptr /* environment */, dir.TakeChannel(), + false /* service_isolate */); + + return true; +} + +std::vector DartComponentController_v2::GetArguments() { + return std::vector(); +} + } // namespace dart_runner diff --git a/shell/platform/fuchsia/dart_runner/dart_component_controller.h b/shell/platform/fuchsia/dart_runner/dart_component_controller.h index 24b49a055c..bb210862c1 100644 --- a/shell/platform/fuchsia/dart_runner/dart_component_controller.h +++ b/shell/platform/fuchsia/dart_runner/dart_component_controller.h @@ -7,6 +7,7 @@ #include +#include #include #include #include @@ -21,22 +22,35 @@ namespace dart_runner { -class DartComponentController : public fuchsia::sys::ComponentController { +/// The base class for Dart components. +class DartComponentController { public: - DartComponentController( - fuchsia::sys::Package package, - fuchsia::sys::StartupInfo startup_info, - std::shared_ptr runner_incoming_services, - fidl::InterfaceRequest controller); - ~DartComponentController() override; - + // Called before the application is run. bool Setup(); + + // Calling this method will run the given application void Run(); - bool Main(); - void SendReturnCode(); private: - bool SetupNamespace(); + bool Main(); + + // Override this method to send the return code to the caller. + virtual void SendReturnCode() = 0; + + // Called when the application is starting up. Subclasses should + // populate the namespace and return the pointer. + virtual fdio_ns_t* PrepareNamespace() = 0; + + // Initializes the builtin libraries given the namespace. + virtual bool PrepareBuiltinLibraries() = 0; + + // Returns the file descriptors for stdout/stderr + virtual int GetStdoutFileDescriptor() = 0; + virtual int GetStderrFileDescriptor() = 0; + + // Called by the main method to pass incoming arguments to the dart + // application. + virtual std::vector GetArguments() = 0; bool SetupFromKernel(); bool SetupFromAppSnapshot(); @@ -44,12 +58,6 @@ class DartComponentController : public fuchsia::sys::ComponentController { bool CreateIsolate(const uint8_t* isolate_snapshot_data, const uint8_t* isolate_snapshot_instructions); - int SetupFileDescriptor(fuchsia::sys::FileDescriptorPtr fd); - - // |ComponentController| - void Kill() override; - void Detach() override; - // Idle notification. void MessageEpilogue(Dart_Handle result); void OnIdleTimer(async_dispatcher_t* dispatcher, @@ -57,28 +65,14 @@ class DartComponentController : public fuchsia::sys::ComponentController { zx_status_t status, const zx_packet_signal* signal); - // The loop must be the first declared member so that it gets destroyed after - // binding_ which expects the existence of a loop. - std::unique_ptr loop_; - std::string label_; - std::string url_; - fuchsia::sys::Package package_; - fuchsia::sys::StartupInfo startup_info_; std::shared_ptr runner_incoming_services_; - std::string data_path_; - fidl::Binding binding_; - std::unique_ptr context_; - fdio_ns_t* namespace_ = nullptr; - int stdoutfd_ = -1; - int stderrfd_ = -1; dart_utils::ElfSnapshot elf_snapshot_; // AOT snapshot dart_utils::MappedResource isolate_snapshot_data_; // JIT snapshot dart_utils::MappedResource isolate_snapshot_instructions_; // JIT snapshot std::vector kernel_peices_; Dart_Isolate isolate_; - int32_t return_code_ = 0; zx::time idle_start_{0}; zx::timer idle_timer_; @@ -89,6 +83,99 @@ class DartComponentController : public fuchsia::sys::ComponentController { // Disallow copy and assignment. DartComponentController(const DartComponentController&) = delete; DartComponentController& operator=(const DartComponentController&) = delete; + + protected: + DartComponentController( + std::string resolved_url, + std::shared_ptr runner_incoming_services); + ~DartComponentController(); + + void Shutdown(); + + std::unique_ptr loop_; + std::string label_; + std::string data_path_; + std::string url_; + + int32_t return_code_ = 0; + + fdio_ns_t* namespace_ = nullptr; + int stdoutfd_ = -1; + int stderrfd_ = -1; +}; + +class DartComponentController_v1 : public DartComponentController, + public fuchsia::sys::ComponentController { + public: + DartComponentController_v1( + fuchsia::sys::Package package, + fuchsia::sys::StartupInfo startup_info, + std::shared_ptr runner_incoming_services, + fidl::InterfaceRequest controller); + ~DartComponentController_v1() override; + + private: + // |ComponentController| + void Kill() override; + void Detach() override; + + void SendReturnCode() override; + fdio_ns_t* PrepareNamespace() override; + + int GetStdoutFileDescriptor() override; + int GetStderrFileDescriptor() override; + + bool PrepareBuiltinLibraries() override; + + std::vector GetArguments() override; + + int SetupFileDescriptor(fuchsia::sys::FileDescriptorPtr fd); + + fuchsia::sys::Package package_; + fuchsia::sys::StartupInfo startup_info_; + + fidl::Binding binding_; + + // Disallow copy and assignment. + DartComponentController_v1(const DartComponentController_v1&) = delete; + DartComponentController_v1& operator=(const DartComponentController_v1&) = + delete; +}; + +class DartComponentController_v2 + : public DartComponentController, + public fuchsia::component::runner::ComponentController { + public: + DartComponentController_v2( + fuchsia::component::runner::ComponentStartInfo start_info, + std::shared_ptr runner_incoming_services, + fidl::InterfaceRequest + controller); + ~DartComponentController_v2() override; + + private: + // |fuchsia::component::runner::ComponentController| + void Kill() override; + void Stop() override; + + void SendReturnCode() override; + fdio_ns_t* PrepareNamespace() override; + + int GetStdoutFileDescriptor() override; + int GetStderrFileDescriptor() override; + + bool PrepareBuiltinLibraries() override; + + std::vector GetArguments() override; + + fuchsia::component::runner::ComponentStartInfo start_info_; + + fidl::Binding binding_; + + // Disallow copy and assignment. + DartComponentController_v2(const DartComponentController_v2&) = delete; + DartComponentController_v2& operator=(const DartComponentController_v2&) = + delete; }; } // namespace dart_runner diff --git a/shell/platform/fuchsia/dart_runner/dart_runner.cc b/shell/platform/fuchsia/dart_runner/dart_runner.cc index bfcb00391e..91d88897c2 100644 --- a/shell/platform/fuchsia/dart_runner/dart_runner.cc +++ b/shell/platform/fuchsia/dart_runner/dart_runner.cc @@ -17,6 +17,7 @@ #include #include "dart_component_controller.h" +#include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" #include "logging.h" #include "runtime/dart/utils/inlines.h" @@ -100,6 +101,7 @@ void IsolateGroupCleanupCallback(void* isolate_group_data) { delete static_cast*>(isolate_group_data); } +// RunApplication for a v1 component void RunApplication( DartRunner* runner, fuchsia::sys::Package package, @@ -107,8 +109,32 @@ void RunApplication( std::shared_ptr runner_incoming_services, ::fidl::InterfaceRequest controller) { int64_t start = Dart_TimelineGetMicros(); - DartComponentController app(std::move(package), std::move(startup_info), - runner_incoming_services, std::move(controller)); + DartComponentController_v1 app(std::move(package), std::move(startup_info), + runner_incoming_services, + std::move(controller)); + bool success = app.Setup(); + int64_t end = Dart_TimelineGetMicros(); + Dart_TimelineEvent("DartComponentController::Setup", start, end, + Dart_Timeline_Event_Duration, 0, NULL, NULL); + if (success) { + app.Run(); + } + + if (Dart_CurrentIsolate()) { + Dart_ShutdownIsolate(); + } +} + +// RunApplication for a v2 componeent +void RunApplication2( + DartRunner* runner, + fuchsia::component::runner::ComponentStartInfo start_info, + std::shared_ptr runner_incoming_services, + fidl::InterfaceRequest + controller) { + int64_t start = Dart_TimelineGetMicros(); + DartComponentController_v2 app( + std::move(start_info), runner_incoming_services, std::move(controller)); bool success = app.Setup(); int64_t end = Dart_TimelineGetMicros(); Dart_TimelineEvent("DartComponentController::Setup", start, end, @@ -135,6 +161,13 @@ DartRunner::DartRunner(sys::ComponentContext* context) : context_(context) { bindings_.AddBinding(this, std::move(request)); }); + context_->outgoing() + ->AddPublicService( + [this](fidl::InterfaceRequest< + fuchsia::component::runner::ComponentRunner> request) { + component_runner_bindings_.AddBinding(this, std::move(request)); + }); + #if !defined(DART_PRODUCT) // The VM service isolate uses the process-wide namespace. It writes the // vm service protocol port under /tmp. The VMServiceObject exposes that @@ -207,4 +240,15 @@ void DartRunner::StartComponent( thread.detach(); } +void DartRunner::Start( + fuchsia::component::runner::ComponentStartInfo start_info, + fidl::InterfaceRequest + controller) { + std::string url_copy = start_info.resolved_url(); + TRACE_EVENT1("dart", "Start", "url", url_copy.c_str()); + std::thread thread(RunApplication2, this, std::move(start_info), + context_->svc(), std::move(controller)); + thread.detach(); +} + } // namespace dart_runner diff --git a/shell/platform/fuchsia/dart_runner/dart_runner.h b/shell/platform/fuchsia/dart_runner/dart_runner.h index 8e8b089ec9..9b9dc73e57 100644 --- a/shell/platform/fuchsia/dart_runner/dart_runner.h +++ b/shell/platform/fuchsia/dart_runner/dart_runner.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_RUNNER_DART_RUNNER_H_ #define FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_RUNNER_DART_RUNNER_H_ +#include #include #include #include @@ -13,7 +14,8 @@ namespace dart_runner { -class DartRunner : public fuchsia::sys::Runner { +class DartRunner : public fuchsia::sys::Runner, + public fuchsia::component::runner::ComponentRunner { public: explicit DartRunner(sys::ComponentContext* context); ~DartRunner() override; @@ -26,9 +28,17 @@ class DartRunner : public fuchsia::sys::Runner { ::fidl::InterfaceRequest controller) override; + // |fuchsia::component::runner::ComponentRunner| + void Start( + fuchsia::component::runner::ComponentStartInfo start_info, + fidl::InterfaceRequest + controller) override; + // Not owned by DartRunner. sys::ComponentContext* context_; fidl::BindingSet bindings_; + fidl::BindingSet + component_runner_bindings_; #if !defined(AOT_RUNTIME) dart_utils::MappedResource vm_snapshot_data_; diff --git a/shell/platform/fuchsia/dart_runner/main.cc b/shell/platform/fuchsia/dart_runner/main.cc index 329834db90..6b4fe7af4f 100644 --- a/shell/platform/fuchsia/dart_runner/main.cc +++ b/shell/platform/fuchsia/dart_runner/main.cc @@ -39,6 +39,7 @@ int main(int argc, const char** argv) { // Create our component context which is served later. auto context = sys::ComponentContext::Create(); + dart_utils::RootInspectNode::Initialize(context.get()); auto build_info = dart_utils::RootInspectNode::CreateRootChild("build_info"); dart_utils::BuildInfo::Dump(build_info); diff --git a/shell/platform/fuchsia/dart_runner/meta/common.shard.cml b/shell/platform/fuchsia/dart_runner/meta/common.shard.cml new file mode 100644 index 0000000000..c38f1704ae --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/meta/common.shard.cml @@ -0,0 +1,39 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +{ + capabilities: [ + { + directory: "diagnostics", + rights: [ "connect" ], + path: "/diagnostics", + }, + ], + use: [ + { + directory: "config-data", + rights: [ "r*" ], + path: "/config/data", + }, + { + protocol: [ + "fuchsia.component.runner.ComponentRunner", + "fuchsia.deprecatedtimezone.Timezone", + "fuchsia.feedback.CrashReporter", + "fuchsia.intl.PropertyProvider", + "fuchsia.logger.LogSink", + "fuchsia.net.NameLookup", + "fuchsia.posix.socket.Provider", + "fuchsia.tracing.provider.Registry", + ], + from: "parent", + }, + ], + expose: [ + { + directory: "diagnostics", + from: "self", + to: "framework", + }, + ], +} diff --git a/shell/platform/fuchsia/dart_runner/meta/dart_aot_product_runner.cml b/shell/platform/fuchsia/dart_runner/meta/dart_aot_product_runner.cml new file mode 100644 index 0000000000..5f3e58cea8 --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/meta/dart_aot_product_runner.cml @@ -0,0 +1,24 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +{ + include: [ "common.shard.cml" ], + program: { + runner: "elf", + binary: "bin/app", + forward_stdout_to: "log", + forward_stderr_to: "log", + }, + capabilities: [ + { + runner: "dart_aot_product_runner", + path: "/svc/fuchsia.component.runner.ComponentRunner", + }, + ], + expose: [ + { + runner: "dart_aot_product_runner", + from: "self", + }, + ], +} diff --git a/shell/platform/fuchsia/dart_runner/meta/dart_aot_runner.cml b/shell/platform/fuchsia/dart_runner/meta/dart_aot_runner.cml new file mode 100644 index 0000000000..d884ba849f --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/meta/dart_aot_runner.cml @@ -0,0 +1,24 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +{ + include: [ "common.shard.cml" ], + program: { + runner: "elf", + binary: "bin/app", + forward_stdout_to: "log", + forward_stderr_to: "log", + }, + capabilities: [ + { + runner: "dart_aot_runner", + path: "/svc/fuchsia.component.runner.ComponentRunner", + }, + ], + expose: [ + { + runner: "dart_aot_runner", + from: "self", + }, + ], +} diff --git a/shell/platform/fuchsia/dart_runner/meta/dart_jit_product_runner.cml b/shell/platform/fuchsia/dart_runner/meta/dart_jit_product_runner.cml new file mode 100644 index 0000000000..8dadc78b24 --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/meta/dart_jit_product_runner.cml @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +{ + include: [ "common.shard.cml" ], + program: { + runner: "elf", + binary: "bin/app", + forward_stdout_to: "log", + forward_stderr_to: "log", + // needed for JIT builds + job_policy_ambient_mark_vmo_exec: "true", + }, + capabilities: [ + { + runner: "dart_jit_product_runner", + path: "/svc/fuchsia.component.runner.ComponentRunner", + }, + ], + expose: [ + { + runner: "dart_jit_product_runner", + from: "self", + }, + ], +} diff --git a/shell/platform/fuchsia/dart_runner/meta/dart_jit_runner.cml b/shell/platform/fuchsia/dart_runner/meta/dart_jit_runner.cml new file mode 100644 index 0000000000..6304f182da --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/meta/dart_jit_runner.cml @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +{ + include: [ "common.shard.cml" ], + program: { + runner: "elf", + binary: "bin/app", + forward_stdout_to: "log", + forward_stderr_to: "log", + // needed for JIT builds + job_policy_ambient_mark_vmo_exec: "true", + }, + capabilities: [ + { + runner: "dart_jit_runner", + path: "/svc/fuchsia.component.runner.ComponentRunner", + }, + ], + expose: [ + { + runner: "dart_jit_runner", + from: "self", + }, + ], +} diff --git a/tools/fuchsia/devshell/serve.sh b/tools/fuchsia/devshell/serve.sh index a3e3601284..07d389a13f 100755 --- a/tools/fuchsia/devshell/serve.sh +++ b/tools/fuchsia/devshell/serve.sh @@ -205,6 +205,22 @@ while true; do \"host_match\": \"fuchsia.com\", \"host_replacement\": \"engine\", \"path_prefix_match\": \"/flutter_aot_runner\", \"path_prefix_replacement\": \"/flutter_aot_runner\" }, + { + \"host_match\": \"fuchsia.com\", \"host_replacement\": \"engine\", + \"path_prefix_match\": \"/dart_jit_runner/\", \"path_prefix_replacement\": \"/dart_jit_runner/\" + }, + { + \"host_match\": \"fuchsia.com\", \"host_replacement\": \"engine\", + \"path_prefix_match\": \"/dart_jit_runner\", \"path_prefix_replacement\": \"/dart_jit_runner\" + }, + { + \"host_match\": \"fuchsia.com\", \"host_replacement\": \"engine\", + \"path_prefix_match\": \"/dart_aot_runner/\", \"path_prefix_replacement\": \"/dart_aot_runner/\" + }, + { + \"host_match\": \"fuchsia.com\", \"host_replacement\": \"engine\", + \"path_prefix_match\": \"/dart_aot_runner\", \"path_prefix_replacement\": \"/dart_aot_runner\" + }, { \"host_match\": \"fuchsia.com\", \"host_replacement\": \"devhost\", \"path_prefix_match\": \"/\", \"path_prefix_replacement\": \"/\" diff --git a/tools/fuchsia/fuchsia_archive.gni b/tools/fuchsia/fuchsia_archive.gni index 9a17e8a040..d7d0598add 100644 --- a/tools/fuchsia/fuchsia_archive.gni +++ b/tools/fuchsia/fuchsia_archive.gni @@ -146,6 +146,10 @@ template("fuchsia_archive") { ] sources = copy_outputs + if (defined(invoker.cml_file)) { + sources += [ invoker.cml_file ] + } + inputs = [] if (defined(invoker.inputs)) { inputs += invoker.inputs -- GitLab