diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index eb0d510e1831a..2b00cf830cf8f 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1367,6 +1367,10 @@ FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/builtin_libraries.cc FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/builtin_libraries.h FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/dart_component_controller.cc FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/dart_component_controller.h +FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/dart_component_controller_v1.cc +FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/dart_component_controller_v1.h +FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/dart_component_controller_v2.cc +FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/dart_component_controller_v2.h FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/dart_runner.cc FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/dart_runner.h FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/embedder/builtin.dart @@ -1392,6 +1396,8 @@ FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/dart_jit_runner.c FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/dart_zircon_test.cmx FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/jit_product_runtime FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/meta/jit_runtime +FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/parse_url.cc +FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/parse_url.h FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/service_isolate.cc FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/service_isolate.h FILE: ../../../flutter/shell/platform/fuchsia/dart_runner/vmservice/empty.dart 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 2857a5a7c3afe..9ac85679c7b5d 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 c4990c7bc9258..714483fa06451 100644 --- a/shell/platform/fuchsia/dart_runner/BUILD.gn +++ b/shell/platform/fuchsia/dart_runner/BUILD.gn @@ -38,10 +38,16 @@ template("runner") { "builtin_libraries.h", "dart_component_controller.cc", "dart_component_controller.h", + "dart_component_controller_v1.cc", + "dart_component_controller_v1.h", + "dart_component_controller_v2.cc", + "dart_component_controller_v2.h", "dart_runner.cc", "dart_runner.h", "logging.h", "main.cc", + "parse_url.cc", + "parse_url.h", "service_isolate.cc", "service_isolate.h", ] @@ -69,6 +75,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", @@ -160,6 +167,7 @@ template("aot_runner_package") { binary = "dart_aot${product_suffix}_runner" cmx_file = rebase_path("meta/dart_aot${product_suffix}_runner.cmx") + cml_file = rebase_path("meta/dart_aot${product_suffix}_runner.cml") libraries = _common_runner_libs @@ -220,6 +228,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_runner_libs diff --git a/shell/platform/fuchsia/dart_runner/dart_component_controller.cc b/shell/platform/fuchsia/dart_runner/dart_component_controller.cc index dd9b16bd65aee..f536cbeb2a495 100644 --- a/shell/platform/fuchsia/dart_runner/dart_component_controller.cc +++ b/shell/platform/fuchsia/dart_runner/dart_component_controller.cc @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -25,10 +24,14 @@ #include #include +#include "builtin_libraries.h" +#include "logging.h" +#include "parse_url.h" + +#include "flutter/fml/logging.h" #include "runtime/dart/utils/files.h" #include "runtime/dart/utils/handle_exception.h" #include "runtime/dart/utils/inlines.h" -#include "runtime/dart/utils/tempfs.h" #include "third_party/dart/runtime/include/dart_tools_api.h" #include "third_party/tonic/converter/dart_converter.h" #include "third_party/tonic/dart_message_handler.h" @@ -36,15 +39,10 @@ #include "third_party/tonic/dart_state.h" #include "third_party/tonic/logging/dart_error.h" -#include "builtin_libraries.h" -#include "logging.h" - using tonic::ToDart; namespace dart_runner { -constexpr char kDataKey[] = "data"; - namespace { void AfterTask(async_loop_t*, void*) { @@ -67,74 +65,17 @@ constexpr async_loop_config_t kLoopConfig = { .epilogue = &AfterTask, }; -// Find the last path component. -// fuchsia-pkg://fuchsia.com/hello_dart#meta/hello_dart.cmx -> hello_dart.cmx -std::string GetLabelFromURL(const std::string& url) { - for (size_t i = url.length() - 1; i > 0; i--) { - if (url[i] == '/') { - return url.substr(i + 1, url.length() - 1); - } - } - 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; - } - } - 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()); - } -} - -DartComponentController::~DartComponentController() { - if (namespace_) { - fdio_ns_destroy(namespace_); - namespace_ = nullptr; - } - close(stdoutfd_); - close(stderrfd_); -} - 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; } @@ -153,45 +94,33 @@ bool DartComponentController::Setup() { return true; } -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) + : loop_(std::make_unique(&kLoopConfig)), + label_(GetLabelFromUrl(resolved_url)), + url_(resolved_url), + runner_incoming_services_(runner_incoming_services) { + const 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() { @@ -250,6 +179,7 @@ bool DartComponentController::SetupFromKernel() { kernel_peices_.emplace_back(std::move(kernel)); } + Dart_SetRootLibrary(library); Dart_Handle result = Dart_FinalizeLoading(false); @@ -292,22 +222,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 +230,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 +238,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; @@ -344,7 +260,7 @@ bool DartComponentController::CreateIsolate( void DartComponentController::Run() { async::PostTask(loop_->dispatcher(), [loop = loop_.get(), app = this] { - if (!app->Main()) { + if (!app->RunDartMain()) { loop->Quit(); } }); @@ -352,41 +268,27 @@ void DartComponentController::Run() { SendReturnCode(); } -bool DartComponentController::Main() { +bool DartComponentController::RunDartMain() { + FML_CHECK(namespace_ != nullptr); Dart_EnterScope(); tonic::DartMicrotaskQueue::StartForCurrentThread(); - std::vector arguments = - startup_info_.launch_info.arguments.value_or(std::vector()); - - 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); - - 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"); + const std::vector arguments = GetArguments(); + + stdoutfd_ = GetStdoutFileDescriptor(); + stderrfd_ = GetStderrFileDescriptor(); + + 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; + // The namespace pointer must be reset before the next run. Attempting + // to allocate a namespace into a non-null pointer will result in an invalid + // namespace, preventing files from opening on future runs (see fxb/82557). + // namespace_ = nullptr; Dart_ExitScope(); Dart_ExitIsolate(); @@ -420,6 +322,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 +341,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 +402,23 @@ 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(); + } +} + } // 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 24b49a055c9dd..d3a90748c41c0 100644 --- a/shell/platform/fuchsia/dart_runner/dart_component_controller.h +++ b/shell/platform/fuchsia/dart_runner/dart_component_controller.h @@ -21,22 +21,59 @@ 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(); + + protected: + static constexpr char kComponentTmpPath[] = "/tmp"; + static constexpr char kServiceRootPath[] = "/svc"; + + 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; private: - bool SetupNamespace(); + /// Runs the Dart component. Returns true if the component ran and + /// the main result was successful, otherwise false. + bool RunDartMain(); + + /// 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 +81,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 +88,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_; diff --git a/shell/platform/fuchsia/dart_runner/dart_component_controller_v1.cc b/shell/platform/fuchsia/dart_runner/dart_component_controller_v1.cc new file mode 100644 index 0000000000000..84af08f0464ab --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/dart_component_controller_v1.cc @@ -0,0 +1,165 @@ +// 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 "dart_component_controller_v1.h" + +#include +#include +#include +#include + +#include "builtin_libraries.h" +#include "logging.h" + +#include "runtime/dart/utils/tempfs.h" + +namespace dart_runner { + +namespace { + +constexpr char kDataKey[] = "data"; + +} // namespace + +DartComponentControllerV1::DartComponentControllerV1( + 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(); }); + } +} + +DartComponentControllerV1::~DartComponentControllerV1() {} + +void DartComponentControllerV1::Kill() { + Shutdown(); +} + +void DartComponentControllerV1::Detach() { + binding_.set_error_handler([](zx_status_t status) {}); +} + +void DartComponentControllerV1::SendReturnCode() { + binding_.events().OnTerminated(return_code_, + fuchsia::sys::TerminationReason::EXITED); +} + +fdio_ns_t* DartComponentControllerV1::PrepareNamespace() { + fdio_ns_t* ns = nullptr; + 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) == kComponentTmpPath) { + // /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 DartComponentControllerV1::GetStdoutFileDescriptor() { + return SetupFileDescriptor(std::move(startup_info_.launch_info.out)); +} + +int DartComponentControllerV1::GetStderrFileDescriptor() { + return SetupFileDescriptor(std::move(startup_info_.launch_info.err)); +} + +int DartComponentControllerV1::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 DartComponentControllerV1::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 DartComponentControllerV1::GetArguments() { + return startup_info_.launch_info.arguments.value_or( + std::vector()); +} + +} // namespace dart_runner diff --git a/shell/platform/fuchsia/dart_runner/dart_component_controller_v1.h b/shell/platform/fuchsia/dart_runner/dart_component_controller_v1.h new file mode 100644 index 0000000000000..8221cac929a42 --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/dart_component_controller_v1.h @@ -0,0 +1,56 @@ +// 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. + +#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_RUNNER_DART_COMPONENT_CONTROLLER_V1_H_ +#define FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_RUNNER_DART_COMPONENT_CONTROLLER_V1_H_ + +#include +#include +#include + +#include "dart_component_controller.h" + +namespace dart_runner { + +class DartComponentControllerV1 : public DartComponentController, + public fuchsia::sys::ComponentController { + public: + DartComponentControllerV1( + fuchsia::sys::Package package, + fuchsia::sys::StartupInfo startup_info, + std::shared_ptr runner_incoming_services, + fidl::InterfaceRequest controller); + ~DartComponentControllerV1() 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. + DartComponentControllerV1(const DartComponentControllerV1&) = delete; + DartComponentControllerV1& operator=(const DartComponentControllerV1&) = + delete; +}; + +} // namespace dart_runner + +#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_RUNNER_DART_COMPONENT_CONTROLLER_V1_H_ diff --git a/shell/platform/fuchsia/dart_runner/dart_component_controller_v2.cc b/shell/platform/fuchsia/dart_runner/dart_component_controller_v2.cc new file mode 100644 index 0000000000000..cf07d6098f0d9 --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/dart_component_controller_v2.cc @@ -0,0 +1,113 @@ +// 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 "dart_component_controller_v2.h" + +#include +#include + +#include "builtin_libraries.h" +#include "logging.h" +#include "parse_url.h" + +#include "runtime/dart/utils/tempfs.h" + +namespace dart_runner { + +DartComponentControllerV2::DartComponentControllerV2( + 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) { + const std::string 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(); }); + } +} + +DartComponentControllerV2::~DartComponentControllerV2() {} + +void DartComponentControllerV2::Kill() { + binding_.set_error_handler([](zx_status_t status) {}); + Shutdown(); +} + +void DartComponentControllerV2::Stop() { + Kill(); +} + +void DartComponentControllerV2::SendReturnCode() { + if (binding_.is_bound()) { + binding_.Close(return_code_); + } +} + +fdio_ns_t* DartComponentControllerV2::PrepareNamespace() { + fdio_ns_t* ns; + const 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() == kComponentTmpPath) { + // /tmp is covered by the local memfs. + continue; + } + + auto dir = std::move(*ns_entry.mutable_directory()); + auto path = std::move(*ns_entry.mutable_path()); + + const 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 DartComponentControllerV2::GetStdoutFileDescriptor() { + return fileno(stdout); +} + +int DartComponentControllerV2::GetStderrFileDescriptor() { + return fileno(stderr); +} + +bool DartComponentControllerV2::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 DartComponentControllerV2::GetArguments() { + return std::vector(); +} + +} // namespace dart_runner diff --git a/shell/platform/fuchsia/dart_runner/dart_component_controller_v2.h b/shell/platform/fuchsia/dart_runner/dart_component_controller_v2.h new file mode 100644 index 0000000000000..9fabac5372003 --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/dart_component_controller_v2.h @@ -0,0 +1,54 @@ +// 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. + +#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_RUNNER_DART_COMPONENT_CONTROLLER_V2_H_ +#define FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_RUNNER_DART_COMPONENT_CONTROLLER_V2_H_ + +#include +#include +#include + +#include "dart_component_controller.h" + +namespace dart_runner { + +class DartComponentControllerV2 + : public DartComponentController, + public fuchsia::component::runner::ComponentController { + public: + DartComponentControllerV2( + fuchsia::component::runner::ComponentStartInfo start_info, + std::shared_ptr runner_incoming_services, + fidl::InterfaceRequest + controller); + ~DartComponentControllerV2() override; + + private: + // |fuchsia::component::runner::ComponentController| implementation: + 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. + DartComponentControllerV2(const DartComponentControllerV2&) = delete; + DartComponentControllerV2& operator=(const DartComponentControllerV2&) = + delete; +}; + +} // namespace dart_runner + +#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_RUNNER_DART_COMPONENT_CONTROLLER_V2_H_ diff --git a/shell/platform/fuchsia/dart_runner/dart_runner.cc b/shell/platform/fuchsia/dart_runner/dart_runner.cc index bfcb00391ed71..6aae3901b9560 100644 --- a/shell/platform/fuchsia/dart_runner/dart_runner.cc +++ b/shell/platform/fuchsia/dart_runner/dart_runner.cc @@ -17,6 +17,9 @@ #include #include "dart_component_controller.h" +#include "dart_component_controller_v1.h" +#include "dart_component_controller_v2.h" +#include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" #include "logging.h" #include "runtime/dart/utils/inlines.h" @@ -100,15 +103,17 @@ void IsolateGroupCleanupCallback(void* isolate_group_data) { delete static_cast*>(isolate_group_data); } -void RunApplication( +// RunApplication for a v1 component +void RunApplicationV1( DartRunner* runner, fuchsia::sys::Package package, fuchsia::sys::StartupInfo startup_info, 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)); + DartComponentControllerV1 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, @@ -122,11 +127,49 @@ void RunApplication( } } +// RunApplication for a v2 componeent +void RunApplicationV2( + DartRunner* runner, + fuchsia::component::runner::ComponentStartInfo start_info, + std::shared_ptr runner_incoming_services, + fidl::InterfaceRequest + controller) { + const int64_t start = Dart_TimelineGetMicros(); + DartComponentControllerV2 app(std::move(start_info), runner_incoming_services, + std::move(controller)); + const bool success = app.Setup(); + const 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(); + } +} bool EntropySource(uint8_t* buffer, intptr_t count) { zx_cprng_draw(buffer, count); return true; } +void SetProcessName() { + std::stringstream stream; +#if defined(DART_PRODUCT) + stream << "io.flutter.product_runner_dart_akbiggs."; +#else + stream << "io.flutter.runner_dart_akbiggs."; +#endif + if (flutter::DartVM::IsRunningPrecompiledCode()) { + stream << "aot"; + } else { + stream << "jit"; + } + const auto name = stream.str(); + zx::process::self()->set_property(ZX_PROP_NAME, name.c_str(), name.size()); +} + } // namespace DartRunner::DartRunner(sys::ComponentContext* context) : context_(context) { @@ -135,6 +178,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 @@ -153,6 +203,8 @@ DartRunner::DartRunner(sys::ComponentContext* context) : context_(context) { FX_LOGF(FATAL, LOG_TAG, "Dart_SetVMFlags failed: %s", error); } + SetProcessName(); + Dart_InitializeParams params = {}; params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; #if defined(AOT_RUNTIME) @@ -201,10 +253,21 @@ void DartRunner::StartComponent( // eagerly. std::string url_copy = package.resolved_url; TRACE_EVENT1("dart", "StartComponent", "url", url_copy.c_str()); - std::thread thread(RunApplication, this, std::move(package), + std::thread thread(RunApplicationV1, this, std::move(package), std::move(startup_info), context_->svc(), std::move(controller)); 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(RunApplicationV2, 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 8e8b089ec9a49..807354b1e3282 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| implementation: + 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/parse_url.cc b/shell/platform/fuchsia/dart_runner/parse_url.cc new file mode 100644 index 0000000000000..4b99a6299a4c8 --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/parse_url.cc @@ -0,0 +1,30 @@ +#include "parse_url.h" + +#include +#include +#include + +namespace dart_runner { + +std::string GetLabelFromUrl(const std::string& url) { + for (size_t i = url.length() - 1; i > 0; i--) { + if (url[i] == '/') { + return url.substr(i + 1, url.length() - 1); + } + } + return url; +} + +// 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) { + const std::string label = GetLabelFromUrl(url); + for (size_t i = 0; i < label.length(); ++i) { + if (label[i] == '.') { + return label.substr(0, i); + } + } + return label; +} + +} // namespace dart_runner diff --git a/shell/platform/fuchsia/dart_runner/parse_url.h b/shell/platform/fuchsia/dart_runner/parse_url.h new file mode 100644 index 0000000000000..650b74c4d72ec --- /dev/null +++ b/shell/platform/fuchsia/dart_runner/parse_url.h @@ -0,0 +1,22 @@ +// 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. + +#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_RUNNER_PARSE_URL_H_ +#define FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_RUNNER_PARSE_URL_H_ + +#include + +namespace dart_runner { + +// Find the last path of the component. +// fuchsia-pkg://fuchsia.com/hello_dart#meta/hello_dart.cmx -> hello_dart.cmx +std::string GetLabelFromUrl(const std::string& url); + +// 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); + +} // namespace dart_runner + +#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_RUNNER_PARSE_URL_H_ diff --git a/shell/platform/fuchsia/flutter/runner.cc b/shell/platform/fuchsia/flutter/runner.cc index 86e6dfbb6e047..e423d6a29aa46 100644 --- a/shell/platform/fuchsia/flutter/runner.cc +++ b/shell/platform/fuchsia/flutter/runner.cc @@ -118,9 +118,9 @@ bool InitializeICU() { static void SetProcessName() { std::stringstream stream; #if defined(DART_PRODUCT) - stream << "io.flutter.product_runner."; + stream << "io.flutter.product_runner_akbiggs."; #else - stream << "io.flutter.runner."; + stream << "io.flutter.runner_akbiggs."; #endif if (flutter::DartVM::IsRunningPrecompiledCode()) { stream << "aot"; diff --git a/tools/fuchsia/devshell/serve.sh b/tools/fuchsia/devshell/serve.sh index 07d389a13f64c..9052295e86704 100755 --- a/tools/fuchsia/devshell/serve.sh +++ b/tools/fuchsia/devshell/serve.sh @@ -221,6 +221,22 @@ while true; do \"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_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 eb0d1b9807edd..b63c04a6bb301 100644 --- a/tools/fuchsia/fuchsia_archive.gni +++ b/tools/fuchsia/fuchsia_archive.gni @@ -129,7 +129,11 @@ template("_fuchsia_archive") { ":${target_name}_dir", ":${_dbg_symbols_target}", ] + sources = copy_outputs + if (defined(invoker.cml_file)) { + sources += [ invoker.cml_file ] + } inputs = [] if (defined(invoker.inputs)) {