[email protected] | 9cc40cb | 2013-03-25 18:20:08 | [diff] [blame] | 1 | // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef DBUS_OBJECT_MANAGER_H_ |
| 6 | #define DBUS_OBJECT_MANAGER_H_ |
| 7 | |
avi | 22437c69 | 2015-12-22 18:12:45 | [diff] [blame] | 8 | #include <stdint.h> |
| 9 | |
[email protected] | 9cc40cb | 2013-03-25 18:20:08 | [diff] [blame] | 10 | #include <map> |
| 11 | |
avi | 22437c69 | 2015-12-22 18:12:45 | [diff] [blame] | 12 | #include "base/macros.h" |
[email protected] | 9cc40cb | 2013-03-25 18:20:08 | [diff] [blame] | 13 | #include "base/memory/ref_counted.h" |
| 14 | #include "base/memory/weak_ptr.h" |
| 15 | #include "dbus/object_path.h" |
| 16 | #include "dbus/property.h" |
| 17 | |
| 18 | // Newer D-Bus services implement the Object Manager interface to inform other |
| 19 | // clients about the objects they export, the properties of those objects, and |
| 20 | // notification of changes in the set of available objects: |
| 21 | // http://dbus.freedesktop.org/doc/dbus-specification.html |
| 22 | // #standard-interfaces-objectmanager |
| 23 | // |
| 24 | // This interface is very closely tied to the Properties interface, and uses |
| 25 | // even more levels of nested dictionaries and variants. In addition to |
| 26 | // simplifying implementation, since there tends to be a single object manager |
| 27 | // per service, spanning the complete set of objects an interfaces available, |
| 28 | // the classes implemented here make dealing with this interface simpler. |
| 29 | // |
| 30 | // Except where noted, use of this class replaces the need for the code |
| 31 | // documented in dbus/property.h |
| 32 | // |
| 33 | // Client implementation classes should begin by deriving from the |
| 34 | // dbus::ObjectManager::Interface class, and defining a Properties structure as |
| 35 | // documented in dbus/property.h. |
| 36 | // |
| 37 | // Example: |
| 38 | // class ExampleClient : public dbus::ObjectManager::Interface { |
| 39 | // public: |
| 40 | // struct Properties : public dbus::PropertySet { |
| 41 | // dbus::Property<std::string> name; |
avi | 22437c69 | 2015-12-22 18:12:45 | [diff] [blame] | 42 | // dbus::Property<uint16_t> version; |
[email protected] | 9cc40cb | 2013-03-25 18:20:08 | [diff] [blame] | 43 | // dbus::Property<dbus::ObjectPath> parent; |
| 44 | // dbus::Property<std::vector<std::string> > children; |
| 45 | // |
| 46 | // Properties(dbus::ObjectProxy* object_proxy, |
| 47 | // const PropertyChangedCallback callback) |
| 48 | // : dbus::PropertySet(object_proxy, kExampleInterface, callback) { |
| 49 | // RegisterProperty("Name", &name); |
| 50 | // RegisterProperty("Version", &version); |
| 51 | // RegisterProperty("Parent", &parent); |
| 52 | // RegisterProperty("Children", &children); |
| 53 | // } |
| 54 | // virtual ~Properties() {} |
| 55 | // }; |
| 56 | // |
| 57 | // The link between the implementation class and the object manager is set up |
| 58 | // in the constructor and removed in the destructor; the class should maintain |
| 59 | // a pointer to its object manager for use in other methods and establish |
| 60 | // itself as the implementation class for its interface. |
| 61 | // |
| 62 | // Example: |
| 63 | // explicit ExampleClient::ExampleClient(dbus::Bus* bus) |
| 64 | // : bus_(bus), |
| 65 | // weak_ptr_factory_(this) { |
| 66 | // object_manager_ = bus_->GetObjectManager(kServiceName, kManagerPath); |
| 67 | // object_manager_->RegisterInterface(kInterface, this); |
| 68 | // } |
| 69 | // |
| 70 | // virtual ExampleClient::~ExampleClient() { |
| 71 | // object_manager_->UnregisterInterface(kInterface); |
| 72 | // } |
| 73 | // |
| 74 | // The D-Bus thread manager takes care of issuing the necessary call to |
| 75 | // GetManagedObjects() after the implementation classes have been set up. |
| 76 | // |
| 77 | // The object manager interface class has one abstract method that must be |
| 78 | // implemented by the class to create Properties structures on demand. As well |
| 79 | // as implementing this, you will want to implement a public GetProperties() |
| 80 | // method. |
| 81 | // |
| 82 | // Example: |
| 83 | // dbus::PropertySet* CreateProperties(dbus::ObjectProxy* object_proxy, |
| 84 | // const std::string& interface_name) |
mostynb | a10ba53 | 2014-10-16 19:50:16 | [diff] [blame] | 85 | // override { |
[email protected] | 9cc40cb | 2013-03-25 18:20:08 | [diff] [blame] | 86 | // Properties* properties = new Properties( |
| 87 | // object_proxy, interface_name, |
| 88 | // base::Bind(&PropertyChanged, |
| 89 | // weak_ptr_factory_.GetWeakPtr(), |
| 90 | // object_path)); |
| 91 | // return static_cast<dbus::PropertySet*>(properties); |
| 92 | // } |
| 93 | // |
| 94 | // Properties* GetProperties(const dbus::ObjectPath& object_path) { |
| 95 | // return static_cast<Properties*>( |
| 96 | // object_manager_->GetProperties(object_path, kInterface)); |
| 97 | // } |
| 98 | // |
| 99 | // Note that unlike classes that only use dbus/property.h there is no need |
| 100 | // to connect signals or obtain the initial values of properties. The object |
| 101 | // manager class handles that for you. |
| 102 | // |
| 103 | // PropertyChanged is a method of your own to notify your observers of a change |
| 104 | // in your properties, either as a result of a signal from the Properties |
| 105 | // interface or from the Object Manager interface. You may also wish to |
| 106 | // implement the optional ObjectAdded and ObjectRemoved methods of the class |
| 107 | // to likewise notify observers. |
| 108 | // |
| 109 | // When your class needs an object proxy for a given object path, it may |
| 110 | // obtain it from the object manager. Unlike the equivalent method on the bus |
| 111 | // this will return NULL if the object is not known. |
| 112 | // |
| 113 | // object_proxy = object_manager_->GetObjectProxy(object_path); |
| 114 | // if (object_proxy) { |
| 115 | // ... |
| 116 | // } |
| 117 | // |
| 118 | // There is no need for code using your implementation class to be aware of the |
| 119 | // use of object manager behind the scenes, the rules for updating properties |
| 120 | // documented in dbus/property.h still apply. |
| 121 | |
| 122 | namespace dbus { |
| 123 | |
| 124 | const char kObjectManagerInterface[] = "org.freedesktop.DBus.ObjectManager"; |
| 125 | const char kObjectManagerGetManagedObjects[] = "GetManagedObjects"; |
| 126 | const char kObjectManagerInterfacesAdded[] = "InterfacesAdded"; |
| 127 | const char kObjectManagerInterfacesRemoved[] = "InterfacesRemoved"; |
| 128 | |
| 129 | class Bus; |
| 130 | class MessageReader; |
| 131 | class ObjectProxy; |
| 132 | class Response; |
| 133 | class Signal; |
| 134 | |
| 135 | // ObjectManager implements both the D-Bus client components of the D-Bus |
| 136 | // Object Manager interface, as internal methods, and a public API for |
| 137 | // client classes to utilize. |
| 138 | class CHROME_DBUS_EXPORT ObjectManager |
| 139 | : public base::RefCountedThreadSafe<ObjectManager> { |
| 140 | public: |
| 141 | // ObjectManager::Interface must be implemented by any class wishing to have |
| 142 | // its remote objects managed by an ObjectManager. |
| 143 | class Interface { |
| 144 | public: |
| 145 | virtual ~Interface() {} |
| 146 | |
| 147 | // Called by ObjectManager to create a Properties structure for the remote |
| 148 | // D-Bus object identified by |object_path| and accessibile through |
| 149 | // |object_proxy|. The D-Bus interface name |interface_name| is that passed |
| 150 | // to RegisterInterface() by the implementation class. |
| 151 | // |
| 152 | // The implementation class should create and return an instance of its own |
| 153 | // subclass of dbus::PropertySet; ObjectManager will then connect signals |
| 154 | // and update the properties from its own internal message reader. |
| 155 | virtual PropertySet* CreateProperties( |
| 156 | ObjectProxy *object_proxy, |
| 157 | const dbus::ObjectPath& object_path, |
| 158 | const std::string& interface_name) = 0; |
| 159 | |
| 160 | // Called by ObjectManager to inform the implementation class that an |
| 161 | // object has been added with the path |object_path|. The D-Bus interface |
| 162 | // name |interface_name| is that passed to RegisterInterface() by the |
| 163 | // implementation class. |
| 164 | // |
| 165 | // If a new object implements multiple interfaces, this method will be |
| 166 | // called on each interface implementation with differing values of |
| 167 | // |interface_name| as appropriate. An implementation class will only |
| 168 | // receive multiple calls if it has registered for multiple interfaces. |
| 169 | virtual void ObjectAdded(const ObjectPath& object_path, |
| 170 | const std::string& interface_name) { } |
| 171 | |
| 172 | // Called by ObjectManager to inform the implementation class than an |
| 173 | // object with the path |object_path| has been removed. Ths D-Bus interface |
| 174 | // name |interface_name| is that passed to RegisterInterface() by the |
| 175 | // implementation class. Multiple interfaces are handled as with |
| 176 | // ObjectAdded(). |
| 177 | // |
| 178 | // This method will be called before the Properties structure and the |
| 179 | // ObjectProxy object for the given interface are cleaned up, it is safe |
| 180 | // to retrieve them during removal to vary processing. |
| 181 | virtual void ObjectRemoved(const ObjectPath& object_path, |
| 182 | const std::string& interface_name) { } |
| 183 | }; |
| 184 | |
| 185 | // Client code should use Bus::GetObjectManager() instead of this constructor. |
| 186 | ObjectManager(Bus* bus, |
| 187 | const std::string& service_name, |
| 188 | const ObjectPath& object_path); |
| 189 | |
| 190 | // Register a client implementation class |interface| for the given D-Bus |
| 191 | // interface named in |interface_name|. That object's CreateProperties() |
| 192 | // method will be used to create instances of dbus::PropertySet* when |
| 193 | // required. |
| 194 | void RegisterInterface(const std::string& interface_name, |
| 195 | Interface* interface); |
| 196 | |
| 197 | // Unregister the implementation class for the D-Bus interface named in |
| 198 | // |interface_name|, objects and properties of this interface will be |
| 199 | // ignored. |
| 200 | void UnregisterInterface(const std::string& interface_name); |
| 201 | |
| 202 | // Returns a list of object paths, in an undefined order, of objects known |
| 203 | // to this manager. |
| 204 | std::vector<ObjectPath> GetObjects(); |
| 205 | |
| 206 | // Returns the list of object paths, in an undefined order, of objects |
| 207 | // implementing the interface named in |interface_name| known to this manager. |
| 208 | std::vector<ObjectPath> GetObjectsWithInterface( |
| 209 | const std::string& interface_name); |
| 210 | |
| 211 | // Returns a ObjectProxy pointer for the given |object_path|. Unlike |
| 212 | // the equivalent method on Bus this will return NULL if the object |
| 213 | // manager has not been informed of that object's existance. |
| 214 | ObjectProxy* GetObjectProxy(const ObjectPath& object_path); |
| 215 | |
| 216 | // Returns a PropertySet* pointer for the given |object_path| and |
| 217 | // |interface_name|, or NULL if the object manager has not been informed of |
| 218 | // that object's existance or the interface's properties. The caller should |
| 219 | // cast the returned pointer to the appropriate type, e.g.: |
| 220 | // static_cast<Properties*>(GetProperties(object_path, my_interface)); |
| 221 | PropertySet* GetProperties(const ObjectPath& object_path, |
| 222 | const std::string& interface_name); |
| 223 | |
| 224 | // Instructs the object manager to refresh its list of managed objects; |
| 225 | // automatically called by the D-Bus thread manager, there should never be |
| 226 | // a need to call this manually. |
| 227 | void GetManagedObjects(); |
| 228 | |
armansito | ebff093d | 2014-09-05 17:49:34 | [diff] [blame] | 229 | // Cleans up any match rules and filter functions added by this ObjectManager. |
| 230 | // The Bus object will take care of this so you don't have to do it manually. |
| 231 | // |
| 232 | // BLOCKING CALL. |
| 233 | void CleanUp(); |
| 234 | |
[email protected] | 9cc40cb | 2013-03-25 18:20:08 | [diff] [blame] | 235 | protected: |
| 236 | virtual ~ObjectManager(); |
| 237 | |
| 238 | private: |
| 239 | friend class base::RefCountedThreadSafe<ObjectManager>; |
| 240 | |
armansito | ebff093d | 2014-09-05 17:49:34 | [diff] [blame] | 241 | // Connects the InterfacesAdded and InterfacesRemoved signals and calls |
| 242 | // GetManagedObjects. Called from OnSetupMatchRuleAndFilterComplete. |
| 243 | void InitializeObjects(); |
| 244 | |
| 245 | // Called from the constructor to add a match rule for PropertiesChanged |
| 246 | // signals on the DBus thread and set up a corresponding filter function. |
| 247 | bool SetupMatchRuleAndFilter(); |
| 248 | |
| 249 | // Called on the origin thread once the match rule and filter have been set |
| 250 | // up. |success| is false, if an error occurred during set up; it's true |
| 251 | // otherwise. |
| 252 | void OnSetupMatchRuleAndFilterComplete(bool success); |
| 253 | |
| 254 | // Called by dbus:: when a message is received. This is used to filter |
| 255 | // PropertiesChanged signals from the correct sender and relay the event to |
| 256 | // the correct PropertySet. |
| 257 | static DBusHandlerResult HandleMessageThunk(DBusConnection* connection, |
| 258 | DBusMessage* raw_message, |
| 259 | void* user_data); |
| 260 | DBusHandlerResult HandleMessage(DBusConnection* connection, |
| 261 | DBusMessage* raw_message); |
| 262 | |
| 263 | // Called when a PropertiesChanged signal is received from the sender. |
| 264 | // This method notifies the relevant PropertySet that it should update its |
| 265 | // properties based on the received signal. Called from HandleMessage. |
| 266 | void NotifyPropertiesChanged(const dbus::ObjectPath object_path, |
| 267 | Signal* signal); |
| 268 | void NotifyPropertiesChangedHelper(const dbus::ObjectPath object_path, |
| 269 | Signal* signal); |
[email protected] | 9cc40cb | 2013-03-25 18:20:08 | [diff] [blame] | 270 | |
| 271 | // Called by dbus:: in response to the GetManagedObjects() method call. |
| 272 | void OnGetManagedObjects(Response* response); |
| 273 | |
| 274 | // Called by dbus:: when an InterfacesAdded signal is received and initially |
| 275 | // connected. |
| 276 | void InterfacesAddedReceived(Signal* signal); |
| 277 | void InterfacesAddedConnected(const std::string& interface_name, |
| 278 | const std::string& signal_name, |
| 279 | bool success); |
| 280 | |
| 281 | // Called by dbus:: when an InterfacesRemoved signal is received and |
| 282 | // initially connected. |
| 283 | void InterfacesRemovedReceived(Signal* signal); |
| 284 | void InterfacesRemovedConnected(const std::string& interface_name, |
| 285 | const std::string& signal_name, |
| 286 | bool success); |
| 287 | |
| 288 | // Updates the map entry for the object with path |object_path| using the |
| 289 | // D-Bus message in |reader|, which should consist of an dictionary mapping |
| 290 | // interface names to properties dictionaries as recieved by both the |
| 291 | // GetManagedObjects() method return and the InterfacesAdded() signal. |
| 292 | void UpdateObject(const ObjectPath& object_path, MessageReader* reader); |
| 293 | |
| 294 | // Updates the properties structure of the object with path |object_path| |
| 295 | // for the interface named |interface_name| using the D-Bus message in |
| 296 | // |reader| which should consist of the properties dictionary for that |
| 297 | // interface. |
| 298 | // |
| 299 | // Called by UpdateObjects() for each interface in the dictionary; this |
| 300 | // method takes care of both creating the entry in the ObjectMap and |
| 301 | // ObjectProxy if required, as well as the PropertySet instance for that |
| 302 | // interface if necessary. |
| 303 | void AddInterface(const ObjectPath& object_path, |
| 304 | const std::string& interface_name, |
| 305 | MessageReader* reader); |
| 306 | |
| 307 | // Removes the properties structure of the object with path |object_path| |
| 308 | // for the interfaces named |interface_name|. |
| 309 | // |
| 310 | // If no further interfaces remain, the entry in the ObjectMap is discarded. |
| 311 | void RemoveInterface(const ObjectPath& object_path, |
| 312 | const std::string& interface_name); |
| 313 | |
[email protected] | 043fb8c | 2014-03-07 02:24:33 | [diff] [blame] | 314 | // Removes all objects and interfaces from the object manager when |
| 315 | // |old_owner| is not the empty string and/or re-requests the set of managed |
| 316 | // objects when |new_owner| is not the empty string. |
| 317 | void NameOwnerChanged(const std::string& old_owner, |
| 318 | const std::string& new_owner); |
| 319 | |
[email protected] | 9cc40cb | 2013-03-25 18:20:08 | [diff] [blame] | 320 | Bus* bus_; |
| 321 | std::string service_name_; |
armansito | ebff093d | 2014-09-05 17:49:34 | [diff] [blame] | 322 | std::string service_name_owner_; |
| 323 | std::string match_rule_; |
[email protected] | 9cc40cb | 2013-03-25 18:20:08 | [diff] [blame] | 324 | ObjectPath object_path_; |
| 325 | ObjectProxy* object_proxy_; |
armansito | ebff093d | 2014-09-05 17:49:34 | [diff] [blame] | 326 | bool setup_success_; |
| 327 | bool cleanup_called_; |
[email protected] | 9cc40cb | 2013-03-25 18:20:08 | [diff] [blame] | 328 | |
| 329 | // Maps the name of an interface to the implementation class used for |
| 330 | // instantiating PropertySet structures for that interface's properties. |
| 331 | typedef std::map<std::string, Interface*> InterfaceMap; |
| 332 | InterfaceMap interface_map_; |
| 333 | |
| 334 | // Each managed object consists of a ObjectProxy used to make calls |
| 335 | // against that object and a collection of D-Bus interface names and their |
| 336 | // associated PropertySet structures. |
| 337 | struct Object { |
| 338 | Object(); |
| 339 | ~Object(); |
| 340 | |
| 341 | ObjectProxy* object_proxy; |
| 342 | |
| 343 | // Maps the name of an interface to the specific PropertySet structure |
| 344 | // of that interface's properties. |
| 345 | typedef std::map<const std::string, PropertySet*> PropertiesMap; |
| 346 | PropertiesMap properties_map; |
| 347 | }; |
| 348 | |
| 349 | // Maps the object path of an object to the Object structure. |
| 350 | typedef std::map<const ObjectPath, Object*> ObjectMap; |
| 351 | ObjectMap object_map_; |
| 352 | |
| 353 | // Weak pointer factory for generating 'this' pointers that might live longer |
| 354 | // than we do. |
| 355 | // Note: This should remain the last member so it'll be destroyed and |
| 356 | // invalidate its weak pointers before any other members are destroyed. |
| 357 | base::WeakPtrFactory<ObjectManager> weak_ptr_factory_; |
| 358 | |
| 359 | DISALLOW_COPY_AND_ASSIGN(ObjectManager); |
| 360 | }; |
| 361 | |
| 362 | } // namespace dbus |
| 363 | |
| 364 | #endif // DBUS_OBJECT_MANAGER_H_ |