blob: 860a4e73a72fe939873c9ee2d2169fd7ae401ca3 [file] [log] [blame]
// Copyright 2021 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 <fuchsia/component/cpp/fidl.h>
#include <fuchsia/io/cpp/fidl.h>
#include <fuchsia/realm/builder/cpp/fidl.h>
#include <fuchsia/sys2/cpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/io.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/sys/cpp/service_directory.h>
#include <lib/sys/cpp/testing/internal/errors.h>
#include <lib/sys/cpp/testing/internal/realm.h>
#include <lib/sys/cpp/testing/internal/scoped_instance.h>
#include <lib/sys/cpp/testing/realm_builder.h>
#include <lib/syslog/cpp/log_level.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/assert.h>
#include <zircon/status.h>
#include <algorithm>
#include <utility>
#include <variant>
namespace sys::testing {
namespace {
constexpr char kCollectionName[] = "fuchsia_component_test_collection";
constexpr char kFrameworkIntermediaryChildName[] = "fuchsia_component_test_framework_intermediary";
constexpr char kRootName[] = "sys_cpp_realm_builder_root";
void PanicIfMonikerBad(Moniker& moniker) {
if (!moniker.path.empty()) {
ZX_ASSERT_MSG(moniker.path.front() != '/', "Moniker %s is invalid. It contains a leading slash",
moniker.path.c_str());
ZX_ASSERT_MSG(moniker.path.back() != '/', "Moniker %s is invalid. It contains a trailing slash",
moniker.path.c_str());
}
}
fuchsia::realm::builder::RouteEndpoint ConvertToFidl(Endpoint endpoint) {
if (auto moniker = std::get_if<Moniker>(&endpoint)) {
return fuchsia::realm::builder::RouteEndpoint::WithComponent(std::move(moniker->path));
}
if (auto _ = std::get_if<AboveRoot>(&endpoint)) {
return fuchsia::realm::builder::RouteEndpoint::WithAboveRoot(
fuchsia::realm::builder::AboveRoot());
}
ZX_PANIC("ConvertToFidl(Endpoint) reached unreachable block!");
}
fuchsia::realm::builder::Capability ConvertToFidl(Capability capability) {
if (auto protocol = std::get_if<Protocol>(&capability)) {
fuchsia::realm::builder::ProtocolCapability fidl_capability;
fidl_capability.set_name(std::move(protocol->name));
return fuchsia::realm::builder::Capability::WithProtocol(std::move(fidl_capability));
}
if (auto directory = std::get_if<Directory>(&capability)) {
fuchsia::realm::builder::DirectoryCapability fidl_capability;
fidl_capability.set_name(std::move(directory->name));
fidl_capability.set_path(std::move(directory->path));
fidl_capability.set_rights(std::move(directory->rights));
return fuchsia::realm::builder::Capability::WithDirectory(std::move(fidl_capability));
}
if (auto storage = std::get_if<Storage>(&capability)) {
fuchsia::realm::builder::StorageCapability fidl_capability;
fidl_capability.set_name(std::move(storage->name));
fidl_capability.set_path(std::move(storage->path));
return fuchsia::realm::builder::Capability::WithStorage(std::move(fidl_capability));
}
ZX_PANIC("ConvertToFidl(Capability) reached unreachable block!");
}
fuchsia::realm::builder::Component ConvertToFidl(Source source) {
fuchsia::realm::builder::Component result;
if (auto url = std::get_if<ComponentUrl>(&source)) {
return fuchsia::realm::builder::Component::WithUrl(std::move(url->url));
}
if (auto url = std::get_if<LegacyComponentUrl>(&source)) {
return fuchsia::realm::builder::Component::WithLegacyUrl(std::move(url->url));
}
ZX_PANIC("ConvertToFidl(Source) reached unreachable block!");
}
fuchsia::realm::builder::CapabilityRoute ConvertToFidl(CapabilityRoute route) {
fuchsia::realm::builder::CapabilityRoute result;
result.set_capability(ConvertToFidl(route.capability));
result.set_source(ConvertToFidl(route.source));
std::vector<fuchsia::realm::builder::RouteEndpoint> targets;
for (const Endpoint& target : route.targets) {
targets.push_back(ConvertToFidl(target));
}
result.set_targets(std::move(targets));
return result;
}
} // namespace
Realm::Realm(internal::ScopedInstance root) : root_(std::move(root)) {}
Realm::Builder::Builder(
fuchsia::realm::builder::FrameworkIntermediarySyncPtr framework_intermediary_proxy,
sys::ServiceDirectory framework_intermediary_exposed_dir)
: realm_commited_(false),
framework_intermediary_proxy_(std::move(framework_intermediary_proxy)),
framework_intermediary_exposed_dir_(std::move(framework_intermediary_exposed_dir)) {}
Realm::Builder& Realm::Builder::AddComponent(Moniker moniker, Component component) {
PanicIfMonikerBad(moniker);
{
bool exists;
ASSERT_STATUS_OK("FrameworkIntemediary/Contains",
framework_intermediary_proxy_->Contains(moniker.path, &exists));
if (exists) {
ZX_PANIC("Attempted to add a moniker that already exists in Realm: '%s'",
moniker.path.c_str());
}
}
{
fuchsia::realm::builder::FrameworkIntermediary_SetComponent_Result result;
ASSERT_STATUS_AND_RESULT_OK("FrameworkIntemediary/SetComponent",
framework_intermediary_proxy_->SetComponent(
moniker.path, ConvertToFidl(component.source), &result),
result);
}
if (component.eager) {
fuchsia::realm::builder::FrameworkIntermediary_MarkAsEager_Result result;
ASSERT_STATUS_AND_RESULT_OK("FrameworkIntermediary/MarkAsEager",
framework_intermediary_proxy_->MarkAsEager(moniker.path, &result),
result);
}
return *this;
}
Realm::Builder& Realm::Builder::AddRoute(CapabilityRoute route) {
fuchsia::realm::builder::FrameworkIntermediary_RouteCapability_Result result;
auto fidl_route = ConvertToFidl(std::move(route));
ASSERT_STATUS_AND_RESULT_OK(
"FrameworkIntermediary/RouteCapability",
framework_intermediary_proxy_->RouteCapability(std::move(fidl_route), &result), result);
return *this;
}
Realm Realm::Builder::Build(const sys::ComponentContext* context) {
ZX_ASSERT_MSG(!realm_commited_, "RealmBuilder::Build() called after Realm already created");
ZX_ASSERT_MSG(context != nullptr, "context passed to RealmBuilder::Build() must not be nullptr");
fuchsia::realm::builder::FrameworkIntermediary_Commit_Result result;
ASSERT_STATUS_AND_RESULT_OK("FrameworkIntemediary/Commit",
framework_intermediary_proxy_->Commit(&result), result);
realm_commited_ = true;
std::string root_component_url = result.response().root_component_url;
return Realm(
internal::ScopedInstance::New(context, kCollectionName, kRootName, root_component_url));
}
Realm::Builder Realm::Builder::New(const sys::ComponentContext* context) {
ZX_ASSERT_MSG(context != nullptr, "context passed to RealmBuilder::New() must not be nullptr");
fuchsia::realm::builder::FrameworkIntermediarySyncPtr proxy;
auto realm = internal::CreateRealmPtr(context);
auto child_ref = fuchsia::sys2::ChildRef{.name = kFrameworkIntermediaryChildName};
auto exposed_dir = internal::BindChild(realm.get(), child_ref);
exposed_dir.Connect(proxy.NewRequest());
return Builder(std::move(proxy), std::move(exposed_dir));
}
} // namespace sys::testing