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 // Handle the message only if it is a signal.
256 // Note that the match rule in SetupMatchRuleAndFilter() is configured to
257 // only accept signals, but we check here just in case.
258 if (dbus_message_get_type(raw_message
) != DBUS_MESSAGE_TYPE_SIGNAL
)
259 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
261 // raw_message will be unrefed on exit of the function. Increment the
262 // reference so we can use it in Signal.
263 dbus_message_ref(raw_message
);
264 scoped_ptr
<Signal
> signal(
265 Signal::FromRawMessage(raw_message
));
267 const std::string interface
= signal
->GetInterface();
268 const std::string member
= signal
->GetMember();
270 statistics::AddReceivedSignal(service_name_
, interface
, member
);
272 // Handle the signal only if it is PropertiesChanged.
273 // Note that the match rule in SetupMatchRuleAndFilter() is configured to
274 // only accept PropertiesChanged signals, but we check here just in case.
275 const std::string absolute_signal_name
=
276 GetAbsoluteMemberName(interface
, member
);
277 const std::string properties_changed_signal_name
=
278 GetAbsoluteMemberName(kPropertiesInterface
, kPropertiesChanged
);
279 if (absolute_signal_name
!= properties_changed_signal_name
)
280 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
282 VLOG(1) << "Signal received: " << signal
->ToString();
284 // Handle the signal only if it is from the service that the ObjectManager
285 // instance is interested in.
286 // Note that the match rule in SetupMatchRuleAndFilter() is configured to
287 // only accept messages from the service name of our interest. However, the
288 // service='...' filter does not work as intended. See crbug.com/507206#14
289 // and #15 for details, hence it's necessary to check the sender here.
290 std::string sender
= signal
->GetSender();
291 if (service_name_owner_
!= sender
)
292 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
294 const ObjectPath path
= signal
->GetPath();
296 if (bus_
->HasDBusThread()) {
297 // Post a task to run the method in the origin thread. Transfer ownership of
298 // |signal| to NotifyPropertiesChanged, which will handle the clean up.
299 Signal
* released_signal
= signal
.release();
300 bus_
->GetOriginTaskRunner()->PostTask(
302 base::Bind(&ObjectManager::NotifyPropertiesChanged
,
306 // If the D-Bus thread is not used, just call the callback on the
307 // current thread. Transfer the ownership of |signal| to
308 // NotifyPropertiesChanged.
309 NotifyPropertiesChanged(path
, signal
.release());
312 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
313 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
314 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
317 void ObjectManager::NotifyPropertiesChanged(
318 const dbus::ObjectPath object_path
,
321 bus_
->AssertOnOriginThread();
323 NotifyPropertiesChangedHelper(object_path
, signal
);
325 // Delete the message on the D-Bus thread. See comments in HandleMessage.
326 bus_
->GetDBusTaskRunner()->PostTask(
328 base::Bind(&base::DeletePointer
<Signal
>, signal
));
331 void ObjectManager::NotifyPropertiesChangedHelper(
332 const dbus::ObjectPath object_path
,
335 bus_
->AssertOnOriginThread();
337 MessageReader
reader(signal
);
338 std::string interface
;
339 if (!reader
.PopString(&interface
)) {
340 LOG(WARNING
) << "Property changed signal has wrong parameters: "
341 << "expected interface name: " << signal
->ToString();
345 PropertySet
* properties
= GetProperties(object_path
, interface
);
347 properties
->ChangedReceived(signal
);
350 void ObjectManager::OnGetManagedObjects(Response
* response
) {
351 if (response
!= NULL
) {
352 MessageReader
reader(response
);
353 MessageReader
array_reader(NULL
);
354 if (!reader
.PopArray(&array_reader
))
357 while (array_reader
.HasMoreData()) {
358 MessageReader
dict_entry_reader(NULL
);
359 ObjectPath object_path
;
360 if (!array_reader
.PopDictEntry(&dict_entry_reader
) ||
361 !dict_entry_reader
.PopObjectPath(&object_path
))
364 UpdateObject(object_path
, &dict_entry_reader
);
368 LOG(WARNING
) << service_name_
<< " " << object_path_
.value()
369 << ": Failed to get managed objects";
373 void ObjectManager::InterfacesAddedReceived(Signal
* signal
) {
375 MessageReader
reader(signal
);
376 ObjectPath object_path
;
377 if (!reader
.PopObjectPath(&object_path
)) {
378 LOG(WARNING
) << service_name_
<< " " << object_path_
.value()
379 << ": InterfacesAdded signal has incorrect parameters: "
380 << signal
->ToString();
384 UpdateObject(object_path
, &reader
);
387 void ObjectManager::InterfacesAddedConnected(const std::string
& interface_name
,
388 const std::string
& signal_name
,
390 LOG_IF(WARNING
, !success
) << service_name_
<< " " << object_path_
.value()
391 << ": Failed to connect to InterfacesAdded signal.";
394 void ObjectManager::InterfacesRemovedReceived(Signal
* signal
) {
396 MessageReader
reader(signal
);
397 ObjectPath object_path
;
398 std::vector
<std::string
> interface_names
;
399 if (!reader
.PopObjectPath(&object_path
) ||
400 !reader
.PopArrayOfStrings(&interface_names
)) {
401 LOG(WARNING
) << service_name_
<< " " << object_path_
.value()
402 << ": InterfacesRemoved signal has incorrect parameters: "
403 << signal
->ToString();
407 for (size_t i
= 0; i
< interface_names
.size(); ++i
)
408 RemoveInterface(object_path
, interface_names
[i
]);
411 void ObjectManager::InterfacesRemovedConnected(
412 const std::string
& interface_name
,
413 const std::string
& signal_name
,
415 LOG_IF(WARNING
, !success
) << service_name_
<< " " << object_path_
.value()
416 << ": Failed to connect to "
417 << "InterfacesRemoved signal.";
420 void ObjectManager::UpdateObject(const ObjectPath
& object_path
,
421 MessageReader
* reader
) {
423 MessageReader
array_reader(NULL
);
424 if (!reader
->PopArray(&array_reader
))
427 while (array_reader
.HasMoreData()) {
428 MessageReader
dict_entry_reader(NULL
);
429 std::string interface_name
;
430 if (!array_reader
.PopDictEntry(&dict_entry_reader
) ||
431 !dict_entry_reader
.PopString(&interface_name
))
434 AddInterface(object_path
, interface_name
, &dict_entry_reader
);
439 void ObjectManager::AddInterface(const ObjectPath
& object_path
,
440 const std::string
& interface_name
,
441 MessageReader
* reader
) {
442 InterfaceMap::iterator iiter
= interface_map_
.find(interface_name
);
443 if (iiter
== interface_map_
.end())
445 Interface
* interface
= iiter
->second
;
447 ObjectMap::iterator oiter
= object_map_
.find(object_path
);
449 if (oiter
== object_map_
.end()) {
450 object
= object_map_
[object_path
] = new Object
;
451 object
->object_proxy
= bus_
->GetObjectProxy(service_name_
, object_path
);
453 object
= oiter
->second
;
455 Object::PropertiesMap::iterator piter
=
456 object
->properties_map
.find(interface_name
);
457 PropertySet
* property_set
;
458 const bool interface_added
= (piter
== object
->properties_map
.end());
459 if (interface_added
) {
460 property_set
= object
->properties_map
[interface_name
] =
461 interface
->CreateProperties(object
->object_proxy
,
462 object_path
, interface_name
);
464 property_set
= piter
->second
;
466 property_set
->UpdatePropertiesFromReader(reader
);
469 interface
->ObjectAdded(object_path
, interface_name
);
472 void ObjectManager::RemoveInterface(const ObjectPath
& object_path
,
473 const std::string
& interface_name
) {
474 ObjectMap::iterator oiter
= object_map_
.find(object_path
);
475 if (oiter
== object_map_
.end())
477 Object
* object
= oiter
->second
;
479 Object::PropertiesMap::iterator piter
=
480 object
->properties_map
.find(interface_name
);
481 if (piter
== object
->properties_map
.end())
484 // Inform the interface before removing the properties structure or object
485 // in case it needs details from them to make its own decisions.
486 InterfaceMap::iterator iiter
= interface_map_
.find(interface_name
);
487 if (iiter
!= interface_map_
.end()) {
488 Interface
* interface
= iiter
->second
;
489 interface
->ObjectRemoved(object_path
, interface_name
);
492 delete piter
->second
;
493 object
->properties_map
.erase(piter
);
495 if (object
->properties_map
.empty()) {
496 object_map_
.erase(oiter
);
501 void ObjectManager::NameOwnerChanged(const std::string
& old_owner
,
502 const std::string
& new_owner
) {
503 service_name_owner_
= new_owner
;
505 if (!old_owner
.empty()) {
506 ObjectMap::iterator iter
= object_map_
.begin();
507 while (iter
!= object_map_
.end()) {
508 ObjectMap::iterator tmp
= iter
;
511 // PropertiesMap is mutated by RemoveInterface, and also Object is
512 // destroyed; easier to collect the object path and interface names
513 // and remove them safely.
514 const dbus::ObjectPath object_path
= tmp
->first
;
515 Object
* object
= tmp
->second
;
516 std::vector
<std::string
> interfaces
;
518 for (Object::PropertiesMap::iterator piter
=
519 object
->properties_map
.begin();
520 piter
!= object
->properties_map
.end(); ++piter
)
521 interfaces
.push_back(piter
->first
);
523 for (std::vector
<std::string
>::iterator iiter
= interfaces
.begin();
524 iiter
!= interfaces
.end(); ++iiter
)
525 RemoveInterface(object_path
, *iiter
);
530 if (!new_owner
.empty())