blob: 38c228736d502d065f2e8481f8747086177862b9 [file] [log] [blame]
// Copyright 2019 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/lib/inspect_deprecated/reader.h"
#include <lib/inspect/cpp/reader.h>
#include <iterator>
#include <stack>
#include <unordered_map>
#include "fuchsia/inspect/deprecated/cpp/fidl.h"
#include "lib/fit/bridge.h"
#include "lib/fit/result.h"
#include "src/lib/inspect_deprecated/hierarchy.h"
namespace inspect_deprecated {
namespace {
hierarchy::Node FidlObjectToNode(fuchsia::inspect::deprecated::Object obj) {
std::vector<hierarchy::Property> properties;
std::vector<hierarchy::Metric> metrics;
for (auto& metric : obj.metrics) {
if (metric.value.is_uint_value()) {
metrics.push_back(hierarchy::Metric(std::move(metric.key),
hierarchy::UIntMetric(metric.value.uint_value())));
} else if (metric.value.is_int_value()) {
metrics.push_back(
hierarchy::Metric(std::move(metric.key), hierarchy::IntMetric(metric.value.int_value())));
} else if (metric.value.is_double_value()) {
metrics.push_back(hierarchy::Metric(std::move(metric.key),
hierarchy::DoubleMetric(metric.value.double_value())));
}
}
for (auto& property : obj.properties) {
if (property.value.is_str()) {
properties.push_back(hierarchy::Property(
std::move(property.key), hierarchy::StringProperty(std::move(property.value.str()))));
} else if (property.value.is_bytes()) {
properties.push_back(
hierarchy::Property(std::move(property.key),
hierarchy::ByteVectorProperty(std::move(property.value.bytes()))));
}
}
return hierarchy::Node(std::move(obj.name), std::move(properties), std::move(metrics));
}
// TODO(crjohns, nathaniel): Needs to be asynchronous to use a ChildrenManager.
ObjectHierarchy Read(std::shared_ptr<component::Object> object_root, int depth) {
if (depth == 0) {
return ObjectHierarchy(FidlObjectToNode(object_root->ToFidl()), {});
} else {
std::vector<ObjectHierarchy> children;
auto child_names = object_root->GetChildren();
for (auto& child_name : *child_names) {
auto child_obj = object_root->GetChild(child_name);
if (child_obj) {
children.emplace_back(Read(child_obj, depth - 1));
}
}
return ObjectHierarchy(FidlObjectToNode(object_root->ToFidl()), std::move(children));
}
}
hierarchy::ArrayDisplayFormat FromNewFormat(::inspect::ArrayDisplayFormat format) {
switch (format) {
case ::inspect::ArrayDisplayFormat::kFlat:
return hierarchy::ArrayDisplayFormat::FLAT;
case ::inspect::ArrayDisplayFormat::kLinearHistogram:
return hierarchy::ArrayDisplayFormat::LINEAR_HISTOGRAM;
case ::inspect::ArrayDisplayFormat::kExponentialHistogram:
return hierarchy::ArrayDisplayFormat::EXPONENTIAL_HISTOGRAM;
}
}
#define CONVERT_METRIC(OLD_NAME, NEW_NAME) \
if (property.Contains<::inspect::NEW_NAME>()) { \
const auto& val = property.Get<::inspect::NEW_NAME>(); \
ret.node().metrics().emplace_back( \
hierarchy::Metric(property.name(), hierarchy::OLD_NAME(val.value()))); \
}
#define CONVERT_PROPERTY(OLD_NAME, NEW_NAME) \
if (property.Contains<::inspect::NEW_NAME>()) { \
const auto& val = property.Get<::inspect::NEW_NAME>(); \
ret.node().properties().emplace_back( \
hierarchy::Property(property.name(), hierarchy::OLD_NAME(val.value()))); \
}
#define CONVERT_ARRAY(OLD_NAME, NEW_NAME) \
if (property.Contains<::inspect::NEW_NAME>()) { \
const auto& val = property.Get<::inspect::NEW_NAME>(); \
ret.node().metrics().emplace_back(hierarchy::Metric( \
property.name(), \
hierarchy::OLD_NAME(val.value(), FromNewFormat(val.GetDisplayFormat())))); \
}
ObjectHierarchy FromNewHierarchy(const ::inspect::Hierarchy& hierarchy) {
ObjectHierarchy ret;
ret.node().name() = hierarchy.node().name();
for (const auto& property : hierarchy.node().properties()) {
CONVERT_METRIC(IntMetric, IntPropertyValue);
CONVERT_METRIC(UIntMetric, UintPropertyValue);
CONVERT_METRIC(DoubleMetric, DoublePropertyValue);
CONVERT_PROPERTY(StringProperty, StringPropertyValue);
CONVERT_PROPERTY(ByteVectorProperty, ByteVectorPropertyValue);
CONVERT_ARRAY(IntArray, IntArrayValue);
CONVERT_ARRAY(UIntArray, UintArrayValue);
CONVERT_ARRAY(DoubleArray, DoubleArrayValue);
}
for (const auto& child : hierarchy.children()) {
ret.children().emplace_back(FromNewHierarchy(child));
}
return ret;
}
} // namespace
ObjectHierarchy ReadFromObject(const Node& object, int depth) {
return Read(object.object_dir().object(), depth);
}
ObjectReader::ObjectReader(
fidl::InterfaceHandle<fuchsia::inspect::deprecated::Inspect> inspect_handle)
: state_(std::make_shared<internal::ObjectReaderState>()) {
state_->inspect_ptr_.Bind(std::move(inspect_handle));
}
fit::promise<fuchsia::inspect::deprecated::Object> ObjectReader::Read() const {
fit::bridge<fuchsia::inspect::deprecated::Object> bridge;
state_->inspect_ptr_->ReadData(bridge.completer.bind());
return bridge.consumer.promise_or(fit::error());
}
fit::promise<ChildNameVector> ObjectReader::ListChildren() const {
fit::bridge<ChildNameVector> bridge;
state_->inspect_ptr_->ListChildren(bridge.completer.bind());
return bridge.consumer.promise_or(fit::error());
}
fit::promise<ObjectReader> ObjectReader::OpenChild(std::string child_name) const {
fuchsia::inspect::deprecated::InspectPtr child_ptr;
fit::bridge<bool> bridge;
state_->inspect_ptr_->OpenChild(child_name, child_ptr.NewRequest(), bridge.completer.bind());
return bridge.consumer.promise_or(fit::error())
.and_then(
[chan = child_ptr.Unbind()](const bool& success) mutable -> fit::result<ObjectReader> {
if (success) {
return fit::ok(ObjectReader(std::move(chan)));
} else {
return fit::error();
}
});
}
fit::promise<std::vector<ObjectReader>> ObjectReader::OpenChildren() const {
return ListChildren()
.and_then([reader = *this](const ChildNameVector& children) {
std::vector<fit::promise<ObjectReader>> opens;
for (const auto& child_name : *children) {
opens.emplace_back(reader.OpenChild(child_name));
}
return fit::join_promise_vector(std::move(opens));
})
.and_then([](std::vector<fit::result<ObjectReader>>& objects) {
std::vector<ObjectReader> result;
for (auto& obj : objects) {
if (obj.is_ok()) {
result.emplace_back(obj.take_value());
}
}
return fit::ok(std::move(result));
});
}
fit::promise<ObjectHierarchy> ReadFromFidl(ObjectReader reader, int depth) {
auto reader_promise = reader.Read();
if (depth == 0) {
return reader_promise.and_then([reader](fuchsia::inspect::deprecated::Object& obj) {
return fit::ok(ObjectHierarchy(FidlObjectToNode(std::move(obj)), {}));
});
} else {
auto children_promise =
reader.OpenChildren()
.and_then([depth](std::vector<ObjectReader>& result)
-> fit::promise<std::vector<fit::result<ObjectHierarchy>>> {
std::vector<fit::promise<ObjectHierarchy>> children;
for (auto& reader : result) {
children.emplace_back(ReadFromFidl(std::move(reader), depth - 1));
}
return fit::join_promise_vector(std::move(children));
})
.and_then([](std::vector<fit::result<ObjectHierarchy>>& result) {
std::vector<ObjectHierarchy> children;
for (auto& res : result) {
if (res.is_ok()) {
children.emplace_back(res.take_value());
}
}
return fit::ok(std::move(children));
});
return fit::join_promises(std::move(reader_promise), std::move(children_promise))
.and_then([reader](std::tuple<fit::result<fuchsia::inspect::deprecated::Object>,
fit::result<std::vector<ObjectHierarchy>>>& result) mutable
-> fit::result<ObjectHierarchy> {
if (!std::get<0>(result).is_ok() || !std::get<1>(result).is_ok()) {
return fit::error();
}
return fit::ok(ObjectHierarchy(FidlObjectToNode(std::get<0>(result).take_value()),
std::get<1>(result).take_value()));
});
}
}
fit::result<ObjectHierarchy> ReadFromSnapshot(::inspect::Snapshot snapshot) {
auto new_hierarchy = ::inspect::ReadFromSnapshot(std::move(snapshot));
if (!new_hierarchy.is_ok()) {
return fit::error();
}
return fit::ok(FromNewHierarchy(new_hierarchy.value()));
}
fit::result<ObjectHierarchy> ReadFromVmo(const zx::vmo& vmo) {
inspect::Snapshot snapshot;
if (inspect::Snapshot::Create(std::move(vmo), &snapshot) != ZX_OK) {
return fit::error();
}
return ::inspect_deprecated::ReadFromSnapshot(std::move(snapshot));
}
fit::result<ObjectHierarchy> ReadFromBuffer(std::vector<uint8_t> buffer) {
inspect::Snapshot snapshot;
if (inspect::Snapshot::Create(std::move(buffer), &snapshot) != ZX_OK) {
// TODO(CF-865): Best-effort read of invalid snapshots.
return fit::error();
}
return ::inspect_deprecated::ReadFromSnapshot(std::move(snapshot));
}
ObjectHierarchy ReadFromFidlObject(fuchsia::inspect::deprecated::Object object) {
return ObjectHierarchy(FidlObjectToNode(std::move(object)), {});
}
} // namespace inspect_deprecated