| // Copyright 2022 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 "src/devices/bin/driver_manager/composite_node_spec_v2.h" |
| |
| namespace fdd = fuchsia_driver_development; |
| |
| namespace driver_manager { |
| |
| CompositeNodeSpecV2::CompositeNodeSpecV2(CompositeNodeSpecCreateInfo create_info, |
| async_dispatcher_t* dispatcher, NodeManager* node_manager) |
| : CompositeNodeSpec(std::move(create_info)), |
| parent_set_collector_(std::nullopt), |
| dispatcher_(dispatcher), |
| node_manager_(node_manager) {} |
| |
| zx::result<std::optional<DeviceOrNode>> CompositeNodeSpecV2::BindParentImpl( |
| fuchsia_driver_framework::wire::CompositeParent composite_parent, |
| const DeviceOrNode& device_or_node) { |
| auto node_ptr = std::get_if<std::weak_ptr<driver_manager::Node>>(&device_or_node); |
| ZX_ASSERT(node_ptr); |
| ZX_ASSERT(composite_parent.has_index()); |
| |
| if (!composite_info_.has_value()) { |
| ZX_ASSERT(composite_parent.has_composite()); |
| auto composite = fidl::ToNatural(composite_parent.composite()); |
| composite_info_ = composite; |
| } |
| |
| auto& spec = composite_info_->spec(); |
| ZX_ASSERT(spec.has_value()); |
| auto& matched_driver = composite_info_->matched_driver(); |
| ZX_ASSERT(matched_driver.has_value()); |
| auto& spec_name = spec.value().name(); |
| ZX_ASSERT(spec_name.has_value()); |
| auto spec_name_value = spec_name.value(); |
| auto& composite_driver = matched_driver.value().composite_driver(); |
| ZX_ASSERT(composite_driver.has_value()); |
| auto& driver_info = composite_driver.value().driver_info(); |
| ZX_ASSERT(driver_info.has_value()); |
| auto& parent_names = matched_driver.value().parent_names(); |
| ZX_ASSERT(parent_names.has_value()); |
| auto& primary_index = matched_driver.value().primary_parent_index(); |
| auto& url = driver_info.value().url(); |
| ZX_ASSERT(url.has_value()); |
| |
| if (!parent_set_collector_) { |
| parent_set_collector_ = |
| ParentSetCollector(spec_name_value, parent_names.value(), primary_index.value_or(0)); |
| driver_url_ = url.value(); |
| } |
| |
| ZX_ASSERT(parent_specs().size() > composite_parent.index()); |
| zx::result<> add_result = parent_set_collector_->AddNode( |
| composite_parent.index(), parent_specs()[composite_parent.index()].properties(), *node_ptr); |
| if (add_result.is_error()) { |
| return add_result.take_error(); |
| } |
| |
| auto composite_node = parent_set_collector_->TryToAssemble(node_manager_, dispatcher_); |
| if (composite_node.is_error()) { |
| if (composite_node.status_value() != ZX_ERR_SHOULD_WAIT) { |
| return composite_node.take_error(); |
| } |
| return zx::ok(std::nullopt); |
| } |
| |
| return zx::ok(composite_node.value()); |
| } |
| |
| void CompositeNodeSpecV2::RemoveImpl(RemoveCompositeNodeCallback callback) { |
| if (!parent_set_collector_) { |
| callback(zx::ok()); |
| return; |
| } |
| |
| // TODO(https://fxbug.dev/42075799): Once we start enforcing the multibind composite flag, move |
| // the parent nodes back to the orphaned nodes if they can't multibind. |
| auto node = parent_set_collector_->completed_composite_node(); |
| if (node && !node->expired()) { |
| node->lock()->RemoveCompositeNodeForRebind(std::move(callback)); |
| parent_set_collector_.reset(); |
| driver_url_ = ""; |
| composite_info_.reset(); |
| return; |
| } |
| |
| parent_set_collector_.reset(); |
| driver_url_ = ""; |
| composite_info_.reset(); |
| callback(zx::ok()); |
| } |
| |
| fdd::wire::CompositeNodeInfo CompositeNodeSpecV2::GetCompositeInfo(fidl::AnyArena& arena) const { |
| auto composite_info = fdd::wire::CompositeNodeInfo::Builder(arena); |
| if (!parent_set_collector_) { |
| fidl::VectorView<fidl::StringView> parent_topological_paths(arena, size()); |
| composite_info.parent_topological_paths(parent_topological_paths); |
| return composite_info.Build(); |
| } |
| |
| if (composite_info_.has_value()) { |
| composite_info.composite(fdd::wire::CompositeInfo::WithComposite( |
| arena, fidl::ToWire(arena, composite_info_.value()))); |
| } |
| |
| composite_info.parent_topological_paths(parent_set_collector_->GetParentTopologicalPaths(arena)); |
| |
| std::optional<std::weak_ptr<driver_manager::Node>> composite_node = |
| parent_set_collector_->completed_composite_node(); |
| if (composite_node) { |
| if (auto node_ptr = composite_node->lock(); node_ptr) { |
| composite_info.topological_path(node_ptr->MakeTopologicalPath()); |
| } |
| } |
| return composite_info.Build(); |
| } |
| |
| } // namespace driver_manager |