blob: 1ef6fb9e4caf615f89171553d8e2149a89d5170b [file] [log] [blame]
// Copyright 2018 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.
// !!! DEPRECATED !!!
// New usages should reference garnet/public/lib/inspect...
#ifndef SRC_LIB_INSPECT_DEPRECATED_DEPRECATED_EXPOSE_H_
#define SRC_LIB_INSPECT_DEPRECATED_DEPRECATED_EXPOSE_H_
#include <fuchsia/inspect/deprecated/cpp/fidl.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fit/defer.h>
#include <lib/fit/function.h>
#include <mutex>
#include <set>
#include <unordered_map>
#include <variant>
#include <vector>
#include <fs/lazy_dir.h>
#include <fs/pseudo_file.h>
namespace component {
// Property is a string value associated with an |Object| belonging to a
// |Component|. The string value may be updated lazily at read time through the
// use of a callback.
//
// This class is not thread safe; concurrent accesses require external
// coordination.
class Property {
public:
using ByteVector = std::vector<uint8_t>;
using StringValueCallback = fit::function<std::string()>;
using VectorValueCallback = fit::function<ByteVector()>;
// Constructs an empty property with string value "".
Property() { Set(""); }
// Constructs a property from a string.
explicit Property(std::string value) { Set(std::move(value)); }
explicit Property(ByteVector value) { Set(std::move(value)); }
// Constructs a property with value set on each read by the given callback.
explicit Property(StringValueCallback callback) { Set(std::move(callback)); }
explicit Property(VectorValueCallback callback) { Set(std::move(callback)); }
// Sets the property from a string.
void Set(std::string value);
void Set(ByteVector value);
// Sets the property with value set on each read by the given callback.
void Set(StringValueCallback callback);
void Set(VectorValueCallback callback);
fuchsia::inspect::deprecated::Property ToFidl(const std::string& name) const;
private:
// Variants of possible values for this property.
std::variant<std::string, ByteVector, StringValueCallback, VectorValueCallback> value_;
};
// Metric is a numeric value associated with an |Object| belonging to
// a |Component|.
// A Metric has a type, which is one of:
// INT: int64_t
// UINT: uint64_t
// DOUBLE: double
// CALLBACK: Set by a callback function.
//
// Calling Set*() on a metric changes its type, but Add and Sub
// simply perform += or -= respectively, not changing the type of the
// Metric. This means the result of an operation will be cast back to the
// original type.
//
// This class is not thread safe; concurrent accesses require external
// coordination.
class Metric {
public:
using ValueCallback = fit::function<void(Metric*)>;
enum Type { INT, UINT, DOUBLE, CALLBACK };
// Constructs an INT metric with value 0.
Metric() { SetInt(0); }
// Constructs a metric set on read by the given callback.
explicit Metric(ValueCallback callback) { SetCallback(std::move(callback)); }
// Sets the type of this metric to INT with the given value.
void SetInt(int64_t value);
// Sets the type of this metric to UINT with the given value.
void SetUInt(uint64_t value);
// Sets the type of this metric to DOUBLE with the given value.
void SetDouble(double value);
// Sets the type of this metric to CALLBACK, where the given callback
// is responsible for the value of this metric.
void SetCallback(ValueCallback callback);
// Gets the value of this metric as a string.
std::string ToString() const;
// Converts the value of this metric into its FIDL representation,
// using the given name for the |name| field.
fuchsia::inspect::deprecated::Metric ToFidl(const std::string& name) const;
// Adds a numeric type to the value of this metric. The type of
// the metric will not be affected by this operation regardless of the
// type passed in. Adding to a CALLBACK metric does nothing.
template <typename T>
void Add(T amount) {
switch (type_) {
case INT:
int_value_ += static_cast<int64_t>(amount);
break;
case UINT:
uint_value_ += static_cast<uint64_t>(amount);
break;
case DOUBLE:
double_value_ += static_cast<double>(amount);
break;
case CALLBACK:
break;
}
}
// Subtracts a numeric type to the value of this metric. The type of
// the metric will not be affected by this operation regardless of the
// type passed in. Subtracting from a CALLBACK metric does nothing.
template <typename T>
void Sub(T amount) {
switch (type_) {
case INT:
int_value_ -= static_cast<int64_t>(amount);
break;
case UINT:
uint_value_ -= static_cast<uint64_t>(amount);
break;
case DOUBLE:
double_value_ -= static_cast<double>(amount);
break;
case CALLBACK:
break;
}
}
private:
// The current type of this metric.
Type type_;
// Union of 64-bit value types for the value of this metric.
union {
int64_t int_value_;
uint64_t uint_value_;
double double_value_;
};
// Callback to be used if type_ == CALLBACK.
ValueCallback callback_;
};
Metric IntMetric(int64_t value);
Metric UIntMetric(uint64_t value);
Metric DoubleMetric(double value);
Metric CallbackMetric(Metric::ValueCallback callback);
// An interface for dynamic management of an Inspect hierarchy. Implementations
// of this interface are provided by components integrating with Inspect and are
// called by Inspect during inspections to modify the Inspect hierarchy,
// typically by adding or "pinning" nodes of the hierarchy in place for the
// duration of the inspection.
class ChildrenManager {
public:
ChildrenManager() = default;
virtual ~ChildrenManager() = default;
// Specifies to Inspect the names of children available under
// the node with which this ChildrenExpansionFunctions object
// is registered. The names passed by the inspected system to
// the callback need not include or exclude the names of
// child structures already resident in memory and
// maintaining a static Inspect node under the node with
// which this ChildrenExpansionFunctions object is
// registered. The inspected system’s including a name among
// those passed to the callback is not a guarantee that a
// child with that name will be found resultant from a later
// call to Attach.
//
// NOTE(crjohns, jeffbrown, nathaniel): This method is likely
// to be fit::promise-ified in the future.
virtual void GetNames(fit::function<void(std::set<std::string>)> callback) = 0;
// Directs the system under inspection to
// (1) if the structure for the given child is not already
// resident in memory and maintaining a static Inspect
// node in the Inspect hierarchy, bring that structure
// into memory such that it attaches its static node to
// the hierarchy,
// (2) provide to Inspect a closure that Inspect will call
// at a later time to indicate that it is no longer
// examining the portion of the hierarchy with which the
// structure is associated (the system under inspection
// is responsible for ensuring that the closure remains
// safe to call until (a) it is called or (b) the
// ChildrenManager in response to a call on which the
// closure was created is removed from Inspect (at which
// time the closure will be called)), and
// (3) Make a best-effort attempt to retain in memory the
// structure associated with the given child name.
// This method is also best-effort in its overall function;
// systems under inspection may do nothing and pass a no-op
// closure to the callback and doing so will simply
// indicate “no such child” to Inspect.
virtual void Attach(std::string name, fit::function<void(fit::closure)> callback) = 0;
};
// A component |Object| is any named entity that a component wishes to expose
// for inspection. An |Object| consists of any number of string |Property| and
// numeric |Metric| values. They may also have any number of uniquely named
// children. The set of children may be set dynamically at read time.
//
// |Object| implements the |Inspect| interface to expose its values and
// children over FIDL, and it implements |LazyDir| to expose the same over a
// file system.
//
// In the directory implementation, the special file `.channel` exposes a
// |Service| file to bind to the FIDL interface. The special file `.data`
// exposes the current values of the |Object| in a TAB-separated format for
// debugging. `.data` should be used strictly for debugging, and all user-facing
// utilities must communicate over the FIDL interface.
//
// This class is thread safe.
class Object : public fuchsia::inspect::deprecated::Inspect {
public:
using ObjectVector = std::vector<std::shared_ptr<Object>>;
using ChildrenCallback = fit::function<void(ObjectVector*)>;
using StringOutputVector = fidl::VectorPtr<std::string>;
~Object();
// Makes a new shared pointer to an Object.
static std::shared_ptr<Object> Make(std::string name) {
auto ret = std::shared_ptr<Object>(new Object(std::move(name)));
std::lock_guard<std::mutex> lock(ret->mutex_);
ret->self_weak_ptr_ = ret;
return ret;
}
// Gets the name of this |Object|.
std::string name() { return name_; }
// Gets a new reference to a child by name. The return value may be empty if
// the child does not exist.
std::shared_ptr<Object> GetChild(std::string name);
// Sets a child to a new reference. If the child already exists, the contained
// reference will be dropped and replaced with the given one.
void SetChild(std::shared_ptr<Object> child);
// Takes a child from this |Object|. This |Object| will no longer contain a
// reference to the returned child. The return value may be empty if the child
// does not exist.
std::shared_ptr<Object> TakeChild(std::string name);
// Sets a callback to dynamically populate children. The children returned by
// this callback are in addition to the children already contained by this
// |Object|.
void SetChildrenCallback(ChildrenCallback callback);
// Clears the callback for dynamic children. After calling this function, the
// returned children will consist only of children contained by this object.
void ClearChildrenCallback();
// Sets (if |children_manager| is not null) or clears (if |children_manager|
// is null) the ChildrenManager to be used to dynamically expand the inspect
// hierarchy below this Object. The pointed-to ChildrenManager must live until
// another call to this method assigns a different ChildrenManager (or no
// ChildrenManager) or until this Object is deleted.
void SetChildrenManager(ChildrenManager* children_manager);
// Called by this Object's parent Object when its ChildrenManager is being
// reset and the detachers consequent from the being-reset ChildrenManager
// need to be destroyed earlier than they otherwise would be.
std::vector<fit::deferred_callback> TakeDetachers();
// Remove a property from the object, returning true if it was found and
// removed.
bool RemoveProperty(const std::string& name);
// Remove a metric from the object, returning true if it was found and
// removed.
bool RemoveMetric(const std::string& name);
// Sets a |Property| on this |Object| to the given value.
// The name of the property cannot include null bytes.
bool SetProperty(const std::string& name, Property value);
// Sets a |Metric| on this |Object| to the given value.
// The name of the metric cannot include null bytes.
bool SetMetric(const std::string& name, Metric metric);
// Adds to a numeric |Metric| on this |Object|.
template <typename T>
bool AddMetric(const std::string& name, T amount) {
std::lock_guard<std::mutex> lock(mutex_);
auto it = metrics_.find(name);
if (it == metrics_.end()) {
return false;
}
it->second.Add(amount);
return true;
}
// Subtracts from a numeric |Metric| on this |Object|.
template <typename T>
bool SubMetric(const std::string& name, T amount) {
std::lock_guard<std::mutex> lock(mutex_);
auto it = metrics_.find(name);
if (it == metrics_.end()) {
return false;
}
it->second.Sub(amount);
return true;
}
// |Inspect| implementation
// Reads local properties and metrics.
void ReadData(ReadDataCallback callback) override;
// Lists the children of this Object, including dynamic ones if they exist.
void ListChildren(ListChildrenCallback callback) override;
// Opens a channel with the requested child
void OpenChild(std::string name, ::fidl::InterfaceRequest<Inspect> child_channel,
OpenChildCallback callback) override;
// Turn this |Object| into its FIDL representation.
fuchsia::inspect::deprecated::Object ToFidl();
// Returns the names of this Object's children in a vector.
StringOutputVector GetChildren();
protected:
// Constructs a new |Object| with the given name.
// Every object requires a name, and names for children must be unique.
explicit Object(std::string name);
// Drop all bindings to this Object, for testing.
void DropBindings() {
std::lock_guard<std::mutex> lock(mutex_);
bindings_.CloseAll();
}
private:
// The common implementation of the two AddBinding overloads.
void InnerAddBinding(fidl::InterfaceRequest<Inspect> chan) __TA_REQUIRES(mutex_);
// Adds a new binding.
void AddBinding(fidl::InterfaceRequest<Inspect> chan);
// Adds a new binding and a behavior to be called when this Object's binding
// set becomes empty. The behavior may be related to the life cycle of this
// Object and calling it may have the effect of deleting this object. Because
// this method is the only means of adding these behaviors to this Object, it
// is invariant that detachers_ is only ever non-empty when bindings_ is
// non-empty.
void AddBinding(fidl::InterfaceRequest<Inspect> chan, fit::deferred_callback detacher);
std::shared_ptr<Object> GetUnmanagedChild(std::string name);
std::vector<std::string> ListUnmanagedChildNames();
// The name of this object.
std::string name_;
// Because the function of ChildrenManager is to potentially mutate children_
// when asked, the lock protecting ChildrenManager is not the same as the lock
// protecting the things they change.
mutable std::mutex children_manager_mutex_;
ChildrenManager* children_manager_ __TA_GUARDED(children_manager_mutex_);
// Mutex protecting fields below.
mutable std::mutex mutex_;
// |Property| for this object, keyed by name.
std::unordered_map<std::string, Property> properties_ __TA_GUARDED(mutex_);
// |Property| for this object, keyed by name.
std::unordered_map<std::string, Metric> metrics_ __TA_GUARDED(mutex_);
// |Children| for this object, keyed by name. Ordered structure for consistent
// iteration.
std::map<std::string, std::shared_ptr<Object>> children_ __TA_GUARDED(mutex_);
// TODO(crjohns): Convert all remaining uses of ChildrenCallback (who are
// indirectly users of lazy_object_callback_) to use ChildrenManager and
// remove ChildrenCallback.
//
// Callback for retrieving lazily generated children. May be empty.
ChildrenCallback lazy_object_callback_ __TA_GUARDED(mutex_);
// The bindings for channels connected to this |Inspect|. The object itself is
// owned by |self_if_bindings_| below.
fidl::BindingSet<fuchsia::inspect::deprecated::Inspect, Object*> bindings_ __TA_GUARDED(mutex_);
std::vector<fit::deferred_callback> detachers_ __TA_GUARDED(mutex_);
// A self shared_ptr, held only if |bindings_| is non-empty. Allows avoiding
// circular ownership. Recursive destruction is impossible because the object
// will not be destructed while pointing to itself.
// TODO(FIDL-452): change when FIDL supports storing self shared ptrs.
std::shared_ptr<Object> self_if_bindings_ __TA_GUARDED(mutex_);
// A self weak_ptr, used to promote to a self shared_ptr when |bindings_| is
// non-empty.
std::weak_ptr<Object> self_weak_ptr_ __TA_GUARDED(mutex_);
};
} // namespace component
#endif // SRC_LIB_INSPECT_DEPRECATED_DEPRECATED_EXPOSE_H_