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 void ObjectManager::InitializeObjects() {
    171   DCHECK(bus_);
    172   DCHECK(object_proxy_);
    173   DCHECK(setup_success_);
    174 
    175   // |object_proxy_| is no longer valid if the Bus was shut down before this
    176   // call. Don't initiate any other action from the origin thread.
    177   if (cleanup_called_)
    178     return;
    179 
    180   object_proxy_->ConnectToSignal(
    181       kObjectManagerInterface,
    182       kObjectManagerInterfacesAdded,
    183       base::Bind(&ObjectManager::InterfacesAddedReceived,
    184                  weak_ptr_factory_.GetWeakPtr()),
    185       base::Bind(&ObjectManager::InterfacesAddedConnected,
    186                  weak_ptr_factory_.GetWeakPtr()));
    187 
    188   object_proxy_->ConnectToSignal(
    189       kObjectManagerInterface,
    190       kObjectManagerInterfacesRemoved,
    191       base::Bind(&ObjectManager::InterfacesRemovedReceived,
    192                  weak_ptr_factory_.GetWeakPtr()),
    193       base::Bind(&ObjectManager::InterfacesRemovedConnected,
    194                  weak_ptr_factory_.GetWeakPtr()));
    195 
    196   GetManagedObjects();
    197 }
    198 
    199 bool ObjectManager::SetupMatchRuleAndFilter() {
    200   DCHECK(bus_);
    201   DCHECK(!setup_success_);
    202   bus_->AssertOnDBusThread();
    203 
    204   if (cleanup_called_)
    205     return false;
    206 
    207   if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
    208     return false;
    209 
    210   service_name_owner_ =
    211       bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
    212 
    213   const std::string match_rule =
    214       base::StringPrintf(
    215           "type='signal', sender='%s', interface='%s', member='%s'",
    216           service_name_.c_str(),
    217           kPropertiesInterface,
    218           kPropertiesChanged);
    219 
    220   bus_->AddFilterFunction(&ObjectManager::HandleMessageThunk, this);
    221 
    222   ScopedDBusError error;
    223   bus_->AddMatch(match_rule, error.get());
    224   if (error.is_set()) {
    225     LOG(ERROR) << "ObjectManager failed to add match rule \"" << match_rule
    226                << "\". Got " << error.name() << ": " << error.message();
    227     bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this);
    228     return false;
    229   }
    230 
    231   match_rule_ = match_rule;
    232   setup_success_ = true;
    233 
    234   return true;
    235 }
    236 
    237 void ObjectManager::OnSetupMatchRuleAndFilterComplete(bool success) {
    238   LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
    239                             << ": Failed to set up match rule.";
    240   if (success)
    241     InitializeObjects();
    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   scoped_ptr<Signal> signal(
    267       Signal::FromRawMessage(raw_message));
    268 
    269   const std::string interface = signal->GetInterface();
    270   const std::string member = signal->GetMember();
    271 
    272   statistics::AddReceivedSignal(service_name_, interface, member);
    273 
    274   // Handle the signal only if it is PropertiesChanged.
    275   // Note that the match rule in SetupMatchRuleAndFilter() is configured to
    276   // only accept PropertiesChanged signals, but we check here just in case.
    277   const std::string absolute_signal_name =
    278       GetAbsoluteMemberName(interface, member);
    279   const std::string properties_changed_signal_name =
    280       GetAbsoluteMemberName(kPropertiesInterface, kPropertiesChanged);
    281   if (absolute_signal_name != properties_changed_signal_name)
    282     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    283 
    284   VLOG(1) << "Signal received: " << signal->ToString();
    285 
    286   // Handle the signal only if it is from the service that the ObjectManager
    287   // instance is interested in.
    288   // Note that the match rule in SetupMatchRuleAndFilter() is configured to
    289   // only accept messages from the service name of our interest. However, the
    290   // service='...' filter does not work as intended. See crbug.com/507206#14
    291   // and #15 for details, hence it's necessary to check the sender here.
    292   std::string sender = signal->GetSender();
    293   if (service_name_owner_ != sender)
    294     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    295 
    296   const ObjectPath path = signal->GetPath();
    297 
    298   if (bus_->HasDBusThread()) {
    299     // Post a task to run the method in the origin thread. Transfer ownership of
    300     // |signal| to NotifyPropertiesChanged, which will handle the clean up.
    301     Signal* released_signal = signal.release();
    302     bus_->GetOriginTaskRunner()->PostTask(
    303         FROM_HERE,
    304         base::Bind(&ObjectManager::NotifyPropertiesChanged,
    305                    this, path,
    306                    released_signal));
    307   } else {
    308     // If the D-Bus thread is not used, just call the callback on the
    309     // current thread. Transfer the ownership of |signal| to
    310     // NotifyPropertiesChanged.
    311     NotifyPropertiesChanged(path, signal.release());
    312   }
    313 
    314   // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
    315   // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
    316   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    317 }
    318 
    319 void ObjectManager::NotifyPropertiesChanged(
    320     const dbus::ObjectPath object_path,
    321     Signal* signal) {
    322   DCHECK(bus_);
    323   bus_->AssertOnOriginThread();
    324 
    325   NotifyPropertiesChangedHelper(object_path, signal);
    326 
    327   // Delete the message on the D-Bus thread. See comments in HandleMessage.
    328   bus_->GetDBusTaskRunner()->PostTask(
    329       FROM_HERE,
    330       base::Bind(&base::DeletePointer<Signal>, signal));
    331 }
    332 
    333 void ObjectManager::NotifyPropertiesChangedHelper(
    334     const dbus::ObjectPath object_path,
    335     Signal* signal) {
    336   DCHECK(bus_);
    337   bus_->AssertOnOriginThread();
    338 
    339   MessageReader reader(signal);
    340   std::string interface;
    341   if (!reader.PopString(&interface)) {
    342     LOG(WARNING) << "Property changed signal has wrong parameters: "
    343                  << "expected interface name: " << signal->ToString();
    344     return;
    345   }
    346 
    347   PropertySet* properties = GetProperties(object_path, interface);
    348   if (properties)
    349     properties->ChangedReceived(signal);
    350 }
    351 
    352 void ObjectManager::OnGetManagedObjects(Response* response) {
    353   if (response != NULL) {
    354     MessageReader reader(response);
    355     MessageReader array_reader(NULL);
    356     if (!reader.PopArray(&array_reader))
    357       return;
    358 
    359     while (array_reader.HasMoreData()) {
    360       MessageReader dict_entry_reader(NULL);
    361       ObjectPath object_path;
    362       if (!array_reader.PopDictEntry(&dict_entry_reader) ||
    363           !dict_entry_reader.PopObjectPath(&object_path))
    364         continue;
    365 
    366       UpdateObject(object_path, &dict_entry_reader);
    367     }
    368 
    369   } else {
    370     LOG(WARNING) << service_name_ << " " << object_path_.value()
    371                  << ": Failed to get managed objects";
    372   }
    373 }
    374 
    375 void ObjectManager::InterfacesAddedReceived(Signal* signal) {
    376   DCHECK(signal);
    377   MessageReader reader(signal);
    378   ObjectPath object_path;
    379   if (!reader.PopObjectPath(&object_path)) {
    380     LOG(WARNING) << service_name_ << " " << object_path_.value()
    381                  << ": InterfacesAdded signal has incorrect parameters: "
    382                  << signal->ToString();
    383     return;
    384   }
    385 
    386   UpdateObject(object_path, &reader);
    387 }
    388 
    389 void ObjectManager::InterfacesAddedConnected(
    390     const std::string& /* interface_name */,
    391     const std::string& /* signal_name */,
    392     bool success) {
    393   LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
    394                             << ": Failed to connect to InterfacesAdded signal.";
    395 }
    396 
    397 void ObjectManager::InterfacesRemovedReceived(Signal* signal) {
    398   DCHECK(signal);
    399   MessageReader reader(signal);
    400   ObjectPath object_path;
    401   std::vector<std::string> interface_names;
    402   if (!reader.PopObjectPath(&object_path) ||
    403       !reader.PopArrayOfStrings(&interface_names)) {
    404     LOG(WARNING) << service_name_ << " " << object_path_.value()
    405                  << ": InterfacesRemoved signal has incorrect parameters: "
    406                  << signal->ToString();
    407     return;
    408   }
    409 
    410   for (size_t i = 0; i < interface_names.size(); ++i)
    411     RemoveInterface(object_path, interface_names[i]);
    412 }
    413 
    414 void ObjectManager::InterfacesRemovedConnected(
    415     const std::string& /* interface_name */,
    416     const std::string& /* signal_name */,
    417     bool success) {
    418   LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
    419                             << ": Failed to connect to "
    420                             << "InterfacesRemoved signal.";
    421 }
    422 
    423 void ObjectManager::UpdateObject(const ObjectPath& object_path,
    424                                  MessageReader* reader) {
    425   DCHECK(reader);
    426   MessageReader array_reader(NULL);
    427   if (!reader->PopArray(&array_reader))
    428     return;
    429 
    430   while (array_reader.HasMoreData()) {
    431     MessageReader dict_entry_reader(NULL);
    432     std::string interface_name;
    433     if (!array_reader.PopDictEntry(&dict_entry_reader) ||
    434         !dict_entry_reader.PopString(&interface_name))
    435       continue;
    436 
    437     AddInterface(object_path, interface_name, &dict_entry_reader);
    438   }
    439 }
    440 
    441 
    442 void ObjectManager::AddInterface(const ObjectPath& object_path,
    443                                  const std::string& interface_name,
    444                                  MessageReader* reader) {
    445   InterfaceMap::iterator iiter = interface_map_.find(interface_name);
    446   if (iiter == interface_map_.end())
    447     return;
    448   Interface* interface = iiter->second;
    449 
    450   ObjectMap::iterator oiter = object_map_.find(object_path);
    451   Object* object;
    452   if (oiter == object_map_.end()) {
    453     object = object_map_[object_path] = new Object;
    454     object->object_proxy = bus_->GetObjectProxy(service_name_, object_path);
    455   } else
    456     object = oiter->second;
    457 
    458   Object::PropertiesMap::iterator piter =
    459       object->properties_map.find(interface_name);
    460   PropertySet* property_set;
    461   const bool interface_added = (piter == object->properties_map.end());
    462   if (interface_added) {
    463     property_set = object->properties_map[interface_name] =
    464         interface->CreateProperties(object->object_proxy,
    465                                     object_path, interface_name);
    466   } else
    467     property_set = piter->second;
    468 
    469   property_set->UpdatePropertiesFromReader(reader);
    470 
    471   if (interface_added)
    472     interface->ObjectAdded(object_path, interface_name);
    473 }
    474 
    475 void ObjectManager::RemoveInterface(const ObjectPath& object_path,
    476                                     const std::string& interface_name) {
    477   ObjectMap::iterator oiter = object_map_.find(object_path);
    478   if (oiter == object_map_.end())
    479     return;
    480   Object* object = oiter->second;
    481 
    482   Object::PropertiesMap::iterator piter =
    483       object->properties_map.find(interface_name);
    484   if (piter == object->properties_map.end())
    485     return;
    486 
    487   // Inform the interface before removing the properties structure or object
    488   // in case it needs details from them to make its own decisions.
    489   InterfaceMap::iterator iiter = interface_map_.find(interface_name);
    490   if (iiter != interface_map_.end()) {
    491     Interface* interface = iiter->second;
    492     interface->ObjectRemoved(object_path, interface_name);
    493   }
    494 
    495   delete piter->second;
    496   object->properties_map.erase(piter);
    497 
    498   if (object->properties_map.empty()) {
    499     object_map_.erase(oiter);
    500     delete object;
    501   }
    502 }
    503 
    504 void ObjectManager::NameOwnerChanged(const std::string& old_owner,
    505                                      const std::string& new_owner) {
    506   service_name_owner_ = new_owner;
    507 
    508   if (!old_owner.empty()) {
    509     ObjectMap::iterator iter = object_map_.begin();
    510     while (iter != object_map_.end()) {
    511       ObjectMap::iterator tmp = iter;
    512       ++iter;
    513 
    514       // PropertiesMap is mutated by RemoveInterface, and also Object is
    515       // destroyed; easier to collect the object path and interface names
    516       // and remove them safely.
    517       const dbus::ObjectPath object_path = tmp->first;
    518       Object* object = tmp->second;
    519       std::vector<std::string> interfaces;
    520 
    521       for (Object::PropertiesMap::iterator piter =
    522               object->properties_map.begin();
    523            piter != object->properties_map.end(); ++piter)
    524         interfaces.push_back(piter->first);
    525 
    526       for (std::vector<std::string>::iterator iiter = interfaces.begin();
    527            iiter != interfaces.end(); ++iiter)
    528         RemoveInterface(object_path, *iiter);
    529     }
    530 
    531   }
    532 
    533   if (!new_owner.empty())
    534     GetManagedObjects();
    535 }
    536 
    537 }  // namespace dbus
    538