blob: 106e35a6480b1801cabac7f17b6be379a914f823 [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 <fidl/fuchsia.devfs.test/cpp/wire.h>
#include <fidl/fuchsia.driver.framework/cpp/wire.h>
#include <lib/async/cpp/executor.h>
#include <lib/driver2/devfs_exporter.h>
#include <lib/driver2/logger.h>
#include <lib/driver2/namespace.h>
#include <lib/driver2/promise.h>
#include <lib/driver2/record_cpp.h>
#include <lib/fpromise/bridge.h>
#include <lib/fpromise/scope.h>
#include <lib/sys/component/cpp/outgoing_directory.h>
namespace fdf {
using namespace fuchsia_driver_framework;
} // namespace fdf
namespace fcd = fuchsia_component_decl;
namespace fio = fuchsia_io;
namespace ft = fuchsia_devfs_test;
using fpromise::error;
using fpromise::ok;
using fpromise::promise;
using fpromise::result;
namespace {
class RootDriver : public fidl::WireServer<ft::Device> {
public:
RootDriver(async_dispatcher_t* dispatcher, fidl::WireSharedClient<fdf::Node> node,
driver::Namespace ns, driver::Logger logger, component::OutgoingDirectory outgoing)
: dispatcher_(dispatcher),
executor_(dispatcher),
outgoing_(std::move(outgoing)),
node_(std::move(node)),
ns_(std::move(ns)),
logger_(std::move(logger)) {}
static constexpr const char* Name() { return "root"; }
static zx::status<std::unique_ptr<RootDriver>> Start(fdf::wire::DriverStartArgs& start_args,
fdf::UnownedDispatcher dispatcher,
fidl::WireSharedClient<fdf::Node> node,
driver::Namespace ns,
driver::Logger logger) {
auto outgoing = component::OutgoingDirectory::Create(dispatcher->async_dispatcher());
auto driver =
std::make_unique<RootDriver>(dispatcher->async_dispatcher(), std::move(node), std::move(ns),
std::move(logger), std::move(outgoing));
auto result = driver->Run(std::move(start_args.outgoing_dir()));
if (result.is_error()) {
return result.take_error();
}
return zx::ok(std::move(driver));
}
private:
zx::status<> Run(fidl::ServerEnd<fio::Directory> outgoing_dir) {
// Setup the outgoing directory.
auto status = outgoing_.AddProtocol<ft::Device>(this, Name());
if (status.is_error()) {
return status.take_error();
}
auto serve = outgoing_.Serve(std::move(outgoing_dir));
if (serve.is_error()) {
return serve.take_error();
}
// Create the devfs exporter.
auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
if (endpoints.is_error()) {
return zx::error(endpoints.status_value());
}
status = outgoing_.Serve(std::move(endpoints->server));
if (status.is_error()) {
return status.take_error();
}
auto exporter = driver::DevfsExporter::Create(
ns_, dispatcher_, fidl::WireSharedClient(std::move(endpoints->client), dispatcher_));
if (exporter.is_error()) {
return exporter.take_error();
}
exporter_ = std::move(*exporter);
// Export "root-device" to devfs.
auto task = exporter_.Export(std::string("svc/").append(Name()), "root-device")
.or_else(fit::bind_member(this, &RootDriver::UnbindNode))
.wrap_with(scope_);
executor_.schedule_task(std::move(task));
return zx::ok();
}
result<> UnbindNode(const zx_status_t& status) {
FDF_LOG(ERROR, "Failed to start root driver: %s", zx_status_get_string(status));
node_.AsyncTeardown();
return ok();
}
// fidl::WireServer<ft::Device>
void Ping(PingRequestView request, PingCompleter::Sync& completer) override { completer.Reply(); }
async_dispatcher_t* const dispatcher_;
async::Executor executor_;
component::OutgoingDirectory outgoing_;
fidl::WireSharedClient<fdf::Node> node_;
driver::Namespace ns_;
driver::Logger logger_;
driver::DevfsExporter exporter_;
// NOTE: Must be the last member.
fpromise::scope scope_;
};
} // namespace
FUCHSIA_DRIVER_RECORD_CPP_V1(RootDriver);