| // 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_CHROMEOS_EXPORTED_PROPERTY_SET_H_ |
| #define LIBCHROMEOS_CHROMEOS_EXPORTED_PROPERTY_SET_H_ |
| |
| #include <stdint.h> |
| |
| #include <map> |
| #include <string> |
| #include <vector> |
| |
| #include <base/memory/weak_ptr.h> |
| #include <dbus/exported_object.h> |
| #include <dbus/message.h> |
| |
| namespace chromeos { |
| |
| 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. |
| // |
| // Example usage: |
| // |
| // class ExampleObjectExportingProperties { |
| // public: |
| // ExampleObjectExportingProperties(ExportedObject* exported_object) |
| // : p_(exported_object) { |
| // // Initialize properties appropriately. Do this before |
| // // claiming the Properties interface so that daemons watching |
| // // this object don't see partial or inaccurate state. |
| // p_.ClaimPropertiesInterface(); |
| // } |
| // |
| // private: |
| // struct Properties : public chromeos::dbus_utils::ExportedPropertySet { |
| // public: |
| // chromeos::dbus_utils::ExportedProperty<std::string> name_; |
| // chromeos::dbus_utils::ExportedProperty<uint16_t> version_; |
| // chromeos::dbus_utils::ExportedProperty<dbus::ObjectPath> parent_; |
| // chromeos::dbus_utils::ExportedProperty<std::vector<std::string>> |
| // children_; |
| // |
| // Properties(dbus_utils::ExportedObject* exported_object) |
| // : chromeos::dbus::ExportedPropertySet(exported_object) { |
| // RegisterProperty(kExampleInterfaceName, "Name", &name_); |
| // RegisterProperty(kExampleInterfaceName, "Version", &version_); |
| // RegisterProperty(kExampleInterfaceName, "Parent", &parent_); |
| // RegisterProperty(kExampleInterfaceName, "Children", &children_); |
| // } |
| // virtual ~Properties() {} |
| // }; |
| // |
| // Properties p_; |
| // }; |
| |
| class ExportedPropertyBase { |
| public: |
| 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); |
| |
| // Appends a variant of the contained value to the writer. This is |
| // needed to write out properties to Get and GetAll methods implemented |
| // by the ExportedPropertySet since it doesn't actually know the type |
| // of each property. |
| virtual void AppendValueToWriter(dbus::MessageWriter* writer) const = 0; |
| |
| protected: |
| // Notify the listeners of OnUpdateCallback that the property has changed. |
| void NotifyPropertyChanged(); |
| |
| private: |
| OnUpdateCallback on_update_callback_; |
| }; |
| |
| class ExportedPropertySet { |
| public: |
| typedef base::Callback<void(bool success)> OnInitFinish; |
| typedef base::Callback<void(dbus::MessageWriter* writer)> PropertyWriter; |
| |
| ExportedPropertySet(dbus::Bus* bus, const dbus::ObjectPath& path); |
| virtual ~ExportedPropertySet() = default; |
| |
| // Claims the method associated with the org.freedesktop.DBus.Properties |
| // interface. This needs to be done after all properties are initialized to |
| // appropriate values. This method will call |cb| when all methods |
| // are exported to the DBus object. |cb| will be called on the origin |
| // thread. |
| void Init(const OnInitFinish& cb); |
| |
| // 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); |
| |
| protected: |
| void RegisterProperty(const std::string& interface_name, |
| const std::string& property_name, |
| ExportedPropertyBase* exported_property); |
| |
| private: |
| // Used to write the dictionary of string->variant to a message. |
| // This dictionary represents the property name/value pairs for the |
| // given interface. |
| void WritePropertiesDictToMessage(const std::string& interface_name, |
| dbus::MessageWriter* writer); |
| void HandleGetAll(dbus::MethodCall* method_call, |
| dbus::ExportedObject::ResponseSender response_sender); |
| void HandleGet(dbus::MethodCall* method_call, |
| dbus::ExportedObject::ResponseSender response_sender); |
| // 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. |
| void HandleSet(dbus::MethodCall* method_call, |
| dbus::ExportedObject::ResponseSender response_sender); |
| void HandlePropertyUpdated(const std::string& interface, |
| const std::string& name, |
| const ExportedPropertyBase* property); |
| |
| dbus::Bus* bus_; |
| dbus::ExportedObject* exported_object_; // weak; owned by the Bus 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_; |
| |
| friend class ExportedPropertySetTest; |
| DISALLOW_COPY_AND_ASSIGN(ExportedPropertySet); |
| }; |
| |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, bool value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, uint8_t value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, int16_t value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, uint16_t value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, int32_t value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, uint32_t value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, int64_t value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, uint64_t value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, double value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, |
| const std::string& value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, |
| const dbus::ObjectPath& value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, |
| const std::vector<std::string>& value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, |
| const std::vector<dbus::ObjectPath>& value); |
| void AppendPropertyToWriter(dbus::MessageWriter* writer, |
| const std::vector<uint8_t>& value); |
| |
| 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(); |
| } |
| } |
| |
| // Implementation provided by specialization. |
| void AppendValueToWriter(dbus::MessageWriter* writer) const override { |
| AppendPropertyToWriter(writer, value_); |
| } |
| |
| private: |
| T value_{}; |
| |
| DISALLOW_COPY_AND_ASSIGN(ExportedProperty); |
| }; |
| |
| } // namespace dbus_utils |
| |
| } // namespace chromeos |
| |
| #endif // LIBCHROMEOS_CHROMEOS_EXPORTED_PROPERTY_SET_H_ |