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