blob: 966b2f0e68a20cc61930cdac04291bb95bd0fa86 [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/manager/environment_controller_impl.h"
#include <lib/fit/function.h>
#include <lib/fxl/logging.h>
#include "garnet/bin/guest/manager/guest_services.h"
EnvironmentControllerImpl::EnvironmentControllerImpl(
uint32_t id, const std::string& label, component::StartupContext* context,
fidl::InterfaceRequest<fuchsia::guest::EnvironmentController> request)
: id_(id),
label_(label),
host_vsock_endpoint_(
fit::bind_member(this, &EnvironmentControllerImpl::GetAcceptor)) {
// Create environment.
context->environment()->CreateNestedEnvironment(
env_.NewRequest(), env_controller_.NewRequest(), label,
/*additional_services=*/nullptr, {.inherit_parent_services = true});
env_->GetLauncher(launcher_.NewRequest());
zx::channel h1, h2;
FXL_CHECK(zx::channel::create(0, &h1, &h2) == ZX_OK);
context->environment()->GetDirectory(std::move(h1));
AddBinding(std::move(request));
}
void EnvironmentControllerImpl::set_unbound_handler(
fit::function<void()> handler) {
bindings_.set_empty_set_handler(std::move(handler));
}
void EnvironmentControllerImpl::AddBinding(
fidl::InterfaceRequest<EnvironmentController> request) {
bindings_.AddBinding(this, std::move(request));
}
void EnvironmentControllerImpl::LaunchInstance(
fuchsia::guest::LaunchInfo launch_info,
fidl::InterfaceRequest<fuchsia::guest::InstanceController> controller,
LaunchInstanceCallback callback) {
component::Services services;
fuchsia::sys::ComponentControllerPtr component_controller;
fuchsia::sys::LaunchInfo info;
info.url = launch_info.url;
info.arguments = std::move(launch_info.args);
info.directory_request = services.NewRequest();
info.flat_namespace = std::move(launch_info.flat_namespace);
std::string label =
launch_info.label ? launch_info.label.get() : launch_info.url;
auto guest_services = std::make_unique<GuestServices>(std::move(launch_info));
info.additional_services = guest_services->ServeDirectory();
launcher_->CreateComponent(std::move(info),
component_controller.NewRequest());
services.ConnectToService(std::move(controller));
// Setup guest endpoint.
const uint32_t cid = next_guest_cid_++;
fuchsia::guest::GuestVsockEndpointPtr guest_endpoint;
services.ConnectToService(guest_endpoint.NewRequest());
guest_endpoint.events().OnShutdown =
fit::bind_member(this, &EnvironmentControllerImpl::OnVsockShutdown);
auto endpoint = std::make_unique<GuestVsockEndpoint>(
cid, std::move(guest_endpoint), &host_vsock_endpoint_);
component_controller.set_error_handler(
[this, cid](zx_status_t status) { guests_.erase(cid); });
auto component = std::make_unique<GuestComponent>(
label, std::move(endpoint), std::move(services),
std::move(guest_services), std::move(component_controller));
bool inserted;
std::tie(std::ignore, inserted) = guests_.insert({cid, std::move(component)});
if (!inserted) {
FXL_LOG(ERROR) << "Failed to allocate guest endpoint on CID " << cid;
callback(0);
return;
}
callback(cid);
}
void EnvironmentControllerImpl::OnVsockShutdown(uint32_t src_cid,
uint32_t src_port,
uint32_t dst_cid,
uint32_t dst_port) {
if (src_cid == fuchsia::guest::HOST_CID) {
host_vsock_endpoint_.OnShutdown(src_port);
}
}
void EnvironmentControllerImpl::GetHostVsockEndpoint(
fidl::InterfaceRequest<fuchsia::guest::HostVsockEndpoint> request) {
host_vsock_endpoint_.AddBinding(std::move(request));
}
fidl::VectorPtr<fuchsia::guest::InstanceInfo>
EnvironmentControllerImpl::ListGuests() {
fidl::VectorPtr<fuchsia::guest::InstanceInfo> infos =
fidl::VectorPtr<fuchsia::guest::InstanceInfo>::New(0);
for (const auto& it : guests_) {
infos.push_back(fuchsia::guest::InstanceInfo{
.cid = it.first,
.label = it.second->label(),
});
}
return infos;
}
void EnvironmentControllerImpl::ListInstances(ListInstancesCallback callback) {
callback(ListGuests());
}
void EnvironmentControllerImpl::ConnectToInstance(
uint32_t id,
fidl::InterfaceRequest<fuchsia::guest::InstanceController> request) {
const auto& it = guests_.find(id);
if (it != guests_.end()) {
it->second->ConnectToInstance(std::move(request));
}
}
void EnvironmentControllerImpl::ConnectToBalloon(
uint32_t id,
fidl::InterfaceRequest<fuchsia::guest::BalloonController> request) {
const auto& it = guests_.find(id);
if (it != guests_.end()) {
it->second->ConnectToBalloon(std::move(request));
}
}
fuchsia::guest::GuestVsockAcceptor* EnvironmentControllerImpl::GetAcceptor(
uint32_t cid) {
const auto& it = guests_.find(cid);
return it == guests_.end() ? nullptr : it->second->endpoint();
}