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