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