OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "dbus/object_manager.h" | 5 #include "dbus/object_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/location.h" |
8 #include "base/logging.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" |
9 #include "dbus/bus.h" | 13 #include "dbus/bus.h" |
| 14 #include "dbus/dbus_statistics.h" |
10 #include "dbus/message.h" | 15 #include "dbus/message.h" |
11 #include "dbus/object_proxy.h" | 16 #include "dbus/object_proxy.h" |
12 #include "dbus/property.h" | 17 #include "dbus/property.h" |
| 18 #include "dbus/scoped_dbus_error.h" |
13 | 19 |
14 namespace dbus { | 20 namespace dbus { |
15 | 21 |
| 22 namespace { |
| 23 |
| 24 // TODO(armansito): Move this to a utils file so that it can be reused among |
| 25 // ObjectManager and ObjectProxy. |
| 26 // Gets the absolute signal name by concatenating the interface name and |
| 27 // the signal name. |
| 28 std::string GetAbsoluteSignalName( |
| 29 const std::string& interface_name, |
| 30 const std::string& signal_name) { |
| 31 return interface_name + "." + signal_name; |
| 32 } |
| 33 |
| 34 } // namespace |
| 35 |
16 ObjectManager::Object::Object() | 36 ObjectManager::Object::Object() |
17 : object_proxy(NULL) { | 37 : object_proxy(NULL) { |
18 } | 38 } |
19 | 39 |
20 ObjectManager::Object::~Object() { | 40 ObjectManager::Object::~Object() { |
21 } | 41 } |
22 | 42 |
23 ObjectManager::ObjectManager(Bus* bus, | 43 ObjectManager::ObjectManager(Bus* bus, |
24 const std::string& service_name, | 44 const std::string& service_name, |
25 const ObjectPath& object_path) | 45 const ObjectPath& object_path) |
26 : bus_(bus), | 46 : bus_(bus), |
27 service_name_(service_name), | 47 service_name_(service_name), |
28 object_path_(object_path), | 48 object_path_(object_path), |
| 49 setup_success_(false), |
29 weak_ptr_factory_(this) { | 50 weak_ptr_factory_(this) { |
30 DVLOG(1) << "Creating ObjectManager for " << service_name_ | 51 DVLOG(1) << "Creating ObjectManager for " << service_name_ |
31 << " " << object_path_.value(); | 52 << " " << object_path_.value(); |
32 | |
33 DCHECK(bus_); | 53 DCHECK(bus_); |
| 54 bus_->AssertOnOriginThread(); |
34 object_proxy_ = bus_->GetObjectProxy(service_name_, object_path_); | 55 object_proxy_ = bus_->GetObjectProxy(service_name_, object_path_); |
35 object_proxy_->SetNameOwnerChangedCallback( | 56 object_proxy_->SetNameOwnerChangedCallback( |
36 base::Bind(&ObjectManager::NameOwnerChanged, | 57 base::Bind(&ObjectManager::NameOwnerChanged, |
37 weak_ptr_factory_.GetWeakPtr())); | 58 weak_ptr_factory_.GetWeakPtr())); |
38 | 59 |
39 object_proxy_->ConnectToSignal( | 60 // Set up a match rule and a filter function to handle PropertiesChanged |
40 kObjectManagerInterface, | 61 // signals from the service. This is important to avoid any race conditions |
41 kObjectManagerInterfacesAdded, | 62 // that might cause us to miss PropertiesChanged signals once all objects are |
42 base::Bind(&ObjectManager::InterfacesAddedReceived, | 63 // initialized via GetManagedObjects. |
43 weak_ptr_factory_.GetWeakPtr()), | 64 base::PostTaskAndReplyWithResult( |
44 base::Bind(&ObjectManager::InterfacesAddedConnected, | 65 bus_->GetDBusTaskRunner(), |
45 weak_ptr_factory_.GetWeakPtr())); | 66 FROM_HERE, |
46 | 67 base::Bind(&ObjectManager::SetupMatchRuleAndFilter, this), |
47 object_proxy_->ConnectToSignal( | 68 base::Bind(&ObjectManager::OnSetupMatchRuleAndFilterComplete, this)); |
48 kObjectManagerInterface, | |
49 kObjectManagerInterfacesRemoved, | |
50 base::Bind(&ObjectManager::InterfacesRemovedReceived, | |
51 weak_ptr_factory_.GetWeakPtr()), | |
52 base::Bind(&ObjectManager::InterfacesRemovedConnected, | |
53 weak_ptr_factory_.GetWeakPtr())); | |
54 | |
55 GetManagedObjects(); | |
56 } | 69 } |
57 | 70 |
58 ObjectManager::~ObjectManager() { | 71 ObjectManager::~ObjectManager() { |
59 // Clean up Object structures | 72 // Clean up Object structures |
60 for (ObjectMap::iterator iter = object_map_.begin(); | 73 for (ObjectMap::iterator iter = object_map_.begin(); |
61 iter != object_map_.end(); ++iter) { | 74 iter != object_map_.end(); ++iter) { |
62 Object* object = iter->second; | 75 Object* object = iter->second; |
63 | 76 |
64 for (Object::PropertiesMap::iterator piter = object->properties_map.begin(); | 77 for (Object::PropertiesMap::iterator piter = object->properties_map.begin(); |
65 piter != object->properties_map.end(); ++piter) { | 78 piter != object->properties_map.end(); ++piter) { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 MethodCall method_call(kObjectManagerInterface, | 150 MethodCall method_call(kObjectManagerInterface, |
138 kObjectManagerGetManagedObjects); | 151 kObjectManagerGetManagedObjects); |
139 | 152 |
140 object_proxy_->CallMethod( | 153 object_proxy_->CallMethod( |
141 &method_call, | 154 &method_call, |
142 ObjectProxy::TIMEOUT_USE_DEFAULT, | 155 ObjectProxy::TIMEOUT_USE_DEFAULT, |
143 base::Bind(&ObjectManager::OnGetManagedObjects, | 156 base::Bind(&ObjectManager::OnGetManagedObjects, |
144 weak_ptr_factory_.GetWeakPtr())); | 157 weak_ptr_factory_.GetWeakPtr())); |
145 } | 158 } |
146 | 159 |
| 160 void ObjectManager::CleanUp() { |
| 161 DCHECK(bus_); |
| 162 bus_->AssertOnDBusThread(); |
| 163 |
| 164 if (!setup_success_) |
| 165 return; |
| 166 |
| 167 if (!bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this)) |
| 168 LOG(ERROR) << "Failed to remove filter function"; |
| 169 |
| 170 ScopedDBusError error; |
| 171 bus_->RemoveMatch(match_rule_, error.get()); |
| 172 if (error.is_set()) |
| 173 LOG(ERROR) << "Failed to remove match rule: " << match_rule_; |
| 174 |
| 175 match_rule_.clear(); |
| 176 } |
| 177 |
| 178 void ObjectManager::InitializeObjects() { |
| 179 DCHECK(bus_); |
| 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 (!bus_->Connect() || !bus_->SetUpAsyncOperations()) |
| 205 return false; |
| 206 |
| 207 service_name_owner_ = |
| 208 bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS); |
| 209 |
| 210 const std::string match_rule = |
| 211 base::StringPrintf( |
| 212 "type='signal', sender='%s', interface='%s', member='%s'", |
| 213 service_name_.c_str(), |
| 214 kPropertiesInterface, |
| 215 kPropertiesChanged); |
| 216 |
| 217 if (!bus_->AddFilterFunction(&ObjectManager::HandleMessageThunk, this)) { |
| 218 LOG(ERROR) << "ObjectManager failed to add filter function"; |
| 219 return false; |
| 220 } |
| 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 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL) |
| 258 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| 259 |
| 260 // raw_message will be unrefed on exit of the function. Increment the |
| 261 // reference so we can use it in Signal. |
| 262 dbus_message_ref(raw_message); |
| 263 scoped_ptr<Signal> signal( |
| 264 Signal::FromRawMessage(raw_message)); |
| 265 |
| 266 const std::string interface = signal->GetInterface(); |
| 267 const std::string member = signal->GetMember(); |
| 268 |
| 269 statistics::AddReceivedSignal(service_name_, interface, member); |
| 270 |
| 271 // Only handle the PropertiesChanged signal. |
| 272 const std::string absolute_signal_name = |
| 273 GetAbsoluteSignalName(interface, member); |
| 274 const std::string properties_changed_signal_name = |
| 275 GetAbsoluteSignalName(kPropertiesInterface, kPropertiesChanged); |
| 276 if (absolute_signal_name != properties_changed_signal_name) |
| 277 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| 278 |
| 279 VLOG(1) << "Signal received: " << signal->ToString(); |
| 280 |
| 281 // Make sure that the signal originated from the correct sender. |
| 282 std::string sender = signal->GetSender(); |
| 283 if (service_name_owner_ != sender) { |
| 284 LOG(ERROR) << "Rejecting a message from a wrong sender."; |
| 285 UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1); |
| 286 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| 287 } |
| 288 |
| 289 const ObjectPath path = signal->GetPath(); |
| 290 |
| 291 if (bus_->HasDBusThread()) { |
| 292 // Post a task to run the method in the origin thread. Transfer ownership of |
| 293 // |signal| to NotifyPropertiesChanged, which will handle the clean up. |
| 294 Signal* released_signal = signal.release(); |
| 295 bus_->GetOriginTaskRunner()->PostTask( |
| 296 FROM_HERE, |
| 297 base::Bind(&ObjectManager::NotifyPropertiesChanged, |
| 298 this, path, |
| 299 released_signal)); |
| 300 } else { |
| 301 // If the D-Bus thread is not used, just call the callback on the |
| 302 // current thread. Transfer the ownership of |signal| to |
| 303 // NotifyPropertiesChanged. |
| 304 NotifyPropertiesChanged(path, signal.release()); |
| 305 } |
| 306 |
| 307 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other |
| 308 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus) |
| 309 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| 310 } |
| 311 |
| 312 void ObjectManager::NotifyPropertiesChanged( |
| 313 const dbus::ObjectPath object_path, |
| 314 Signal* signal) { |
| 315 DCHECK(bus_); |
| 316 bus_->AssertOnOriginThread(); |
| 317 |
| 318 NotifyPropertiesChangedHelper(object_path, signal); |
| 319 |
| 320 // Delete the message on the D-Bus thread. See comments in HandleMessage. |
| 321 bus_->GetDBusTaskRunner()->PostTask( |
| 322 FROM_HERE, |
| 323 base::Bind(&base::DeletePointer<Signal>, signal)); |
| 324 } |
| 325 |
| 326 void ObjectManager::NotifyPropertiesChangedHelper( |
| 327 const dbus::ObjectPath object_path, |
| 328 Signal* signal) { |
| 329 MessageReader reader(signal); |
| 330 std::string interface; |
| 331 if (!reader.PopString(&interface)) { |
| 332 LOG(WARNING) << "Property changed signal has wrong parameters: " |
| 333 << "expected interface name: " << signal->ToString(); |
| 334 return; |
| 335 } |
| 336 |
| 337 PropertySet* properties = GetProperties(object_path, interface); |
| 338 if (properties) |
| 339 properties->ChangedReceived(signal); |
| 340 } |
| 341 |
147 void ObjectManager::OnGetManagedObjects(Response* response) { | 342 void ObjectManager::OnGetManagedObjects(Response* response) { |
148 if (response != NULL) { | 343 if (response != NULL) { |
149 MessageReader reader(response); | 344 MessageReader reader(response); |
150 MessageReader array_reader(NULL); | 345 MessageReader array_reader(NULL); |
151 if (!reader.PopArray(&array_reader)) | 346 if (!reader.PopArray(&array_reader)) |
152 return; | 347 return; |
153 | 348 |
154 while (array_reader.HasMoreData()) { | 349 while (array_reader.HasMoreData()) { |
155 MessageReader dict_entry_reader(NULL); | 350 MessageReader dict_entry_reader(NULL); |
156 ObjectPath object_path; | 351 ObjectPath object_path; |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 object = oiter->second; | 445 object = oiter->second; |
251 | 446 |
252 Object::PropertiesMap::iterator piter = | 447 Object::PropertiesMap::iterator piter = |
253 object->properties_map.find(interface_name); | 448 object->properties_map.find(interface_name); |
254 PropertySet* property_set; | 449 PropertySet* property_set; |
255 const bool interface_added = (piter == object->properties_map.end()); | 450 const bool interface_added = (piter == object->properties_map.end()); |
256 if (interface_added) { | 451 if (interface_added) { |
257 property_set = object->properties_map[interface_name] = | 452 property_set = object->properties_map[interface_name] = |
258 interface->CreateProperties(object->object_proxy, | 453 interface->CreateProperties(object->object_proxy, |
259 object_path, interface_name); | 454 object_path, interface_name); |
260 property_set->ConnectSignals(); | |
261 } else | 455 } else |
262 property_set = piter->second; | 456 property_set = piter->second; |
263 | 457 |
264 property_set->UpdatePropertiesFromReader(reader); | 458 property_set->UpdatePropertiesFromReader(reader); |
265 | 459 |
266 if (interface_added) | 460 if (interface_added) |
267 interface->ObjectAdded(object_path, interface_name); | 461 interface->ObjectAdded(object_path, interface_name); |
268 } | 462 } |
269 | 463 |
270 void ObjectManager::RemoveInterface(const ObjectPath& object_path, | 464 void ObjectManager::RemoveInterface(const ObjectPath& object_path, |
(...skipping 19 matching lines...) Expand all Loading... |
290 object->properties_map.erase(piter); | 484 object->properties_map.erase(piter); |
291 | 485 |
292 if (object->properties_map.empty()) { | 486 if (object->properties_map.empty()) { |
293 object_map_.erase(oiter); | 487 object_map_.erase(oiter); |
294 delete object; | 488 delete object; |
295 } | 489 } |
296 } | 490 } |
297 | 491 |
298 void ObjectManager::NameOwnerChanged(const std::string& old_owner, | 492 void ObjectManager::NameOwnerChanged(const std::string& old_owner, |
299 const std::string& new_owner) { | 493 const std::string& new_owner) { |
| 494 service_name_owner_ = new_owner; |
| 495 |
300 if (!old_owner.empty()) { | 496 if (!old_owner.empty()) { |
301 ObjectMap::iterator iter = object_map_.begin(); | 497 ObjectMap::iterator iter = object_map_.begin(); |
302 while (iter != object_map_.end()) { | 498 while (iter != object_map_.end()) { |
303 ObjectMap::iterator tmp = iter; | 499 ObjectMap::iterator tmp = iter; |
304 ++iter; | 500 ++iter; |
305 | 501 |
306 // PropertiesMap is mutated by RemoveInterface, and also Object is | 502 // PropertiesMap is mutated by RemoveInterface, and also Object is |
307 // destroyed; easier to collect the object path and interface names | 503 // destroyed; easier to collect the object path and interface names |
308 // and remove them safely. | 504 // and remove them safely. |
309 const dbus::ObjectPath object_path = tmp->first; | 505 const dbus::ObjectPath object_path = tmp->first; |
(...skipping 10 matching lines...) Expand all Loading... |
320 RemoveInterface(object_path, *iiter); | 516 RemoveInterface(object_path, *iiter); |
321 } | 517 } |
322 | 518 |
323 } | 519 } |
324 | 520 |
325 if (!new_owner.empty()) | 521 if (!new_owner.empty()) |
326 GetManagedObjects(); | 522 GetManagedObjects(); |
327 } | 523 } |
328 | 524 |
329 } // namespace dbus | 525 } // namespace dbus |
OLD | NEW |