| // 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(); |
| } |