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