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 <stdint.h> 9 10 #include <map> 11 12 #include "base/macros.h" 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; 42 // dbus::Property<uint16_t> version; 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) 85 // override { 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: ~Interface()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. ObjectAdded(const ObjectPath &,const std::string &)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. ObjectRemoved(const ObjectPath &,const std::string &)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 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 235 protected: 236 virtual ~ObjectManager(); 237 238 private: 239 friend class base::RefCountedThreadSafe<ObjectManager>; 240 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); 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 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 320 Bus* bus_; 321 std::string service_name_; 322 std::string service_name_owner_; 323 std::string match_rule_; 324 ObjectPath object_path_; 325 ObjectProxy* object_proxy_; 326 bool setup_success_; 327 bool cleanup_called_; 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_ 365