Home | History | Annotate | Download | only in dbus
      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:
    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 
    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