blob: cca4bf6576b7e37ce6382397c5915bd01a7abce6 [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/component/decl/cpp/fidl.h>
#include <fuchsia/io/cpp/fidl.h>
#include <lib/async/default.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/io.h>
#include <lib/sys/component/cpp/testing/internal/errors.h>
#include <lib/sys/component/cpp/testing/internal/realm.h>
#include <lib/sys/component/cpp/testing/scoped_child.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/sys/cpp/service_directory.h>
#include <zircon/assert.h>
#include <zircon/status.h>
#include <memory>
#include <random>
namespace component_testing {
namespace {
std::size_t random_unsigned() {
std::random_device random_device;
std::mt19937 generator(random_device());
std::uniform_int_distribution<std::size_t> distribution;
return distribution(generator);
}
} // namespace
ScopedChild ScopedChild::New(fuchsia::component::RealmSyncPtr realm_proxy, std::string collection,
std::string url) {
std::string name = "auto-" + std::to_string(random_unsigned());
return New(std::move(realm_proxy), std::move(collection), std::move(name), std::move(url));
}
ScopedChild ScopedChild::New(fuchsia::component::RealmSyncPtr realm_proxy, std::string collection,
std::string name, std::string url) {
internal::CreateChild(realm_proxy.get(), collection, name, std::move(url));
auto exposed_dir = internal::OpenExposedDir(
realm_proxy.get(),
fuchsia::component::decl::ChildRef{.name = name, .collection = collection});
return ScopedChild(sys::ServiceDirectory::CreateFromNamespace(),
fuchsia::component::decl::ChildRef{.name = name, .collection = collection},
std::move(exposed_dir));
}
ScopedChild ScopedChild::New(std::string collection, std::string name, std::string url,
std::shared_ptr<sys::ServiceDirectory> svc) {
fuchsia::component::RealmSyncPtr realm_proxy;
svc->Connect(realm_proxy.NewRequest());
internal::CreateChild(realm_proxy.get(), collection, name, std::move(url));
auto exposed_dir = internal::OpenExposedDir(
realm_proxy.get(),
fuchsia::component::decl::ChildRef{.name = name, .collection = collection});
return ScopedChild(svc,
fuchsia::component::decl::ChildRef{.name = name, .collection = collection},
std::move(exposed_dir));
}
ScopedChild ScopedChild::New(std::string collection, std::string url,
std::shared_ptr<sys::ServiceDirectory> svc) {
std::string name = "auto-" + std::to_string(random_unsigned());
return New(std::move(collection), std::move(name), std::move(url), std::move(svc));
}
ScopedChild::ScopedChild(std::shared_ptr<sys::ServiceDirectory> svc,
fuchsia::component::decl::ChildRef child_ref,
sys::ServiceDirectory exposed_dir)
: svc_(std::move(svc)),
child_ref_(std::move(child_ref)),
exposed_dir_(std::move(exposed_dir)) {}
ScopedChild::~ScopedChild() {
if (has_moved_) {
return;
}
if (dispatcher_) {
fuchsia::component::RealmPtr async_realm_proxy;
svc_->Connect(async_realm_proxy.NewRequest(dispatcher_));
internal::DestroyChild(async_realm_proxy.get(), child_ref_);
} else {
fuchsia::component::RealmSyncPtr sync_realm_proxy;
svc_->Connect(sync_realm_proxy.NewRequest());
internal::DestroyChild(sync_realm_proxy.get(), child_ref_);
}
}
ScopedChild::ScopedChild(ScopedChild&& other) noexcept
: svc_(std::move(other.svc_)),
child_ref_(std::move(other.child_ref_)),
exposed_dir_(std::move(other.exposed_dir_)),
dispatcher_(other.dispatcher_) {
other.has_moved_ = true;
}
ScopedChild& ScopedChild::operator=(ScopedChild&& other) noexcept {
this->svc_ = std::move(other.svc_);
this->child_ref_ = std::move(other.child_ref_);
this->exposed_dir_ = std::move(other.exposed_dir_);
this->dispatcher_ = other.dispatcher_;
other.has_moved_ = true;
return *this;
}
void ScopedChild::MakeTeardownAsync(async_dispatcher_t* dispatcher) {
if (dispatcher == nullptr) {
dispatcher = async_get_default_dispatcher();
}
dispatcher_ = dispatcher;
}
zx_status_t ScopedChild::Connect(const std::string& interface_name, zx::channel request) const {
return this->exposed_dir_.Connect(interface_name, std::move(request));
}
std::string ScopedChild::GetChildName() const { return child_ref_.name; }
} // namespace component_testing