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 bus_
->RemoveFilterFunction(&ObjectManager::HandleMessageThunk
, this);
160 ScopedDBusError error
;
161 bus_
->RemoveMatch(match_rule_
, error
.get());
163 LOG(ERROR
) << "Failed to remove match rule: " << match_rule_
;
168 void ObjectManager::InitializeObjects() {
170 DCHECK(object_proxy_
);
171 DCHECK(setup_success_
);
173 // |object_proxy_| is no longer valid if the Bus was shut down before this
174 // call. Don't initiate any other action from the origin thread.
178 object_proxy_
->ConnectToSignal(
179 kObjectManagerInterface
,
180 kObjectManagerInterfacesAdded
,
181 base::Bind(&ObjectManager::InterfacesAddedReceived
,
182 weak_ptr_factory_
.GetWeakPtr()),
183 base::Bind(&ObjectManager::InterfacesAddedConnected
,
184 weak_ptr_factory_
.GetWeakPtr()));
186 object_proxy_
->ConnectToSignal(
187 kObjectManagerInterface
,
188 kObjectManagerInterfacesRemoved
,
189 base::Bind(&ObjectManager::InterfacesRemovedReceived
,
190 weak_ptr_factory_
.GetWeakPtr()),
191 base::Bind(&ObjectManager::InterfacesRemovedConnected
,
192 weak_ptr_factory_
.GetWeakPtr()));
197 bool ObjectManager::SetupMatchRuleAndFilter() {
199 DCHECK(!setup_success_
);
200 bus_
->AssertOnDBusThread();
205 if (!bus_
->Connect() || !bus_
->SetUpAsyncOperations())
208 service_name_owner_
=
209 bus_
->GetServiceOwnerAndBlock(service_name_
, Bus::SUPPRESS_ERRORS
);
211 const std::string match_rule
=
213 "type='signal', sender='%s', interface='%s', member='%s'",
214 service_name_
.c_str(),
215 kPropertiesInterface
,
218 bus_
->AddFilterFunction(&ObjectManager::HandleMessageThunk
, this);
220 ScopedDBusError error
;
221 bus_
->AddMatch(match_rule
, error
.get());
222 if (error
.is_set()) {
223 LOG(ERROR
) << "ObjectManager failed to add match rule \"" << match_rule
224 << "\". Got " << error
.name() << ": " << error
.message();
225 bus_
->RemoveFilterFunction(&ObjectManager::HandleMessageThunk
, this);
229 match_rule_
= match_rule
;
230 setup_success_
= true;
235 void ObjectManager::OnSetupMatchRuleAndFilterComplete(bool success
) {
236 LOG_IF(WARNING
, !success
) << service_name_
<< " " << object_path_
.value()
237 << ": Failed to set up match rule.";
243 DBusHandlerResult
ObjectManager::HandleMessageThunk(DBusConnection
* connection
,
244 DBusMessage
* raw_message
,
246 ObjectManager
* self
= reinterpret_cast<ObjectManager
*>(user_data
);
247 return self
->HandleMessage(connection
, raw_message
);
250 DBusHandlerResult
ObjectManager::HandleMessage(DBusConnection
* connection
,
251 DBusMessage
* raw_message
) {
253 bus_
->AssertOnDBusThread();
255 if (dbus_message_get_type(raw_message
) != DBUS_MESSAGE_TYPE_SIGNAL
)
256 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
258 // raw_message will be unrefed on exit of the function. Increment the
259 // reference so we can use it in Signal.
260 dbus_message_ref(raw_message
);
261 scoped_ptr
<Signal
> signal(
262 Signal::FromRawMessage(raw_message
));
264 const std::string interface
= signal
->GetInterface();
265 const std::string member
= signal
->GetMember();
267 statistics::AddReceivedSignal(service_name_
, interface
, member
);
269 // Only handle the PropertiesChanged signal.
270 const std::string absolute_signal_name
=
271 GetAbsoluteMemberName(interface
, member
);
272 const std::string properties_changed_signal_name
=
273 GetAbsoluteMemberName(kPropertiesInterface
, kPropertiesChanged
);
274 if (absolute_signal_name
!= properties_changed_signal_name
)
275 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
277 VLOG(1) << "Signal received: " << signal
->ToString();
279 // Make sure that the signal originated from the correct sender.
280 std::string sender
= signal
->GetSender();
281 if (service_name_owner_
!= sender
) {
282 LOG(ERROR
) << "Rejecting a message from a wrong sender.";
283 UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
284 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
287 const ObjectPath path
= signal
->GetPath();
289 if (bus_
->HasDBusThread()) {
290 // Post a task to run the method in the origin thread. Transfer ownership of
291 // |signal| to NotifyPropertiesChanged, which will handle the clean up.
292 Signal
* released_signal
= signal
.release();
293 bus_
->GetOriginTaskRunner()->PostTask(
295 base::Bind(&ObjectManager::NotifyPropertiesChanged
,
299 // If the D-Bus thread is not used, just call the callback on the
300 // current thread. Transfer the ownership of |signal| to
301 // NotifyPropertiesChanged.
302 NotifyPropertiesChanged(path
, signal
.release());
305 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
306 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
307 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
310 void ObjectManager::NotifyPropertiesChanged(
311 const dbus::ObjectPath object_path
,
314 bus_
->AssertOnOriginThread();
316 NotifyPropertiesChangedHelper(object_path
, signal
);
318 // Delete the message on the D-Bus thread. See comments in HandleMessage.
319 bus_
->GetDBusTaskRunner()->PostTask(
321 base::Bind(&base::DeletePointer
<Signal
>, signal
));
324 void ObjectManager::NotifyPropertiesChangedHelper(
325 const dbus::ObjectPath object_path
,
328 bus_
->AssertOnOriginThread();
330 MessageReader
reader(signal
);
331 std::string interface
;
332 if (!reader
.PopString(&interface
)) {
333 LOG(WARNING
) << "Property changed signal has wrong parameters: "
334 << "expected interface name: " << signal
->ToString();
338 PropertySet
* properties
= GetProperties(object_path
, interface
);
340 properties
->ChangedReceived(signal
);
343 void ObjectManager::OnGetManagedObjects(Response
* response
) {
344 if (response
!= NULL
) {
345 MessageReader
reader(response
);
346 MessageReader
array_reader(NULL
);
347 if (!reader
.PopArray(&array_reader
))
350 while (array_reader
.HasMoreData()) {
351 MessageReader
dict_entry_reader(NULL
);
352 ObjectPath object_path
;
353 if (!array_reader
.PopDictEntry(&dict_entry_reader
) ||
354 !dict_entry_reader
.PopObjectPath(&object_path
))
357 UpdateObject(object_path
, &dict_entry_reader
);
361 LOG(WARNING
) << service_name_
<< " " << object_path_
.value()
362 << ": Failed to get managed objects";
366 void ObjectManager::InterfacesAddedReceived(Signal
* signal
) {
368 MessageReader
reader(signal
);
369 ObjectPath object_path
;
370 if (!reader
.PopObjectPath(&object_path
)) {
371 LOG(WARNING
) << service_name_
<< " " << object_path_
.value()
372 << ": InterfacesAdded signal has incorrect parameters: "
373 << signal
->ToString();
377 UpdateObject(object_path
, &reader
);
380 void ObjectManager::InterfacesAddedConnected(const std::string
& interface_name
,
381 const std::string
& signal_name
,
383 LOG_IF(WARNING
, !success
) << service_name_
<< " " << object_path_
.value()
384 << ": Failed to connect to InterfacesAdded signal.";
387 void ObjectManager::InterfacesRemovedReceived(Signal
* signal
) {
389 MessageReader
reader(signal
);
390 ObjectPath object_path
;
391 std::vector
<std::string
> interface_names
;
392 if (!reader
.PopObjectPath(&object_path
) ||
393 !reader
.PopArrayOfStrings(&interface_names
)) {
394 LOG(WARNING
) << service_name_
<< " " << object_path_
.value()
395 << ": InterfacesRemoved signal has incorrect parameters: "
396 << signal
->ToString();
400 for (size_t i
= 0; i
< interface_names
.size(); ++i
)
401 RemoveInterface(object_path
, interface_names
[i
]);
404 void ObjectManager::InterfacesRemovedConnected(
405 const std::string
& interface_name
,
406 const std::string
& signal_name
,
408 LOG_IF(WARNING
, !success
) << service_name_
<< " " << object_path_
.value()
409 << ": Failed to connect to "
410 << "InterfacesRemoved signal.";
413 void ObjectManager::UpdateObject(const ObjectPath
& object_path
,
414 MessageReader
* reader
) {
416 MessageReader
array_reader(NULL
);
417 if (!reader
->PopArray(&array_reader
))
420 while (array_reader
.HasMoreData()) {
421 MessageReader
dict_entry_reader(NULL
);
422 std::string interface_name
;
423 if (!array_reader
.PopDictEntry(&dict_entry_reader
) ||
424 !dict_entry_reader
.PopString(&interface_name
))
427 AddInterface(object_path
, interface_name
, &dict_entry_reader
);
432 void ObjectManager::AddInterface(const ObjectPath
& object_path
,
433 const std::string
& interface_name
,
434 MessageReader
* reader
) {
435 InterfaceMap::iterator iiter
= interface_map_
.find(interface_name
);
436 if (iiter
== interface_map_
.end())
438 Interface
* interface
= iiter
->second
;
440 ObjectMap::iterator oiter
= object_map_
.find(object_path
);
442 if (oiter
== object_map_
.end()) {
443 object
= object_map_
[object_path
] = new Object
;
444 object
->object_proxy
= bus_
->GetObjectProxy(service_name_
, object_path
);
446 object
= oiter
->second
;
448 Object::PropertiesMap::iterator piter
=
449 object
->properties_map
.find(interface_name
);
450 PropertySet
* property_set
;
451 const bool interface_added
= (piter
== object
->properties_map
.end());
452 if (interface_added
) {
453 property_set
= object
->properties_map
[interface_name
] =
454 interface
->CreateProperties(object
->object_proxy
,
455 object_path
, interface_name
);
457 property_set
= piter
->second
;
459 property_set
->UpdatePropertiesFromReader(reader
);
462 interface
->ObjectAdded(object_path
, interface_name
);
465 void ObjectManager::RemoveInterface(const ObjectPath
& object_path
,
466 const std::string
& interface_name
) {
467 ObjectMap::iterator oiter
= object_map_
.find(object_path
);
468 if (oiter
== object_map_
.end())
470 Object
* object
= oiter
->second
;
472 Object::PropertiesMap::iterator piter
=
473 object
->properties_map
.find(interface_name
);
474 if (piter
== object
->properties_map
.end())
477 // Inform the interface before removing the properties structure or object
478 // in case it needs details from them to make its own decisions.
479 InterfaceMap::iterator iiter
= interface_map_
.find(interface_name
);
480 if (iiter
!= interface_map_
.end()) {
481 Interface
* interface
= iiter
->second
;
482 interface
->ObjectRemoved(object_path
, interface_name
);
485 delete piter
->second
;
486 object
->properties_map
.erase(piter
);
488 if (object
->properties_map
.empty()) {
489 object_map_
.erase(oiter
);
494 void ObjectManager::NameOwnerChanged(const std::string
& old_owner
,
495 const std::string
& new_owner
) {
496 service_name_owner_
= new_owner
;
498 if (!old_owner
.empty()) {
499 ObjectMap::iterator iter
= object_map_
.begin();
500 while (iter
!= object_map_
.end()) {
501 ObjectMap::iterator tmp
= iter
;
504 // PropertiesMap is mutated by RemoveInterface, and also Object is
505 // destroyed; easier to collect the object path and interface names
506 // and remove them safely.
507 const dbus::ObjectPath object_path
= tmp
->first
;
508 Object
* object
= tmp
->second
;
509 std::vector
<std::string
> interfaces
;
511 for (Object::PropertiesMap::iterator piter
=
512 object
->properties_map
.begin();
513 piter
!= object
->properties_map
.end(); ++piter
)
514 interfaces
.push_back(piter
->first
);
516 for (std::vector
<std::string
>::iterator iiter
= interfaces
.begin();
517 iiter
!= interfaces
.end(); ++iiter
)
518 RemoveInterface(object_path
, *iiter
);
523 if (!new_owner
.empty())