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