| // Copyright 2023 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.power.broker/cpp/fidl.h> |
| #include <lib/driver/component/cpp/driver_base.h> |
| #include <lib/driver/component/cpp/internal/start_args.h> |
| #include <lib/driver/logging/cpp/logger.h> |
| #include <lib/inspect/component/cpp/component.h> |
| #include <zircon/availability.h> |
| |
| namespace fdf { |
| |
| #if FUCHSIA_API_LEVEL_LESS_THAN(29) |
| __WEAK bool logger_wait_for_initial_interest = true; |
| #endif |
| |
| DriverBase::DriverBase(std::string_view name, DriverStartArgs start_args, |
| fdf::UnownedSynchronizedDispatcher driver_dispatcher) |
| : name_(name), |
| start_args_(std::move(start_args)), |
| driver_dispatcher_(std::move(driver_dispatcher)) { |
| Namespace incoming = [ns = std::move(start_args_.incoming())]() mutable { |
| ZX_ASSERT(ns.has_value()); |
| zx::result incoming = Namespace::Create(ns.value()); |
| ZX_ASSERT_MSG(incoming.is_ok(), "%s", incoming.status_string()); |
| return std::move(incoming.value()); |
| }(); |
| logger_ = [&incoming, this]() { |
| auto logger = Logger::Create2(incoming, dispatcher(), name_, FUCHSIA_LOG_INFO |
| #if FUCHSIA_API_LEVEL_LESS_THAN(29) |
| , |
| logger_wait_for_initial_interest |
| #endif |
| ); |
| return logger; |
| }(); |
| Logger::SetGlobalInstance(logger_.get()); |
| std::optional outgoing_request = std::move(start_args_.outgoing_dir()); |
| ZX_ASSERT(outgoing_request.has_value()); |
| InitializeAndServe(std::move(incoming), std::move(outgoing_request.value())); |
| |
| zx::result val = fdf_internal::ProgramValue(program(), "service_connect_validation"); |
| if (val.is_ok() && val.value() == "true") { |
| EnableServiceValidator(); |
| } |
| } |
| |
| void DriverBase::RegisterInitMethods(InitMethodCallback cb) { |
| init_methods_.push_back(std::move(cb)); |
| } |
| |
| zx::result<> DriverBase::RunInitMethods() { |
| for (auto& method : init_methods_) { |
| zx::result result = method(dispatcher(), *incoming(), name()); |
| if (result.is_error()) { |
| return result.take_error(); |
| } |
| } |
| return zx::ok(); |
| } |
| |
| #if FUCHSIA_API_LEVEL_AT_LEAST(HEAD) |
| std::optional<fidl::ServerEnd<fuchsia_power_broker::ElementRunner>> |
| DriverBase::take_power_element_runner() { |
| if (!start_args_.power_element_args().has_value()) { |
| return std::nullopt; |
| } |
| |
| return fidl::ServerEnd<fuchsia_power_broker::ElementRunner>( |
| start_args_.power_element_args()->runner_server()->TakeChannel()); |
| } |
| |
| std::optional<fidl::ClientEnd<fuchsia_power_broker::Lessor>> |
| DriverBase::take_power_element_lessor() { |
| if (!start_args_.power_element_args().has_value()) { |
| return std::nullopt; |
| } |
| |
| return fidl::ClientEnd<fuchsia_power_broker::Lessor>( |
| std::move(start_args_.power_element_args()->lessor_client().value())); |
| } |
| |
| std::optional<fuchsia_power_broker::DependencyToken> DriverBase::power_element_token() { |
| if (!start_args_.power_element_args().has_value()) { |
| return std::nullopt; |
| } |
| |
| zx::event copy; |
| ZX_ASSERT(start_args_.power_element_args()->token()->duplicate(ZX_RIGHT_SAME_RIGHTS, ©) != |
| ZX_OK); |
| |
| return fuchsia_power_broker::DependencyToken(std::move(copy)); |
| } |
| #endif |
| |
| void DriverBase::InitializeAndServe( |
| Namespace incoming, fidl::ServerEnd<fuchsia_io::Directory> outgoing_directory_request) { |
| incoming_ = std::make_shared<Namespace>(std::move(incoming)); |
| outgoing_ = |
| std::make_shared<OutgoingDirectory>(OutgoingDirectory::Create(driver_dispatcher_->get())); |
| ZX_ASSERT(outgoing_->Serve(std::move(outgoing_directory_request)).is_ok()); |
| } |
| |
| void DriverBase::EnableServiceValidator() { |
| if (start_args_.node_offers().has_value()) { |
| incoming_->SetServiceValidator( |
| std::make_optional<ServiceValidator>(start_args_.node_offers().value())); |
| } else { |
| FDF_LOGL(INFO, *logger_, "No node_offers available, not able to enable service validation."); |
| } |
| } |
| |
| void DriverBase::InitInspectorExactlyOnce(inspect::Inspector inspector) { |
| std::call_once(init_inspector_once_, [&] { |
| inspector_.emplace( |
| dispatcher(), inspect::PublishOptions{ |
| .inspector = std::move(inspector), |
| .tree_name = {name_}, |
| .client_end = incoming()->Connect<fuchsia_inspect::InspectSink>().value(), |
| }); |
| }); |
| } |
| |
| #if FUCHSIA_API_LEVEL_AT_MOST(26) |
| cpp20::span<const fuchsia_driver_framework::NodeProperty> DriverBase::node_properties( |
| const std::string& parent_node_name) const { |
| const auto& node_properties = start_args_.node_properties(); |
| if (node_properties.has_value()) { |
| for (const auto& entry : node_properties.value()) { |
| if (entry.name() == parent_node_name) { |
| return entry.properties(); |
| } |
| } |
| } |
| return {}; |
| } |
| #endif |
| |
| zx::result<OwnedChildNode> DriverBase::AddOwnedChild(std::string_view node_name) { |
| return fdf::AddOwnedChild(node(), logger(), node_name); |
| } |
| |
| zx::result<fidl::ClientEnd<fuchsia_driver_framework::NodeController>> DriverBase::AddChild( |
| std::string_view node_name, |
| cpp20::span<const fuchsia_driver_framework::NodeProperty> properties, |
| cpp20::span<const fuchsia_driver_framework::Offer> offers) { |
| return fdf::AddChild(node(), logger(), node_name, properties, offers); |
| } |
| |
| zx::result<OwnedChildNode> DriverBase::AddOwnedChild( |
| std::string_view node_name, fuchsia_driver_framework::DevfsAddArgs& devfs_args) { |
| return fdf::AddOwnedChild(node(), logger(), node_name, devfs_args); |
| } |
| |
| zx::result<fidl::ClientEnd<fuchsia_driver_framework::NodeController>> DriverBase::AddChild( |
| std::string_view node_name, fuchsia_driver_framework::DevfsAddArgs& devfs_args, |
| cpp20::span<const fuchsia_driver_framework::NodeProperty> properties, |
| cpp20::span<const fuchsia_driver_framework::Offer> offers) { |
| return fdf::AddChild(node(), logger(), node_name, devfs_args, properties, offers); |
| } |
| |
| zx::result<fidl::ClientEnd<fuchsia_driver_framework::NodeController>> DriverBase::AddChild( |
| std::string_view node_name, |
| cpp20::span<const fuchsia_driver_framework::NodeProperty2> properties, |
| cpp20::span<const fuchsia_driver_framework::Offer> offers) { |
| return fdf::AddChild(node(), logger(), node_name, properties, offers); |
| } |
| |
| zx::result<fidl::ClientEnd<fuchsia_driver_framework::NodeController>> DriverBase::AddChild( |
| std::string_view node_name, fuchsia_driver_framework::DevfsAddArgs& devfs_args, |
| cpp20::span<const fuchsia_driver_framework::NodeProperty2> properties, |
| cpp20::span<const fuchsia_driver_framework::Offer> offers) { |
| return fdf::AddChild(node(), logger(), node_name, devfs_args, properties, offers); |
| } |
| |
| cpp20::span<const fuchsia_driver_framework::NodeProperty2> DriverBase::node_properties_2( |
| const std::string& parent_node_name) const { |
| const auto& node_properties_2 = start_args_.node_properties_2(); |
| if (node_properties_2.has_value()) { |
| for (const auto& entry : node_properties_2.value()) { |
| if (entry.name() == parent_node_name) { |
| return entry.properties(); |
| } |
| } |
| } |
| return {}; |
| } |
| |
| DriverBase::~DriverBase() { Logger::SetGlobalInstance(nullptr); } |
| |
| } // namespace fdf |