aboutsummaryrefslogtreecommitdiffstats
path: root/brillo/dbus/exported_property_set.h
diff options
context:
space:
mode:
Diffstat (limited to 'brillo/dbus/exported_property_set.h')
-rw-r--r--brillo/dbus/exported_property_set.h226
1 files changed, 226 insertions, 0 deletions
diff --git a/brillo/dbus/exported_property_set.h b/brillo/dbus/exported_property_set.h
new file mode 100644
index 0000000..16f5086
--- /dev/null
+++ b/brillo/dbus/exported_property_set.h
@@ -0,0 +1,226 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIBCHROMEOS_BRILLO_DBUS_EXPORTED_PROPERTY_SET_H_
+#define LIBCHROMEOS_BRILLO_DBUS_EXPORTED_PROPERTY_SET_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/memory/weak_ptr.h>
+#include <brillo/any.h>
+#include <brillo/brillo_export.h>
+#include <brillo/dbus/dbus_signal.h>
+#include <brillo/errors/error.h>
+#include <brillo/errors/error_codes.h>
+#include <brillo/variant_dictionary.h>
+#include <dbus/exported_object.h>
+#include <dbus/message.h>
+
+namespace brillo {
+
+namespace dbus_utils {
+
+// This class may be used to implement the org.freedesktop.DBus.Properties
+// interface. It sends the update signal on property updates:
+//
+// org.freedesktop.DBus.Properties.PropertiesChanged (
+// STRING interface_name,
+// DICT<STRING,VARIANT> changed_properties,
+// ARRAY<STRING> invalidated_properties);
+//
+//
+// and implements the required methods of the interface:
+//
+// org.freedesktop.DBus.Properties.Get(in STRING interface_name,
+// in STRING property_name,
+// out VARIANT value);
+// org.freedesktop.DBus.Properties.Set(in STRING interface_name,
+// in STRING property_name,
+// in VARIANT value);
+// org.freedesktop.DBus.Properties.GetAll(in STRING interface_name,
+// out DICT<STRING,VARIANT> props);
+//
+// This class is very similar to the PropertySet class in Chrome, except that
+// it allows objects to expose properties rather than to consume them.
+// It is used as part of DBusObject to implement D-Bus object properties on
+// registered interfaces. See description of DBusObject class for more details.
+
+class DBusInterface;
+class DBusObject;
+
+class BRILLO_EXPORT ExportedPropertyBase {
+ public:
+ enum class Access {
+ kReadOnly,
+ kWriteOnly,
+ kReadWrite,
+ };
+
+ ExportedPropertyBase() = default;
+ virtual ~ExportedPropertyBase() = default;
+
+ using OnUpdateCallback = base::Callback<void(const ExportedPropertyBase*)>;
+
+ // Called by ExportedPropertySet to register a callback. This callback
+ // triggers ExportedPropertySet to send a signal from the properties
+ // interface of the exported object.
+ virtual void SetUpdateCallback(const OnUpdateCallback& cb);
+
+ // Returns the contained value as Any.
+ virtual brillo::Any GetValue() const = 0;
+
+ virtual bool SetValue(brillo::ErrorPtr* error,
+ const brillo::Any& value) = 0;
+
+ void SetAccessMode(Access access_mode);
+ Access GetAccessMode() const;
+
+ protected:
+ // Notify the listeners of OnUpdateCallback that the property has changed.
+ void NotifyPropertyChanged();
+
+ private:
+ OnUpdateCallback on_update_callback_;
+ // Default to read-only.
+ Access access_mode_{Access::kReadOnly};
+};
+
+class BRILLO_EXPORT ExportedPropertySet {
+ public:
+ using PropertyWriter = base::Callback<void(VariantDictionary* dict)>;
+
+ explicit ExportedPropertySet(dbus::Bus* bus);
+ virtual ~ExportedPropertySet() = default;
+
+ // Called to notify ExportedPropertySet that the Properties interface of the
+ // D-Bus object has been exported successfully and property notification
+ // signals can be sent out.
+ void OnPropertiesInterfaceExported(DBusInterface* prop_interface);
+
+ // Return a callback that knows how to write this property set's properties
+ // to a message. This writer retains a weak pointer to this, and must
+ // only be invoked on the same thread as the rest of ExportedPropertySet.
+ PropertyWriter GetPropertyWriter(const std::string& interface_name);
+
+ void RegisterProperty(const std::string& interface_name,
+ const std::string& property_name,
+ ExportedPropertyBase* exported_property);
+
+ // D-Bus methods for org.freedesktop.DBus.Properties interface.
+ VariantDictionary HandleGetAll(const std::string& interface_name);
+ bool HandleGet(brillo::ErrorPtr* error,
+ const std::string& interface_name,
+ const std::string& property_name,
+ brillo::Any* result);
+ // While Properties.Set has a handler to complete the interface, we don't
+ // support writable properties. This is almost a feature, since bindings for
+ // many languages don't support errors coming back from invalid writes.
+ // Instead, use setters in exposed interfaces.
+ bool HandleSet(brillo::ErrorPtr* error,
+ const std::string& interface_name,
+ const std::string& property_name,
+ const brillo::Any& value);
+ // Returns a string-to-variant map of all the properties for the given
+ // interface and their values.
+ VariantDictionary GetInterfaceProperties(
+ const std::string& interface_name) const;
+
+ private:
+ // Used to write the dictionary of string->variant to a message.
+ // This dictionary represents the property name/value pairs for the
+ // given interface.
+ BRILLO_PRIVATE void WritePropertiesToDict(const std::string& interface_name,
+ VariantDictionary* dict);
+ BRILLO_PRIVATE void HandlePropertyUpdated(
+ const std::string& interface_name,
+ const std::string& property_name,
+ const ExportedPropertyBase* exported_property);
+
+ dbus::Bus* bus_; // weak; owned by outer DBusObject containing this object.
+ // This is a map from interface name -> property name -> pointer to property.
+ std::map<std::string, std::map<std::string, ExportedPropertyBase*>>
+ properties_;
+
+ // D-Bus callbacks may last longer the property set exporting those methods.
+ base::WeakPtrFactory<ExportedPropertySet> weak_ptr_factory_;
+
+ using SignalPropertiesChanged =
+ DBusSignal<std::string, VariantDictionary, std::vector<std::string>>;
+
+ std::weak_ptr<SignalPropertiesChanged> signal_properties_changed_;
+
+ friend class DBusObject;
+ friend class ExportedPropertySetTest;
+ DISALLOW_COPY_AND_ASSIGN(ExportedPropertySet);
+};
+
+template<typename T>
+class ExportedProperty : public ExportedPropertyBase {
+ public:
+ ExportedProperty() = default;
+ ~ExportedProperty() override = default;
+
+ // Retrieves the current value.
+ const T& value() const { return value_; }
+
+ // Set the value exposed to remote applications. This triggers notifications
+ // of changes over the Properties interface.
+ void SetValue(const T& new_value) {
+ if (value_ != new_value) {
+ value_ = new_value;
+ this->NotifyPropertyChanged();
+ }
+ }
+
+ // Set the validator for value checking when setting the property by remote
+ // application.
+ void SetValidator(
+ const base::Callback<bool(brillo::ErrorPtr*, const T&)>& validator) {
+ validator_ = validator;
+ }
+
+ // Implementation provided by specialization.
+ brillo::Any GetValue() const override { return value_; }
+
+ bool SetValue(brillo::ErrorPtr* error,
+ const brillo::Any& value) override {
+ if (GetAccessMode() == ExportedPropertyBase::Access::kReadOnly) {
+ brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+ DBUS_ERROR_PROPERTY_READ_ONLY,
+ "Property is read-only.");
+ return false;
+ }
+ if (!value.IsTypeCompatible<T>()) {
+ brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+ DBUS_ERROR_INVALID_ARGS,
+ "Argument type mismatched.");
+ return false;
+ }
+ if (value_ == value.Get<T>()) {
+ // No change to the property value, nothing to be done.
+ return true;
+ }
+ if (!validator_.is_null() && !validator_.Run(error, value.Get<T>())) {
+ return false;
+ }
+ value_ = value.Get<T>();
+ return true;
+ }
+
+ private:
+ T value_{};
+ base::Callback<bool(brillo::ErrorPtr*, const T&)> validator_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExportedProperty);
+};
+
+} // namespace dbus_utils
+
+} // namespace brillo
+
+#endif // LIBCHROMEOS_BRILLO_DBUS_EXPORTED_PROPERTY_SET_H_