blob: da037337471ac5c7972c5146f685b0f5f71888e4 [file] [log] [blame]
// 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::result<> add_result = parent_set_collector_->AddNode(composite_parent.index(), *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