blob: cddab89cf14a4f23e128a6d7d5f46a6ae43b974c [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 "src/virtualization/bin/guest_manager/realm_impl.h"
#include <fuchsia/sys/cpp/fidl.h>
#include <lib/fit/function.h>
#include <lib/syslog/cpp/macros.h>
#include "src/virtualization/bin/guest_manager/guest_services.h"
RealmImpl::RealmImpl(uint32_t id, const std::string& label, sys::ComponentContext* context,
fidl::InterfaceRequest<fuchsia::virtualization::Realm> request)
: id_(id),
label_(label),
host_vsock_endpoint_(fit::bind_member(this, &RealmImpl::GetAcceptor)) {
// Create environment.
fuchsia::sys::EnvironmentPtr environment;
context->svc()->Connect(environment.NewRequest());
environment->CreateNestedEnvironment(env_.NewRequest(), env_controller_.NewRequest(), label,
/*additional_services=*/nullptr,
{.inherit_parent_services = true});
env_->GetLauncher(launcher_.NewRequest());
zx::channel h1, h2;
FX_CHECK(zx::channel::create(0, &h1, &h2) == ZX_OK);
environment->GetDirectory(std::move(h1));
AddBinding(std::move(request));
}
void RealmImpl::set_unbound_handler(fit::function<void()> handler) {
bindings_.set_empty_set_handler(std::move(handler));
}
void RealmImpl::AddBinding(fidl::InterfaceRequest<Realm> request) {
bindings_.AddBinding(this, std::move(request));
}
void RealmImpl::LaunchInstance(std::string url, fidl::StringPtr label,
fuchsia::virtualization::GuestConfig cfg,
fidl::InterfaceRequest<fuchsia::virtualization::Guest> controller,
LaunchInstanceCallback callback) {
fuchsia::sys::ComponentControllerPtr component_controller;
fuchsia::sys::LaunchInfo info;
info.url = url;
auto services = sys::ServiceDirectory::CreateWithRequest(&info.directory_request);
auto guest_services = std::make_unique<GuestServices>(std::move(cfg));
info.additional_services = guest_services->ServeDirectory();
launcher_->CreateComponent(std::move(info), component_controller.NewRequest());
services->Connect(std::move(controller));
// Setup guest endpoint.
const uint32_t cid = next_guest_cid_++;
fuchsia::virtualization::GuestVsockEndpointPtr guest_endpoint;
services->Connect(guest_endpoint.NewRequest());
guest_endpoint.events().OnShutdown = fit::bind_member(this, &RealmImpl::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.value_or(url), 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) {
FX_LOGS(ERROR) << "Failed to allocate guest endpoint on CID " << cid;
callback(0);
return;
}
callback(cid);
}
void RealmImpl::OnVsockShutdown(uint32_t src_cid, uint32_t src_port, uint32_t dst_cid,
uint32_t dst_port) {
if (src_cid == fuchsia::virtualization::HOST_CID) {
host_vsock_endpoint_.OnShutdown(src_port);
}
}
void RealmImpl::GetHostVsockEndpoint(
fidl::InterfaceRequest<fuchsia::virtualization::HostVsockEndpoint> request) {
host_vsock_endpoint_.AddBinding(std::move(request));
}
std::vector<fuchsia::virtualization::InstanceInfo> RealmImpl::ListGuests() {
std::vector<fuchsia::virtualization::InstanceInfo> infos;
for (const auto& it : guests_) {
infos.push_back(fuchsia::virtualization::InstanceInfo{
.cid = it.first,
.label = it.second->label(),
});
}
return infos;
}
void RealmImpl::ListInstances(ListInstancesCallback callback) { callback(ListGuests()); }
void RealmImpl::ConnectToInstance(uint32_t id,
fidl::InterfaceRequest<fuchsia::virtualization::Guest> request) {
const auto& it = guests_.find(id);
if (it != guests_.end()) {
it->second->ConnectToInstance(std::move(request));
}
}
void RealmImpl::ConnectToBalloon(
uint32_t id, fidl::InterfaceRequest<fuchsia::virtualization::BalloonController> request) {
const auto& it = guests_.find(id);
if (it != guests_.end()) {
it->second->ConnectToBalloon(std::move(request));
}
}
fuchsia::virtualization::GuestVsockAcceptor* RealmImpl::GetAcceptor(uint32_t cid) {
const auto& it = guests_.find(cid);
return it == guests_.end() ? nullptr : it->second->endpoint();
}