blob: 5bd9394c8de06bf0ea11dcd279b16fa24562cb85 [file] [log] [blame]
// 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 "garnet/bin/guest/runner/runner_impl.h"
#include <fs/pseudo-dir.h>
#include <fs/remote-dir.h>
#include <fuchsia/guest/vmm/cpp/fidl.h>
#include <lib/async/default.h>
#include <memory>
#include "lib/fxl/logging.h"
#include "lib/svc/cpp/service_provider_bridge.h"
namespace guest_runner {
RunnerImpl::RunnerImpl()
: context_(component::StartupContext::CreateFromStartupInfo()),
vfs_(async_get_default_dispatcher()) {
context_->environment()->GetLauncher(launcher_.NewRequest());
context_->outgoing().AddPublicService(bindings_.GetHandler(this));
}
void RunnerImpl::StartComponent(
fuchsia::sys::Package application, fuchsia::sys::StartupInfo startup_info,
::fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) {
fuchsia::sys::LaunchInfo launch_info;
// Create a bridge between directory_request that we got and vmm's
// directory_request.
fbl::RefPtr<fs::PseudoDir> dir = fbl::AdoptRef(new fs::PseudoDir());
fuchsia::io::DirectoryPtr public_dir;
launch_info.directory_request = public_dir.NewRequest().TakeChannel();
dir->AddEntry(
"public",
fbl::AdoptRef(new fs::RemoteDir(public_dir.Unbind().TakeChannel())));
vfs_.ServeDirectory(std::move(dir),
std::move(startup_info.launch_info.directory_request));
// Pass-through some arguments directly to the vmm package.
launch_info.url = "fuchsia-pkg://fuchsia.com/vmm#meta/vmm.cmx";
launch_info.arguments = std::move(startup_info.launch_info.arguments);
launch_info.flat_namespace = fuchsia::sys::FlatNamespace::New();
for (size_t i = 0; i < startup_info.flat_namespace.paths.size(); ++i) {
const auto& path = startup_info.flat_namespace.paths[i];
if (path == "/pkg") {
// Expose the specific guest package under the /guest namespace.
launch_info.flat_namespace->paths.push_back("/guest");
launch_info.flat_namespace->directories.push_back(
std::move(startup_info.flat_namespace.directories[i]));
} else if (path == "/svc") {
// Hack: We've provided some 'additional_services' to the vmm, but those
// are loaded in the /svc in the provided flat_namespace here. Appmgr
// doesn't allow overriding the /svc namespace of the vmm, instead it
// initialized it to the set of services requested in the vmm.cmx.
//
// The solution here is to invert the dependency between guest_manager and
// the guest_runner. Apps that call the guest_manager directly can just
// embed the artifacts they need into their own package and don't need to
// use a companion guest package. Then the runner can be used for the
// standalone guest packages (ex: linux_guest/zircon_guest).
//
// Note: the leaking of the |ServiceProviderBridge| is intentional. We
// could wrap the ComponentController in one that we retain here so we can
// intercept the error event and cleanup, but since this is temporary we
// can live with this.
//
// See: MAC-181
auto bridge = new component::ServiceProviderBridge;
auto service_list = fuchsia::sys::ServiceList::New();
// This must list every service the vmm depends on. We don't provide
// any implementations here since the ServiceProviderBridge takes care
// of that for us via the backing_dir, which is the above /svc directory.
service_list->names.push_back(
fuchsia::guest::vmm::LaunchInfoProvider::Name_);
bridge->set_backing_dir(
std::move(startup_info.flat_namespace.directories[i]));
service_list->provider = bridge->AddBinding();
launch_info.additional_services = std::move(service_list);
}
}
launcher_->CreateComponent(std::move(launch_info), std::move(controller));
}
} // namespace guest_runner