| // Copyright 2018 The Fuchsia 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 "managed_launcher.h" |
| #include <lib/component/cpp/testing/test_util.h> |
| #include <lib/fdio/io.h> |
| #include <lib/fsl/io/fd.h> |
| #include <lib/fxl/files/unique_fd.h> |
| #include <lib/fxl/logging.h> |
| #include <lib/fxl/strings/concatenate.h> |
| #include <lib/pkg_url/fuchsia_pkg_url.h> |
| #include <zircon/status.h> |
| #include "garnet/lib/cmx/cmx.h" |
| #include "garnet/lib/process/process_builder.h" |
| #include "managed_environment.h" |
| |
| namespace netemul { |
| |
| using fuchsia::sys::TerminationReason; |
| using process::ProcessBuilder; |
| |
| static const char* kVdevRoot = "/vdev"; |
| static const char* kVDataRoot = "/vdata"; |
| |
| static void CreateFlatNamespace(fuchsia::sys::LaunchInfo* linfo) { |
| if (!linfo->flat_namespace) { |
| linfo->flat_namespace = std::make_unique<fuchsia::sys::FlatNamespace>(); |
| } |
| } |
| |
| struct LaunchArgs { |
| fuchsia::sys::LaunchInfo launch_info; |
| fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller; |
| }; |
| |
| void ManagedLauncher::CreateComponent( |
| fuchsia::sys::LaunchInfo launch_info, |
| fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) { |
| // because fuchsia.sys.loader uses legacy callbacks, we need to |
| // save the info in a shared ptr for the closure |
| auto args = std::make_shared<LaunchArgs>(); |
| args->launch_info = std::move(launch_info); |
| args->controller = std::move(controller); |
| |
| // load package information |
| loader_->LoadUrl( |
| args->launch_info.url, [this, args](fuchsia::sys::PackagePtr package) { |
| CreateComponent(std::move(package), std::move(args->launch_info), |
| std::move(args->controller)); |
| }); |
| } |
| |
| ManagedLauncher::ManagedLauncher(ManagedEnvironment* environment) |
| : env_(environment) { |
| env_->environment().ConnectToService(real_launcher_.NewRequest()); |
| env_->environment().ConnectToService(loader_.NewRequest()); |
| } |
| |
| void ManagedLauncher::Bind( |
| fidl::InterfaceRequest<fuchsia::sys::Launcher> request) { |
| bindings_.AddBinding(this, std::move(request)); |
| } |
| |
| void ManagedLauncher::CreateComponent( |
| fuchsia::sys::PackagePtr package, fuchsia::sys::LaunchInfo launch_info, |
| fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) { |
| // Before launching, we'll check the component's sandbox |
| // so we can inject virtual devices |
| if (!package) { |
| FXL_LOG(ERROR) << "Can't load package " << launch_info.url; |
| return; |
| } |
| |
| if (!package->directory.is_valid()) { |
| FXL_LOG(ERROR) << "Package directory not provided"; |
| return; |
| } |
| |
| // let's open and parse the cmx |
| component::FuchsiaPkgUrl fp; |
| if (!fp.Parse(package->resolved_url)) { |
| FXL_LOG(ERROR) << "Can't parse package url " << package->resolved_url; |
| return; |
| } |
| |
| component::CmxMetadata cmx; |
| fxl::UniqueFD fd = |
| fsl::OpenChannelAsFileDescriptor(std::move(package->directory)); |
| |
| json::JSONParser json_parser; |
| if (!cmx.ParseFromFileAt(fd.get(), fp.resource_path(), &json_parser)) { |
| FXL_LOG(ERROR) << "cmx file failed to parse: " << json_parser.error_str(); |
| return; |
| } |
| |
| // we have devices in sandbox meta, here |
| // we just add our own /vdev to the flat namespace |
| // this could be improved by filtering /vdev to requested classes only |
| // like appmgr does, |
| // but seems overkill for testing environments |
| if (!cmx.sandbox_meta().dev().empty()) { |
| CreateFlatNamespace(&launch_info); |
| // add all devices to flat namespace: |
| launch_info.flat_namespace->paths.push_back(kVdevRoot); |
| launch_info.flat_namespace->directories.push_back( |
| env_->OpenVdevDirectory()); |
| } |
| |
| if (cmx.sandbox_meta().HasFeature("persistent-storage")) { |
| CreateFlatNamespace(&launch_info); |
| // add virtual data folder (in-memory fs) to namespace |
| launch_info.flat_namespace->paths.push_back(kVDataRoot); |
| launch_info.flat_namespace->directories.push_back( |
| env_->OpenVdataDirectory()); |
| } |
| |
| if (!launch_info.out) { |
| launch_info.out = component::testing::CloneFileDescriptor(STDOUT_FILENO); |
| } |
| if (!launch_info.err) { |
| launch_info.err = component::testing::CloneFileDescriptor(STDERR_FILENO); |
| } |
| |
| real_launcher_->CreateComponent(std::move(launch_info), |
| std::move(controller)); |
| } |
| |
| ManagedLauncher::~ManagedLauncher() = default; |
| |
| } // namespace netemul |