You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
363 lines
16 KiB
363 lines
16 KiB
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef DBUS_OBJECT_MANAGER_H_
|
|
#define DBUS_OBJECT_MANAGER_H_
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <map>
|
|
|
|
#include "base/macros.h"
|
|
#include "base/memory/ref_counted.h"
|
|
#include "base/memory/weak_ptr.h"
|
|
#include "dbus/object_path.h"
|
|
#include "dbus/property.h"
|
|
|
|
// Newer D-Bus services implement the Object Manager interface to inform other
|
|
// clients about the objects they export, the properties of those objects, and
|
|
// notification of changes in the set of available objects:
|
|
// http://dbus.freedesktop.org/doc/dbus-specification.html
|
|
// #standard-interfaces-objectmanager
|
|
//
|
|
// This interface is very closely tied to the Properties interface, and uses
|
|
// even more levels of nested dictionaries and variants. In addition to
|
|
// simplifying implementation, since there tends to be a single object manager
|
|
// per service, spanning the complete set of objects an interfaces available,
|
|
// the classes implemented here make dealing with this interface simpler.
|
|
//
|
|
// Except where noted, use of this class replaces the need for the code
|
|
// documented in dbus/property.h
|
|
//
|
|
// Client implementation classes should begin by deriving from the
|
|
// dbus::ObjectManager::Interface class, and defining a Properties structure as
|
|
// documented in dbus/property.h.
|
|
//
|
|
// Example:
|
|
// class ExampleClient : public dbus::ObjectManager::Interface {
|
|
// public:
|
|
// struct Properties : public dbus::PropertySet {
|
|
// dbus::Property<std::string> name;
|
|
// dbus::Property<uint16_t> version;
|
|
// dbus::Property<dbus::ObjectPath> parent;
|
|
// dbus::Property<std::vector<std::string>> children;
|
|
//
|
|
// Properties(dbus::ObjectProxy* object_proxy,
|
|
// const PropertyChangedCallback callback)
|
|
// : dbus::PropertySet(object_proxy, kExampleInterface, callback) {
|
|
// RegisterProperty("Name", &name);
|
|
// RegisterProperty("Version", &version);
|
|
// RegisterProperty("Parent", &parent);
|
|
// RegisterProperty("Children", &children);
|
|
// }
|
|
// virtual ~Properties() {}
|
|
// };
|
|
//
|
|
// The link between the implementation class and the object manager is set up
|
|
// in the constructor and removed in the destructor; the class should maintain
|
|
// a pointer to its object manager for use in other methods and establish
|
|
// itself as the implementation class for its interface.
|
|
//
|
|
// Example:
|
|
// explicit ExampleClient::ExampleClient(dbus::Bus* bus)
|
|
// : bus_(bus),
|
|
// weak_ptr_factory_(this) {
|
|
// object_manager_ = bus_->GetObjectManager(kServiceName, kManagerPath);
|
|
// object_manager_->RegisterInterface(kInterface, this);
|
|
// }
|
|
//
|
|
// virtual ExampleClient::~ExampleClient() {
|
|
// object_manager_->UnregisterInterface(kInterface);
|
|
// }
|
|
//
|
|
// This class calls GetManagedObjects() asynchronously after the remote service
|
|
// becomes available and additionally refreshes managed objects after the
|
|
// service stops or restarts.
|
|
//
|
|
// The object manager interface class has one abstract method that must be
|
|
// implemented by the class to create Properties structures on demand. As well
|
|
// as implementing this, you will want to implement a public GetProperties()
|
|
// method.
|
|
//
|
|
// Example:
|
|
// dbus::PropertySet* CreateProperties(dbus::ObjectProxy* object_proxy,
|
|
// const std::string& interface_name)
|
|
// override {
|
|
// Properties* properties = new Properties(
|
|
// object_proxy, interface_name,
|
|
// base::Bind(&PropertyChanged,
|
|
// weak_ptr_factory_.GetWeakPtr(),
|
|
// object_path));
|
|
// return static_cast<dbus::PropertySet*>(properties);
|
|
// }
|
|
//
|
|
// Properties* GetProperties(const dbus::ObjectPath& object_path) {
|
|
// return static_cast<Properties*>(
|
|
// object_manager_->GetProperties(object_path, kInterface));
|
|
// }
|
|
//
|
|
// Note that unlike classes that only use dbus/property.h there is no need
|
|
// to connect signals or obtain the initial values of properties. The object
|
|
// manager class handles that for you.
|
|
//
|
|
// PropertyChanged is a method of your own to notify your observers of a change
|
|
// in your properties, either as a result of a signal from the Properties
|
|
// interface or from the Object Manager interface. You may also wish to
|
|
// implement the optional ObjectAdded and ObjectRemoved methods of the class
|
|
// to likewise notify observers.
|
|
//
|
|
// When your class needs an object proxy for a given object path, it may
|
|
// obtain it from the object manager. Unlike the equivalent method on the bus
|
|
// this will return NULL if the object is not known.
|
|
//
|
|
// object_proxy = object_manager_->GetObjectProxy(object_path);
|
|
// if (object_proxy) {
|
|
// ...
|
|
// }
|
|
//
|
|
// There is no need for code using your implementation class to be aware of the
|
|
// use of object manager behind the scenes, the rules for updating properties
|
|
// documented in dbus/property.h still apply.
|
|
|
|
namespace dbus {
|
|
|
|
const char kObjectManagerInterface[] = "org.freedesktop.DBus.ObjectManager";
|
|
const char kObjectManagerGetManagedObjects[] = "GetManagedObjects";
|
|
const char kObjectManagerInterfacesAdded[] = "InterfacesAdded";
|
|
const char kObjectManagerInterfacesRemoved[] = "InterfacesRemoved";
|
|
|
|
class Bus;
|
|
class MessageReader;
|
|
class ObjectProxy;
|
|
class Response;
|
|
class Signal;
|
|
|
|
// ObjectManager implements both the D-Bus client components of the D-Bus
|
|
// Object Manager interface, as internal methods, and a public API for
|
|
// client classes to utilize.
|
|
class CHROME_DBUS_EXPORT ObjectManager
|
|
: public base::RefCountedThreadSafe<ObjectManager> {
|
|
public:
|
|
// ObjectManager::Interface must be implemented by any class wishing to have
|
|
// its remote objects managed by an ObjectManager.
|
|
class Interface {
|
|
public:
|
|
virtual ~Interface() {}
|
|
|
|
// Called by ObjectManager to create a Properties structure for the remote
|
|
// D-Bus object identified by |object_path| and accessibile through
|
|
// |object_proxy|. The D-Bus interface name |interface_name| is that passed
|
|
// to RegisterInterface() by the implementation class.
|
|
//
|
|
// The implementation class should create and return an instance of its own
|
|
// subclass of dbus::PropertySet; ObjectManager will then connect signals
|
|
// and update the properties from its own internal message reader.
|
|
virtual PropertySet* CreateProperties(
|
|
ObjectProxy *object_proxy,
|
|
const dbus::ObjectPath& object_path,
|
|
const std::string& interface_name) = 0;
|
|
|
|
// Called by ObjectManager to inform the implementation class that an
|
|
// object has been added with the path |object_path|. The D-Bus interface
|
|
// name |interface_name| is that passed to RegisterInterface() by the
|
|
// implementation class.
|
|
//
|
|
// If a new object implements multiple interfaces, this method will be
|
|
// called on each interface implementation with differing values of
|
|
// |interface_name| as appropriate. An implementation class will only
|
|
// receive multiple calls if it has registered for multiple interfaces.
|
|
virtual void ObjectAdded(const ObjectPath& object_path,
|
|
const std::string& interface_name) { }
|
|
|
|
// Called by ObjectManager to inform the implementation class than an
|
|
// object with the path |object_path| has been removed. Ths D-Bus interface
|
|
// name |interface_name| is that passed to RegisterInterface() by the
|
|
// implementation class. Multiple interfaces are handled as with
|
|
// ObjectAdded().
|
|
//
|
|
// This method will be called before the Properties structure and the
|
|
// ObjectProxy object for the given interface are cleaned up, it is safe
|
|
// to retrieve them during removal to vary processing.
|
|
virtual void ObjectRemoved(const ObjectPath& object_path,
|
|
const std::string& interface_name) { }
|
|
};
|
|
|
|
// Client code should use Bus::GetObjectManager() instead of this constructor.
|
|
ObjectManager(Bus* bus,
|
|
const std::string& service_name,
|
|
const ObjectPath& object_path);
|
|
|
|
// Register a client implementation class |interface| for the given D-Bus
|
|
// interface named in |interface_name|. That object's CreateProperties()
|
|
// method will be used to create instances of dbus::PropertySet* when
|
|
// required.
|
|
virtual void RegisterInterface(const std::string& interface_name,
|
|
Interface* interface);
|
|
|
|
// Unregister the implementation class for the D-Bus interface named in
|
|
// |interface_name|, objects and properties of this interface will be
|
|
// ignored.
|
|
virtual void UnregisterInterface(const std::string& interface_name);
|
|
|
|
// Returns a list of object paths, in an undefined order, of objects known
|
|
// to this manager.
|
|
virtual std::vector<ObjectPath> GetObjects();
|
|
|
|
// Returns the list of object paths, in an undefined order, of objects
|
|
// implementing the interface named in |interface_name| known to this manager.
|
|
virtual std::vector<ObjectPath> GetObjectsWithInterface(
|
|
const std::string& interface_name);
|
|
|
|
// Returns a ObjectProxy pointer for the given |object_path|. Unlike
|
|
// the equivalent method on Bus this will return NULL if the object
|
|
// manager has not been informed of that object's existence.
|
|
virtual ObjectProxy* GetObjectProxy(const ObjectPath& object_path);
|
|
|
|
// Returns a PropertySet* pointer for the given |object_path| and
|
|
// |interface_name|, or NULL if the object manager has not been informed of
|
|
// that object's existence or the interface's properties. The caller should
|
|
// cast the returned pointer to the appropriate type, e.g.:
|
|
// static_cast<Properties*>(GetProperties(object_path, my_interface));
|
|
virtual PropertySet* GetProperties(const ObjectPath& object_path,
|
|
const std::string& interface_name);
|
|
|
|
// Instructs the object manager to refresh its list of managed objects;
|
|
// automatically called by the D-Bus thread manager, there should never be
|
|
// a need to call this manually.
|
|
void GetManagedObjects();
|
|
|
|
// Cleans up any match rules and filter functions added by this ObjectManager.
|
|
// The Bus object will take care of this so you don't have to do it manually.
|
|
//
|
|
// BLOCKING CALL.
|
|
void CleanUp();
|
|
|
|
protected:
|
|
virtual ~ObjectManager();
|
|
|
|
private:
|
|
friend class base::RefCountedThreadSafe<ObjectManager>;
|
|
|
|
// Called from the constructor to add a match rule for PropertiesChanged
|
|
// signals on the D-Bus thread and set up a corresponding filter function.
|
|
bool SetupMatchRuleAndFilter();
|
|
|
|
// Called on the origin thread once the match rule and filter have been set
|
|
// up. Connects the InterfacesAdded and InterfacesRemoved signals and
|
|
// refreshes objects if the service is available. |success| is false if an
|
|
// error occurred during setup and true otherwise.
|
|
void OnSetupMatchRuleAndFilterComplete(bool success);
|
|
|
|
// Called by dbus:: when a message is received. This is used to filter
|
|
// PropertiesChanged signals from the correct sender and relay the event to
|
|
// the correct PropertySet.
|
|
static DBusHandlerResult HandleMessageThunk(DBusConnection* connection,
|
|
DBusMessage* raw_message,
|
|
void* user_data);
|
|
DBusHandlerResult HandleMessage(DBusConnection* connection,
|
|
DBusMessage* raw_message);
|
|
|
|
// Called when a PropertiesChanged signal is received from the sender.
|
|
// This method notifies the relevant PropertySet that it should update its
|
|
// properties based on the received signal. Called from HandleMessage.
|
|
void NotifyPropertiesChanged(const dbus::ObjectPath object_path,
|
|
Signal* signal);
|
|
void NotifyPropertiesChangedHelper(const dbus::ObjectPath object_path,
|
|
Signal* signal);
|
|
|
|
// Called by dbus:: in response to the GetManagedObjects() method call.
|
|
void OnGetManagedObjects(Response* response);
|
|
|
|
// Called by dbus:: when an InterfacesAdded signal is received and initially
|
|
// connected.
|
|
void InterfacesAddedReceived(Signal* signal);
|
|
void InterfacesAddedConnected(const std::string& interface_name,
|
|
const std::string& signal_name,
|
|
bool success);
|
|
|
|
// Called by dbus:: when an InterfacesRemoved signal is received and
|
|
// initially connected.
|
|
void InterfacesRemovedReceived(Signal* signal);
|
|
void InterfacesRemovedConnected(const std::string& interface_name,
|
|
const std::string& signal_name,
|
|
bool success);
|
|
|
|
// Updates the map entry for the object with path |object_path| using the
|
|
// D-Bus message in |reader|, which should consist of an dictionary mapping
|
|
// interface names to properties dictionaries as recieved by both the
|
|
// GetManagedObjects() method return and the InterfacesAdded() signal.
|
|
void UpdateObject(const ObjectPath& object_path, MessageReader* reader);
|
|
|
|
// Updates the properties structure of the object with path |object_path|
|
|
// for the interface named |interface_name| using the D-Bus message in
|
|
// |reader| which should consist of the properties dictionary for that
|
|
// interface.
|
|
//
|
|
// Called by UpdateObjects() for each interface in the dictionary; this
|
|
// method takes care of both creating the entry in the ObjectMap and
|
|
// ObjectProxy if required, as well as the PropertySet instance for that
|
|
// interface if necessary.
|
|
void AddInterface(const ObjectPath& object_path,
|
|
const std::string& interface_name,
|
|
MessageReader* reader);
|
|
|
|
// Removes the properties structure of the object with path |object_path|
|
|
// for the interfaces named |interface_name|.
|
|
//
|
|
// If no further interfaces remain, the entry in the ObjectMap is discarded.
|
|
void RemoveInterface(const ObjectPath& object_path,
|
|
const std::string& interface_name);
|
|
|
|
// Removes all objects and interfaces from the object manager when
|
|
// |old_owner| is not the empty string and/or re-requests the set of managed
|
|
// objects when |new_owner| is not the empty string.
|
|
void NameOwnerChanged(const std::string& old_owner,
|
|
const std::string& new_owner);
|
|
|
|
Bus* bus_;
|
|
std::string service_name_;
|
|
std::string service_name_owner_;
|
|
std::string match_rule_;
|
|
ObjectPath object_path_;
|
|
ObjectProxy* object_proxy_;
|
|
bool setup_success_;
|
|
bool cleanup_called_;
|
|
|
|
// Maps the name of an interface to the implementation class used for
|
|
// instantiating PropertySet structures for that interface's properties.
|
|
typedef std::map<std::string, Interface*> InterfaceMap;
|
|
InterfaceMap interface_map_;
|
|
|
|
// Each managed object consists of a ObjectProxy used to make calls
|
|
// against that object and a collection of D-Bus interface names and their
|
|
// associated PropertySet structures.
|
|
struct Object {
|
|
Object();
|
|
~Object();
|
|
|
|
ObjectProxy* object_proxy;
|
|
|
|
// Maps the name of an interface to the specific PropertySet structure
|
|
// of that interface's properties.
|
|
typedef std::map<const std::string, PropertySet*> PropertiesMap;
|
|
PropertiesMap properties_map;
|
|
};
|
|
|
|
// Maps the object path of an object to the Object structure.
|
|
typedef std::map<const ObjectPath, Object*> ObjectMap;
|
|
ObjectMap object_map_;
|
|
|
|
// Weak pointer factory for generating 'this' pointers that might live longer
|
|
// than we do.
|
|
// Note: This should remain the last member so it'll be destroyed and
|
|
// invalidate its weak pointers before any other members are destroyed.
|
|
base::WeakPtrFactory<ObjectManager> weak_ptr_factory_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(ObjectManager);
|
|
};
|
|
|
|
} // namespace dbus
|
|
|
|
#endif // DBUS_OBJECT_MANAGER_H_
|