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 #include "dbus/object_manager.h"
      6 
      7 #include <stddef.h>
      8 
      9 #include "base/bind.h"
     10 #include "base/location.h"
     11 #include "base/logging.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "base/task_runner_util.h"
     15 #include "dbus/bus.h"
     16 #include "dbus/dbus_statistics.h"
     17 #include "dbus/message.h"
     18 #include "dbus/object_proxy.h"
     19 #include "dbus/property.h"
     20 #include "dbus/scoped_dbus_error.h"
     21 #include "dbus/util.h"
     22 
     23 namespace dbus {
     24 
     25 ObjectManager::Object::Object()
     26   : object_proxy(NULL) {
     27 }
     28 
     29 ObjectManager::Object::~Object() {
     30 }
     31 
     32 ObjectManager::ObjectManager(Bus* bus,
     33                              const std::string& service_name,
     34                              const ObjectPath& object_path)
     35     : bus_(bus),
     36       service_name_(service_name),
     37       object_path_(object_path),
     38       setup_success_(false),
     39       cleanup_called_(false),
     40       weak_ptr_factory_(this) {
     41   DVLOG(1) << "Creating ObjectManager for " << service_name_
     42            << " " << object_path_.value();
     43   DCHECK(bus_);
     44   bus_->AssertOnOriginThread();
     45   object_proxy_ = bus_->GetObjectProxy(service_name_, object_path_);
     46   object_proxy_->SetNameOwnerChangedCallback(
     47       base::Bind(&ObjectManager::NameOwnerChanged,
     48                  weak_ptr_factory_.GetWeakPtr()));
     49 
     50   // Set up a match rule and a filter function to handle PropertiesChanged
     51   // signals from the service. This is important to avoid any race conditions
     52   // that might cause us to miss PropertiesChanged signals once all objects are
     53   // initialized via GetManagedObjects.
     54   base::PostTaskAndReplyWithResult(
     55       bus_->GetDBusTaskRunner(),
     56       FROM_HERE,
     57       base::Bind(&ObjectManager::SetupMatchRuleAndFilter, this),
     58       base::Bind(&ObjectManager::OnSetupMatchRuleAndFilterComplete, this));
     59 }
     60 
     61 ObjectManager::~ObjectManager() {
     62   // Clean up Object structures
     63   for (ObjectMap::iterator iter = object_map_.begin();
     64        iter != object_map_.end(); ++iter) {
     65     Object* object = iter->second;
     66 
     67     for (Object::PropertiesMap::iterator piter = object->properties_map.begin();
     68          piter != object->properties_map.end(); ++piter) {
     69       PropertySet* properties = piter->second;
     70       delete properties;
     71     }
     72 
     73     delete object;
     74   }
     75 }
     76 
     77 void ObjectManager::RegisterInterface(const std::string& interface_name,
     78                                       Interface* interface) {
     79   interface_map_[interface_name] = interface;
     80 }
     81 
     82 void ObjectManager::UnregisterInterface(const std::string& interface_name) {
     83   InterfaceMap::iterator iter = interface_map_.find(interface_name);
     84   if (iter != interface_map_.end())
     85     interface_map_.erase(iter);
     86 }
     87 
     88 std::vector<ObjectPath> ObjectManager::GetObjects() {
     89   std::vector<ObjectPath> object_paths;
     90 
     91   for (ObjectMap::iterator iter = object_map_.begin();
     92        iter != object_map_.end(); ++iter)
     93     object_paths.push_back(iter->first);
     94 
     95   return object_paths;
     96 }
     97 
     98 std::vector<ObjectPath> ObjectManager::GetObjectsWithInterface(
     99       const std::string& interface_name) {
    100   std::vector<ObjectPath> object_paths;
    101 
    102   for (ObjectMap::iterator oiter = object_map_.begin();
    103        oiter != object_map_.end(); ++oiter) {
    104     Object* object = oiter->second;
    105 
    106     Object::PropertiesMap::iterator piter =
    107         object->properties_map.find(interface_name);
    108     if (piter != object->properties_map.end())
    109       object_paths.push_back(oiter->first);
    110   }
    111 
    112   return object_paths;
    113 }
    114 
    115 ObjectProxy* ObjectManager::GetObjectProxy(const ObjectPath& object_path) {
    116   ObjectMap::iterator iter = object_map_.find(object_path);
    117   if (iter == object_map_.end())
    118     return NULL;
    119 
    120   Object* object = iter->second;
    121   return object->object_proxy;
    122 }
    123 
    124 PropertySet* ObjectManager::GetProperties(const ObjectPath& object_path,
    125                                           const std::string& interface_name) {
    126   ObjectMap::iterator iter = object_map_.find(object_path);
    127   if (iter == object_map_.end())
    128     return NULL;
    129 
    130   Object* object = iter->second;
    131   Object::PropertiesMap::iterator piter =
    132       object->properties_map.find(interface_name);
    133   if (piter == object->properties_map.end())
    134     return NULL;
    135 
    136   return piter->second;
    137 }
    138 
    139 void ObjectManager::GetManagedObjects() {
    140   MethodCall method_call(kObjectManagerInterface,
    141                          kObjectManagerGetManagedObjects);
    142 
    143   object_proxy_->CallMethod(
    144       &method_call,
    145       ObjectProxy::TIMEOUT_USE_DEFAULT,
    146       base::Bind(&ObjectManager::OnGetManagedObjects,
    147                  weak_ptr_factory_.GetWeakPtr()));
    148 }
    149 
    150 void ObjectManager::CleanUp() {
    151   DCHECK(bus_);
    152   bus_->AssertOnDBusThread();
    153   DCHECK(!cleanup_called_);
    154 
    155   cleanup_called_ = true;
    156 
    157   if (!setup_success_)
    158     return;
    159 
    160   bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this);
    161 
    162   ScopedDBusError error;
    163   bus_->RemoveMatch(match_rule_, error.get());
    164   if (error.is_set())
    165     LOG(ERROR) << "Failed to remove match rule: " << match_rule_;
    166 
    167   match_rule_.clear();
    168 }
    169 
    170 bool ObjectManager::SetupMatchRuleAndFilter() {
    171   DCHECK(bus_);
    172   DCHECK(!setup_success_);
    173   bus_->AssertOnDBusThread();
    174 
    175   if (cleanup_called_)
    176     return false;
    177 
    178   if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
    179     return false;
    180 
    181   service_name_owner_ =
    182       bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
    183 
    184   const std::string match_rule =
    185       base::StringPrintf(
    186           "type='signal', sender='%s', interface='%s', member='%s'",
    187           service_name_.c_str(),
    188           kPropertiesInterface,
    189           kPropertiesChanged);
    190 
    191   bus_->AddFilterFunction(&ObjectManager::HandleMessageThunk, this);
    192 
    193   ScopedDBusError error;
    194   bus_->AddMatch(match_rule, error.get());
    195   if (error.is_set()) {
    196     LOG(ERROR) << "ObjectManager failed to add match rule \"" << match_rule
    197                << "\". Got " << error.name() << ": " << error.message();
    198     bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this);
    199     return false;
    200   }
    201 
    202   match_rule_ = match_rule;
    203   setup_success_ = true;
    204 
    205   return true;
    206 }
    207 
    208 void ObjectManager::OnSetupMatchRuleAndFilterComplete(bool success) {
    209   if (!success) {
    210     LOG(WARNING) << service_name_ << " " << object_path_.value()
    211                  << ": Failed to set up match rule.";
    212     return;
    213   }
    214 
    215   DCHECK(bus_);
    216   DCHECK(object_proxy_);
    217   DCHECK(setup_success_);
    218 
    219   // |object_proxy_| is no longer valid if the Bus was shut down before this
    220   // call. Don't initiate any other action from the origin thread.
    221   if (cleanup_called_)
    222     return;
    223 
    224   object_proxy_->ConnectToSignal(
    225       kObjectManagerInterface,
    226       kObjectManagerInterfacesAdded,
    227       base::Bind(&ObjectManager::InterfacesAddedReceived,
    228                  weak_ptr_factory_.GetWeakPtr()),
    229       base::Bind(&ObjectManager::InterfacesAddedConnected,
    230                  weak_ptr_factory_.GetWeakPtr()));
    231 
    232   object_proxy_->ConnectToSignal(
    233       kObjectManagerInterface,
    234       kObjectManagerInterfacesRemoved,
    235       base::Bind(&ObjectManager::InterfacesRemovedReceived,
    236                  weak_ptr_factory_.GetWeakPtr()),
    237       base::Bind(&ObjectManager::InterfacesRemovedConnected,
    238                  weak_ptr_factory_.GetWeakPtr()));
    239 
    240   if (!service_name_owner_.empty())
    241     GetManagedObjects();
    242 }
    243 
    244 // static
    245 DBusHandlerResult ObjectManager::HandleMessageThunk(DBusConnection* connection,
    246                                                     DBusMessage* raw_message,
    247                                                     void* user_data) {
    248   ObjectManager* self = reinterpret_cast<ObjectManager*>(user_data);
    249   return self->HandleMessage(connection, raw_message);
    250 }
    251 
    252 DBusHandlerResult ObjectManager::HandleMessage(DBusConnection* connection,
    253                                                DBusMessage* raw_message) {
    254   DCHECK(bus_);
    255   bus_->AssertOnDBusThread();
    256 
    257   // Handle the message only if it is a signal.
    258   // Note that the match rule in SetupMatchRuleAndFilter() is configured to
    259   // only accept signals, but we check here just in case.
    260   if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
    261     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    262 
    263   // raw_message will be unrefed on exit of the function. Increment the
    264   // reference so we can use it in Signal.
    265   dbus_message_ref(raw_message);
    266   std::unique_ptr<Signal> signal(Signal::FromRawMessage(raw_message));
    267 
    268   const std::string interface = signal->GetInterface();
    269   const std::string member = signal->GetMember();
    270 
    271   statistics::AddReceivedSignal(service_name_, interface, member);
    272 
    273   // Handle the signal only if it is PropertiesChanged.
    274   // Note that the match rule in SetupMatchRuleAndFilter() is configured to
    275   // only accept PropertiesChanged signals, but we check here just in case.
    276   const std::string absolute_signal_name =
    277       GetAbsoluteMemberName(interface, member);
    278   const std::string properties_changed_signal_name =
    279       GetAbsoluteMemberName(kPropertiesInterface, kPropertiesChanged);
    280   if (absolute_signal_name != properties_changed_signal_name)
    281     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    282 
    283   VLOG(1) << "Signal received: " << signal->ToString();
    284 
    285   // Handle the signal only if it is from the service that the ObjectManager
    286   // instance is interested in.
    287   // Note that the match rule in SetupMatchRuleAndFilter() is configured to
    288   // only accept messages from the service name of our interest. However, the
    289   // service='...' filter does not work as intended. See crbug.com/507206#14
    290   // and #15 for details, hence it's necessary to check the sender here.
    291   std::string sender = signal->GetSender();
    292   if (service_name_owner_ != sender)
    293     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    294 
    295   const ObjectPath path = signal->GetPath();
    296 
    297   if (bus_->HasDBusThread()) {
    298     // Post a task to run the method in the origin thread. Transfer ownership of
    299     // |signal| to NotifyPropertiesChanged, which will handle the clean up.
    300     Signal* released_signal = signal.release();
    301     bus_->GetOriginTaskRunner()->PostTask(
    302         FROM_HERE,
    303         base::Bind(&ObjectManager::NotifyPropertiesChanged,
    304                    this, path,
    305                    released_signal));
    306   } else {
    307     // If the D-Bus thread is not used, just call the callback on the
    308     // current thread. Transfer the ownership of |signal| to
    309     // NotifyPropertiesChanged.
    310     NotifyPropertiesChanged(path, signal.release());
    311   }
    312 
    313   // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
    314   // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
    315   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    316 }
    317 
    318 void ObjectManager::NotifyPropertiesChanged(
    319     const dbus::ObjectPath object_path,
    320     Signal* signal) {
    321   DCHECK(bus_);
    322   bus_->AssertOnOriginThread();
    323 
    324   NotifyPropertiesChangedHelper(object_path, signal);
    325 
    326   // Delete the message on the D-Bus thread. See comments in HandleMessage.
    327   bus_->GetDBusTaskRunner()->PostTask(
    328       FROM_HERE,
    329       base::Bind(&base::DeletePointer<Signal>, signal));
    330 }
    331 
    332 void ObjectManager::NotifyPropertiesChangedHelper(
    333     const dbus::ObjectPath object_path,
    334     Signal* signal) {
    335   DCHECK(bus_);
    336   bus_->AssertOnOriginThread();
    337 
    338   MessageReader reader(signal);
    339   std::string interface;
    340   if (!reader.PopString(&interface)) {
    341     LOG(WARNING) << "Property changed signal has wrong parameters: "
    342                  << "expected interface name: " << signal->ToString();
    343     return;
    344   }
    345 
    346   PropertySet* properties = GetProperties(object_path, interface);
    347   if (properties)
    348     properties->ChangedReceived(signal);
    349 }
    350 
    351 void ObjectManager::OnGetManagedObjects(Response* response) {
    352   if (response != NULL) {
    353     MessageReader reader(response);
    354     MessageReader array_reader(NULL);
    355     if (!reader.PopArray(&array_reader))
    356       return;
    357 
    358     while (array_reader.HasMoreData()) {
    359       MessageReader dict_entry_reader(NULL);
    360       ObjectPath object_path;
    361       if (!array_reader.PopDictEntry(&dict_entry_reader) ||
    362           !dict_entry_reader.PopObjectPath(&object_path))
    363         continue;
    364 
    365       UpdateObject(object_path, &dict_entry_reader);
    366     }
    367 
    368   } else {
    369     LOG(WARNING) << service_name_ << " " << object_path_.value()
    370                  << ": Failed to get managed objects";
    371   }
    372 }
    373 
    374 void ObjectManager::InterfacesAddedReceived(Signal* signal) {
    375   DCHECK(signal);
    376   MessageReader reader(signal);
    377   ObjectPath object_path;
    378   if (!reader.PopObjectPath(&object_path)) {
    379     LOG(WARNING) << service_name_ << " " << object_path_.value()
    380                  << ": InterfacesAdded signal has incorrect parameters: "
    381                  << signal->ToString();
    382     return;
    383   }
    384 
    385   UpdateObject(object_path, &reader);
    386 }
    387 
    388 void ObjectManager::InterfacesAddedConnected(const std::string& interface_name,
    389                                              const std::string& signal_name,
    390                                              bool success) {
    391   LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
    392                             << ": Failed to connect to InterfacesAdded signal.";
    393 }
    394 
    395 void ObjectManager::InterfacesRemovedReceived(Signal* signal) {
    396   DCHECK(signal);
    397   MessageReader reader(signal);
    398   ObjectPath object_path;
    399   std::vector<std::string> interface_names;
    400   if (!reader.PopObjectPath(&object_path) ||
    401       !reader.PopArrayOfStrings(&interface_names)) {
    402     LOG(WARNING) << service_name_ << " " << object_path_.value()
    403                  << ": InterfacesRemoved signal has incorrect parameters: "
    404                  << signal->ToString();
    405     return;
    406   }
    407 
    408   for (size_t i = 0; i < interface_names.size(); ++i)
    409     RemoveInterface(object_path, interface_names[i]);
    410 }
    411 
    412 void ObjectManager::InterfacesRemovedConnected(
    413     const std::string& interface_name,
    414     const std::string& signal_name,
    415     bool success) {
    416   LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
    417                             << ": Failed to connect to "
    418                             << "InterfacesRemoved signal.";
    419 }
    420 
    421 void ObjectManager::UpdateObject(const ObjectPath& object_path,
    422                                  MessageReader* reader) {
    423   DCHECK(reader);
    424   MessageReader array_reader(NULL);
    425   if (!reader->PopArray(&array_reader))
    426     return;
    427 
    428   while (array_reader.HasMoreData()) {
    429     MessageReader dict_entry_reader(NULL);
    430     std::string interface_name;
    431     if (!array_reader.PopDictEntry(&dict_entry_reader) ||
    432         !dict_entry_reader.PopString(&interface_name))
    433       continue;
    434 
    435     AddInterface(object_path, interface_name, &dict_entry_reader);
    436   }
    437 }
    438 
    439 
    440 void ObjectManager::AddInterface(const ObjectPath& object_path,
    441                                  const std::string& interface_name,
    442                                  MessageReader* reader) {
    443   InterfaceMap::iterator iiter = interface_map_.find(interface_name);
    444   if (iiter == interface_map_.end())
    445     return;
    446   Interface* interface = iiter->second;
    447 
    448   ObjectMap::iterator oiter = object_map_.find(object_path);
    449   Object* object;
    450   if (oiter == object_map_.end()) {
    451     object = object_map_[object_path] = new Object;
    452     object->object_proxy = bus_->GetObjectProxy(service_name_, object_path);
    453   } else
    454     object = oiter->second;
    455 
    456   Object::PropertiesMap::iterator piter =
    457       object->properties_map.find(interface_name);
    458   PropertySet* property_set;
    459   const bool interface_added = (piter == object->properties_map.end());
    460   if (interface_added) {
    461     property_set = object->properties_map[interface_name] =
    462         interface->CreateProperties(object->object_proxy,
    463                                     object_path, interface_name);
    464   } else
    465     property_set = piter->second;
    466 
    467   property_set->UpdatePropertiesFromReader(reader);
    468 
    469   if (interface_added)
    470     interface->ObjectAdded(object_path, interface_name);
    471 }
    472 
    473 void ObjectManager::RemoveInterface(const ObjectPath& object_path,
    474                                     const std::string& interface_name) {
    475   ObjectMap::iterator oiter = object_map_.find(object_path);
    476   if (oiter == object_map_.end())
    477     return;
    478   Object* object = oiter->second;
    479 
    480   Object::PropertiesMap::iterator piter =
    481       object->properties_map.find(interface_name);
    482   if (piter == object->properties_map.end())
    483     return;
    484 
    485   // Inform the interface before removing the properties structure or object
    486   // in case it needs details from them to make its own decisions.
    487   InterfaceMap::iterator iiter = interface_map_.find(interface_name);
    488   if (iiter != interface_map_.end()) {
    489     Interface* interface = iiter->second;
    490     interface->ObjectRemoved(object_path, interface_name);
    491   }
    492 
    493   delete piter->second;
    494   object->properties_map.erase(piter);
    495 
    496   if (object->properties_map.empty()) {
    497     object_map_.erase(oiter);
    498     delete object;
    499   }
    500 }
    501 
    502 void ObjectManager::NameOwnerChanged(const std::string& old_owner,
    503                                      const std::string& new_owner) {
    504   service_name_owner_ = new_owner;
    505 
    506   if (!old_owner.empty()) {
    507     ObjectMap::iterator iter = object_map_.begin();
    508     while (iter != object_map_.end()) {
    509       ObjectMap::iterator tmp = iter;
    510       ++iter;
    511 
    512       // PropertiesMap is mutated by RemoveInterface, and also Object is
    513       // destroyed; easier to collect the object path and interface names
    514       // and remove them safely.
    515       const dbus::ObjectPath object_path = tmp->first;
    516       Object* object = tmp->second;
    517       std::vector<std::string> interfaces;
    518 
    519       for (Object::PropertiesMap::iterator piter =
    520               object->properties_map.begin();
    521            piter != object->properties_map.end(); ++piter)
    522         interfaces.push_back(piter->first);
    523 
    524       for (std::vector<std::string>::iterator iiter = interfaces.begin();
    525            iiter != interfaces.end(); ++iiter)
    526         RemoveInterface(object_path, *iiter);
    527     }
    528 
    529   }
    530 
    531   if (!new_owner.empty())
    532     GetManagedObjects();
    533 }
    534 
    535 }  // namespace dbus
    536