| // 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 <fidl/fuchsia.inspect/cpp/markers.h> |
| #include <lib/fidl/cpp/wire/channel.h> |
| #include <lib/fidl/cpp/wire/status.h> |
| #include <lib/fidl/cpp/wire/string_view.h> |
| #include <lib/fidl/cpp/wire/vector_view.h> |
| #include <lib/fidl/cpp/wire/wire_types.h> |
| #include <lib/inspect/component/cpp/service.h> |
| #include <zircon/types.h> |
| |
| #include <variant> |
| #include <vector> |
| |
| namespace inspect { |
| void TreeNameIterator::StartSelfManagedServer( |
| async_dispatcher_t* dispatcher, fidl::ServerEnd<fuchsia_inspect::TreeNameIterator>&& request, |
| std::vector<std::string> names) { |
| ZX_ASSERT(dispatcher); |
| |
| auto impl = std::unique_ptr<TreeNameIterator>(new TreeNameIterator(std::move(names))); |
| auto* ptr = impl.get(); |
| auto binding_ref = fidl::BindServer(dispatcher, std::move(request), std::move(impl), nullptr); |
| ptr->binding_.emplace(std::move(binding_ref)); |
| } |
| |
| // Get the next batch of names. Names are sent in batches of `kMaxTreeNamesListSize`, |
| // which is defined with the rest of the FIDL protocol. |
| void TreeNameIterator::GetNext(GetNextCompleter::Sync& completer) { |
| ZX_ASSERT(binding_.has_value()); |
| |
| std::vector<fidl::StringView> converted_names; |
| converted_names.reserve(names_.size()); |
| auto bytes_used = sizeof(fidl_message_header_t) + sizeof(fidl_vector_t); |
| for (; current_index_ < names_.size(); current_index_++) { |
| bytes_used += sizeof(fidl_string_t); |
| bytes_used += FIDL_ALIGN(names_.at(current_index_).length()); |
| if (bytes_used > ZX_CHANNEL_MAX_MSG_BYTES) { |
| break; |
| } |
| |
| converted_names.emplace_back(fidl::StringView::FromExternal(names_.at(current_index_))); |
| } |
| |
| completer.Reply(fidl::VectorView<fidl::StringView>::FromExternal(converted_names)); |
| } |
| |
| void TreeServer::StartSelfManagedServer(std::variant<Inspector, zx::vmo> data, |
| TreeHandlerSettings settings, |
| async_dispatcher_t* dispatcher, |
| fidl::ServerEnd<fuchsia_inspect::Tree>&& request) { |
| ZX_ASSERT(dispatcher); |
| |
| auto impl = |
| std::unique_ptr<TreeServer>(new TreeServer(std::move(data), std::move(settings), dispatcher)); |
| |
| auto* impl_ptr = impl.get(); |
| auto binding_ref = fidl::BindServer(dispatcher, std::move(request), std::move(impl), nullptr); |
| impl_ptr->binding_.emplace(std::move(binding_ref)); |
| } |
| |
| void TreeServer::GetContent(GetContentCompleter::Sync& completer) { |
| ZX_ASSERT(binding_.has_value()); |
| |
| fidl::Arena arena; |
| auto content_builder = fuchsia_inspect::wire::TreeContent::Builder(arena); |
| fuchsia_mem::wire::Buffer buffer; |
| const auto& primary_behavior = settings_.snapshot_behavior.PrimaryBehavior(); |
| const auto& failure_behavior = settings_.snapshot_behavior.FailureBehavior(); |
| using behavior_types = TreeServerSendPreference::Type; |
| |
| std::visit( |
| [&](auto&& data) { |
| // T is one of the variant values of data_; at the time of writing that is Inspector or |
| // zx::vmo. The branching below first determines if the data is a VMO or an Inspector, |
| // and then determines the duplication policy given the data type. |
| using T = std::decay_t<decltype(data)>; |
| if constexpr (std::is_same_v<T, Inspector>) { |
| if (primary_behavior == behavior_types::Frozen) { |
| auto maybe_vmo_frozen = data.FrozenVmoCopy(); |
| if (maybe_vmo_frozen.has_value()) { |
| buffer.vmo = std::move(maybe_vmo_frozen.value()); |
| } else if (failure_behavior.has_value() && *failure_behavior == behavior_types::Live) { |
| buffer.vmo = data.DuplicateVmo(); |
| } else { |
| auto maybe_vmo_copied = data.CopyVmo(); |
| if (maybe_vmo_copied.has_value()) { |
| buffer.vmo = std::move(maybe_vmo_copied.value()); |
| } else { |
| buffer.vmo = data.DuplicateVmo(); |
| } |
| } |
| } else if (primary_behavior == behavior_types::Live) { |
| buffer.vmo = data.DuplicateVmo(); |
| } else { |
| auto maybe_vmo_copied = data.CopyVmo(); |
| if (maybe_vmo_copied.has_value()) { |
| buffer.vmo = std::move(maybe_vmo_copied.value()); |
| } else { |
| buffer.vmo = data.DuplicateVmo(); |
| } |
| } |
| } else if constexpr (std::is_same_v<T, zx::vmo>) { |
| data.duplicate(ZX_RIGHTS_BASIC | ZX_RIGHT_READ | ZX_RIGHT_MAP | ZX_RIGHT_GET_PROPERTY, |
| &buffer.vmo); |
| } |
| }, |
| data_); |
| |
| content_builder.buffer(std::move(buffer)); |
| completer.Reply(content_builder.Build()); |
| } |
| |
| void TreeServer::ListChildNames(ListChildNamesRequestView request, |
| ListChildNamesCompleter::Sync& completer) { |
| ZX_ASSERT(binding_.has_value()); |
| |
| std::visit( |
| [&](auto&& data) { |
| using T = std::decay_t<decltype(data)>; |
| if constexpr (std::is_same_v<T, Inspector>) { |
| TreeNameIterator::StartSelfManagedServer( |
| executor_.dispatcher(), std::move(request->tree_iterator), data.GetChildNames()); |
| } else if constexpr (std::is_same_v<T, zx::vmo>) { |
| TreeNameIterator::StartSelfManagedServer(executor_.dispatcher(), |
| std::move(request->tree_iterator), {}); |
| } |
| }, |
| data_); |
| } |
| |
| void TreeServer::OpenChild(OpenChildRequestView request, OpenChildCompleter::Sync& completer) { |
| ZX_ASSERT(binding_.has_value()); |
| |
| std::visit( |
| [&](auto&& data) { |
| using T = std::decay_t<decltype(data)>; |
| if constexpr (std::is_same_v<T, Inspector>) { |
| executor_.schedule_task(data.OpenChild(std::string(request->child_name.get())) |
| .and_then([request = std::move(request->tree), |
| this](Inspector& inspector) mutable { |
| TreeServer::StartSelfManagedServer(inspector, settings_, |
| executor_.dispatcher(), |
| std::move(request)); |
| })); |
| } |
| }, |
| data_); |
| } |
| |
| } // namespace inspect |