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.
5 #include "dbus/object_manager.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"
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"
23 ObjectManager::Object::Object()
24 : object_proxy(NULL
) {
27 ObjectManager::Object::~Object() {
30 ObjectManager::ObjectManager(Bus
* bus
,
31 const std::string
& service_name
,
32 const ObjectPath
& object_path
)
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();
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()));
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(),
55 base::Bind(&ObjectManager::SetupMatchRuleAndFilter
, this),
56 base::Bind(&ObjectManager::OnSetupMatchRuleAndFilterComplete
, this));
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
;
65 for (Object::PropertiesMap::iterator piter
= object
->properties_map
.begin();
66 piter
!= object
->properties_map
.end(); ++piter
) {
67 PropertySet
* properties
= piter
->second
;
75 void ObjectManager::RegisterInterface(const std::string
& interface_name
,
76 Interface
* interface
) {
77 interface_map_
[interface_name
] = interface
;
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
);
86 std::vector
<ObjectPath
> ObjectManager::GetObjects() {
87 std::vector
<ObjectPath
> object_paths
;
89 for (ObjectMap::iterator iter
= object_map_
.begin();
90 iter
!= object_map_
.end(); ++iter
)
91 object_paths
.push_back(iter
->first
);
96 std::vector
<ObjectPath
> ObjectManager::GetObjectsWithInterface(
97 const std::string
& interface_name
) {
98 std::vector
<ObjectPath
> object_paths
;
100 for (ObjectMap::iterator oiter
= object_map_
.begin();
101 oiter
!= object_map_
.end(); ++oiter
) {
102 Object
* object
= oiter
->second
;
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
);
113 ObjectProxy
* ObjectManager::GetObjectProxy(const ObjectPath
& object_path
) {
114 ObjectMap::iterator iter
= object_map_
.find(object_path
);
115 if (iter
== object_map_
.end())
118 Object
* object
= iter
->second
;
119 return object
->object_proxy
;
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())
128 Object
* object
= iter
->second
;
129 Object::PropertiesMap::iterator piter
=
130 object
->properties_map
.find(interface_name
);
131 if (piter
== object
->properties_map
.end())
134 return piter
->second
;
137 void ObjectManager::GetManagedObjects() {
138 MethodCall
method_call(kObjectManagerInterface
,
139 kObjectManagerGetManagedObjects
);
141 object_proxy_
->CallMethod(
143 ObjectProxy::TIMEOUT_USE_DEFAULT
,
144 base::Bind(&ObjectManager::OnGetManagedObjects
,
145 weak_ptr_factory_
.GetWeakPtr()));
148 void ObjectManager::CleanUp() {
150 bus_
->AssertOnDBusThread();
151 DCHECK(!cleanup_called_
);
153 cleanup_called_
= true;
158 if (!bus_
->RemoveFilterFunction(&ObjectManager::HandleMessageThunk
, this))
159 LOG(ERROR
) << "Failed to remove filter function";
161 ScopedDBusError error
;
162 bus_
->RemoveMatch(match_rule_
, error
.get());
164 LOG(ERROR
) << "Failed to remove match rule: " << match_rule_
;
169 void ObjectManager::InitializeObjects() {
171 DCHECK(object_proxy_
);
172 DCHECK(setup_success_
);
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.
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()));
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()));
198 bool ObjectManager::SetupMatchRuleAndFilter() {
200 DCHECK(!setup_success_
);
201 bus_
->AssertOnDBusThread();
206 if (!bus_
->Connect() || !bus_
->SetUpAsyncOperations())
209 service_name_owner_
=
210 bus_
->GetServiceOwnerAndBlock(service_name_
, Bus::SUPPRESS_ERRORS
);
212 const std::string match_rule
=
214 "type='signal', sender='%s', interface='%s', member='%s'",
215 service_name_
.c_str(),
216 kPropertiesInterface
,
219 if (!bus_
->AddFilterFunction(&ObjectManager::HandleMessageThunk
, this)) {
220 LOG(ERROR
) << "ObjectManager failed to add filter function";
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);
233 match_rule_
= match_rule
;
234 setup_success_
= true;
239 void ObjectManager::OnSetupMatchRuleAndFilterComplete(bool success
) {
240 LOG_IF(WARNING
, !success
) << service_name_
<< " " << object_path_
.value()
241 << ": Failed to set up match rule.";
247 DBusHandlerResult
ObjectManager::HandleMessageThunk(DBusConnection
* connection
,
248 DBusMessage
* raw_message
,
250 ObjectManager
* self
= reinterpret_cast<ObjectManager
*>(user_data
);
251 return self
->HandleMessage(connection
, raw_message
);
254 DBusHandlerResult
ObjectManager::HandleMessage(DBusConnection
* connection
,
255 DBusMessage
* raw_message
) {
257 bus_
->AssertOnDBusThread();
259 if (dbus_message_get_type(raw_message
) != DBUS_MESSAGE_TYPE_SIGNAL
)
260 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
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
));
268 const std::string interface
= signal
->GetInterface();
269 const std::string member
= signal
->GetMember();
271 statistics::AddReceivedSignal(service_name_
, interface
, member
);
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
;
281 VLOG(1) << "Signal received: " << signal
->ToString();
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
;
291 const ObjectPath path
= signal
->GetPath();
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(
299 base::Bind(&ObjectManager::NotifyPropertiesChanged
,
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());
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
;
314 void ObjectManager::NotifyPropertiesChanged(
315 const dbus::ObjectPath object_path
,
318 bus_
->AssertOnOriginThread();
320 NotifyPropertiesChangedHelper(object_path
, signal
);
322 // Delete the message on the D-Bus thread. See comments in HandleMessage.
323 bus_
->GetDBusTaskRunner()->PostTask(
325 base::Bind(&base::DeletePointer
<Signal
>, signal
));
328 void ObjectManager::NotifyPropertiesChangedHelper(
329 const dbus::ObjectPath object_path
,
332 bus_
->AssertOnOriginThread();
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();
342 PropertySet
* properties
= GetProperties(object_path
, interface
);
344 properties
->ChangedReceived(signal
);
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
))
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
))
361 UpdateObject(object_path
, &dict_entry_reader
);
365 LOG(WARNING
) << service_name_
<< " " << object_path_
.value()
366 << ": Failed to get managed objects";
370 void ObjectManager::InterfacesAddedReceived(Signal
* 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();
381 UpdateObject(object_path
, &reader
);
384 void ObjectManager::InterfacesAddedConnected(const std::string
& interface_name
,
385 const std::string
& signal_name
,
387 LOG_IF(WARNING
, !success
) << service_name_
<< " " << object_path_
.value()
388 << ": Failed to connect to InterfacesAdded signal.";
391 void ObjectManager::InterfacesRemovedReceived(Signal
* 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();
404 for (size_t i
= 0; i
< interface_names
.size(); ++i
)
405 RemoveInterface(object_path
, interface_names
[i
]);
408 void ObjectManager::InterfacesRemovedConnected(
409 const std::string
& interface_name
,
410 const std::string
& signal_name
,
412 LOG_IF(WARNING
, !success
) << service_name_
<< " " << object_path_
.value()
413 << ": Failed to connect to "
414 << "InterfacesRemoved signal.";
417 void ObjectManager::UpdateObject(const ObjectPath
& object_path
,
418 MessageReader
* reader
) {
420 MessageReader
array_reader(NULL
);
421 if (!reader
->PopArray(&array_reader
))
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
))
431 AddInterface(object_path
, interface_name
, &dict_entry_reader
);
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())
442 Interface
* interface
= iiter
->second
;
444 ObjectMap::iterator oiter
= object_map_
.find(object_path
);
446 if (oiter
== object_map_
.end()) {
447 object
= object_map_
[object_path
] = new Object
;
448 object
->object_proxy
= bus_
->GetObjectProxy(service_name_
, object_path
);
450 object
= oiter
->second
;
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
);
461 property_set
= piter
->second
;
463 property_set
->UpdatePropertiesFromReader(reader
);
466 interface
->ObjectAdded(object_path
, interface_name
);
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())
474 Object
* object
= oiter
->second
;
476 Object::PropertiesMap::iterator piter
=
477 object
->properties_map
.find(interface_name
);
478 if (piter
== object
->properties_map
.end())
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
);
489 object
->properties_map
.erase(piter
);
491 if (object
->properties_map
.empty()) {
492 object_map_
.erase(oiter
);
497 void ObjectManager::NameOwnerChanged(const std::string
& old_owner
,
498 const std::string
& new_owner
) {
499 service_name_owner_
= new_owner
;
501 if (!old_owner
.empty()) {
502 ObjectMap::iterator iter
= object_map_
.begin();
503 while (iter
!= object_map_
.end()) {
504 ObjectMap::iterator tmp
= iter
;
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
;
514 for (Object::PropertiesMap::iterator piter
=
515 object
->properties_map
.begin();
516 piter
!= object
->properties_map
.end(); ++piter
)
517 interfaces
.push_back(piter
->first
);
519 for (std::vector
<std::string
>::iterator iiter
= interfaces
.begin();
520 iiter
!= interfaces
.end(); ++iiter
)
521 RemoveInterface(object_path
, *iiter
);
526 if (!new_owner
.empty())