blob: 89ff77fe122c91105f1d8e7ba00cd458f5eac4e6 [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 "include/lib/devmgr-integration-test/fixture.h"
#include <fidl/fuchsia.driver.framework/cpp/wire.h>
#include <fuchsia/driver/test/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/cpp/wait.h>
#include <lib/async/dispatcher.h>
#include <lib/driver_test_realm/realm_builder/cpp/lib.h>
#include <lib/fdio/cpp/caller.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <lib/fidl-async/bind.h>
#include <lib/fidl-async/cpp/bind.h>
#include <lib/vfs/cpp/remote_dir.h>
#include <stdint.h>
#include <zircon/status.h>
#include <fbl/ref_ptr.h>
namespace devmgr_integration_test {
namespace {
constexpr std::string_view kBootPath = "/boot/";
constexpr std::string_view kBootUrlPrefix = "fuchsia-boot:///#";
std::string PathToUrl(std::string_view path) {
if (path.find(kBootUrlPrefix) == 0) {
return std::string(path);
}
if (path.find(kBootPath) != 0) {
ZX_ASSERT_MSG(false, "Driver path to devmgr-launcher must start with /boot/!");
}
return std::string(kBootUrlPrefix).append(path.substr(kBootPath.size()));
}
} // namespace
__EXPORT
zx_status_t IsolatedDevmgr::AddDevfsToOutgoingDir(vfs::PseudoDir* outgoing_root_dir) {
zx::channel client, server;
auto status = zx::channel::create(0, &client, &server);
if (status != ZX_OK) {
return status;
}
fdio_cpp::UnownedFdioCaller fd(devfs_root_.get());
fdio_service_clone_to(fd.borrow_channel(), server.release());
// Add devfs to out directory.
auto devfs_out = std::make_unique<vfs::RemoteDir>(std::move(client));
outgoing_root_dir->AddEntry("dev", std::move(devfs_out));
return ZX_OK;
}
__EXPORT
devmgr_launcher::Args IsolatedDevmgr::DefaultArgs() {
devmgr_launcher::Args args;
args.sys_device_driver = "/boot/driver/sysdev.so";
return args;
}
__EXPORT
IsolatedDevmgr::IsolatedDevmgr() = default;
__EXPORT
zx_status_t IsolatedDevmgr::Create(devmgr_launcher::Args args, IsolatedDevmgr* out) {
return Create(std::move(args), nullptr, out);
}
__EXPORT
zx_status_t IsolatedDevmgr::Create(devmgr_launcher::Args args, async_dispatcher_t* dispatcher,
IsolatedDevmgr* out) {
IsolatedDevmgr devmgr;
devmgr.loop_ = std::make_unique<async::Loop>(&kAsyncLoopConfigNoAttachToCurrentThread);
// Create and build the realm.
auto realm_builder = component_testing::RealmBuilder::Create();
driver_test_realm::Setup(realm_builder);
devmgr.realm_ = std::make_unique<component_testing::RealmRoot>(
realm_builder.Build(devmgr.loop_->dispatcher()));
// Start DriverTestRealm.
fidl::SynchronousInterfacePtr<fuchsia::driver::test::Realm> driver_test_realm;
zx_status_t status = devmgr.realm_->Connect(driver_test_realm.NewRequest());
if (status != ZX_OK) {
return status;
}
fuchsia::driver::test::Realm_Start_Result realm_result;
auto realm_args = fuchsia::driver::test::RealmArgs();
realm_args.set_root_driver(PathToUrl(args.sys_device_driver));
realm_args.set_driver_tests_enable_all(args.driver_tests_enable_all);
realm_args.set_driver_tests_enable(args.driver_tests_enable);
realm_args.set_driver_tests_disable(args.driver_tests_disable);
status = driver_test_realm->Start(std::move(realm_args), &realm_result);
if (status != ZX_OK) {
return status;
}
if (realm_result.is_err()) {
return realm_result.err();
}
// Connect to dev.
fidl::InterfaceHandle<fuchsia::io::Directory> dev;
status = devmgr.realm_->Connect("dev", dev.NewRequest().TakeChannel());
if (status != ZX_OK) {
return status;
}
status = fdio_fd_create(dev.TakeChannel().release(), devmgr.devfs_root_.reset_and_get_address());
if (status != ZX_OK) {
return status;
}
*out = std::move(devmgr);
return ZX_OK;
}
IsolatedDevmgr::IsolatedDevmgr(IsolatedDevmgr&& other)
: loop_(std::move(other.loop_)),
realm_(std::move(other.realm_)),
devfs_root_(std::move(other.devfs_root_)) {}
__EXPORT
IsolatedDevmgr& IsolatedDevmgr::operator=(IsolatedDevmgr&& other) {
// Order is important here. `realm_` must be moved first because its
// destructor depends on a reference to `loop_`. If we destroy `loop_`
// first, we'll encounter a use-after-free failure.
realm_ = std::move(other.realm_);
loop_ = std::move(other.loop_);
devfs_root_ = std::move(other.devfs_root_);
return *this;
}
__EXPORT
IsolatedDevmgr::~IsolatedDevmgr() = default;
} // namespace devmgr_integration_test