blob: 266b53eb9a0ac3d140d468114701af3ecad17ba9 [file] [log] [blame]
[email protected]9cc40cb2013-03-25 18:20:081// 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
avi22437c692015-12-22 18:12:458#include <stdint.h>
9
[email protected]9cc40cb2013-03-25 18:20:0810#include <map>
11
avi22437c692015-12-22 18:12:4512#include "base/macros.h"
[email protected]9cc40cb2013-03-25 18:20:0813#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;
avi22437c692015-12-22 18:12:4542// dbus::Property<uint16_t> version;
[email protected]9cc40cb2013-03-25 18:20:0843// 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)
mostynba10ba532014-10-16 19:50:1685// override {
[email protected]9cc40cb2013-03-25 18:20:0886// 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
122namespace dbus {
123
124const char kObjectManagerInterface[] = "org.freedesktop.DBus.ObjectManager";
125const char kObjectManagerGetManagedObjects[] = "GetManagedObjects";
126const char kObjectManagerInterfacesAdded[] = "InterfacesAdded";
127const char kObjectManagerInterfacesRemoved[] = "InterfacesRemoved";
128
129class Bus;
130class MessageReader;
131class ObjectProxy;
132class Response;
133class 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.
138class CHROME_DBUS_EXPORT ObjectManager
139 : public base::RefCountedThreadSafe<ObjectManager> {
140public:
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
armansitoebff093d2014-09-05 17:49:34229 // 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]9cc40cb2013-03-25 18:20:08235 protected:
236 virtual ~ObjectManager();
237
238 private:
239 friend class base::RefCountedThreadSafe<ObjectManager>;
240
armansitoebff093d2014-09-05 17:49:34241 // 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]9cc40cb2013-03-25 18:20:08270
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]043fb8c2014-03-07 02:24:33314 // 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]9cc40cb2013-03-25 18:20:08320 Bus* bus_;
321 std::string service_name_;
armansitoebff093d2014-09-05 17:49:34322 std::string service_name_owner_;
323 std::string match_rule_;
[email protected]9cc40cb2013-03-25 18:20:08324 ObjectPath object_path_;
325 ObjectProxy* object_proxy_;
armansitoebff093d2014-09-05 17:49:34326 bool setup_success_;
327 bool cleanup_called_;
[email protected]9cc40cb2013-03-25 18:20:08328
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_