1 // Copyright 2013 The Chromium Authors
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"
9 #include "base/functional/bind.h"
10 #include "base/functional/callback_helpers.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/metrics/histogram.h"
14 #include "base/strings/stringprintf.h"
16 #include "dbus/dbus_statistics.h"
17 #include "dbus/error.h"
18 #include "dbus/message.h"
19 #include "dbus/object_proxy.h"
20 #include "dbus/property.h"
21 #include "dbus/util.h"
25 ObjectManager::Object::Object()
26 : object_proxy(nullptr) {
29 ObjectManager::Object::~Object() = default;
31 scoped_refptr<ObjectManager> ObjectManager::Create(
33 const std::string& service_name,
34 const ObjectPath& object_path) {
36 base::WrapRefCounted(new ObjectManager(bus, service_name, object_path));
38 // Set up a match rule and a filter function to handle PropertiesChanged
39 // signals from the service. This is important to avoid any race conditions
40 // that might cause us to miss PropertiesChanged signals once all objects are
41 // initialized via GetManagedObjects.
42 bus->GetDBusTaskRunner()->PostTaskAndReplyWithResult(
44 base::BindOnce(&ObjectManager::SetupMatchRuleAndFilter, object_manager),
45 base::BindOnce(&ObjectManager::OnSetupMatchRuleAndFilterComplete,
47 return object_manager;
50 ObjectManager::ObjectManager(Bus* bus,
51 const std::string& service_name,
52 const ObjectPath& object_path)
53 : bus_(bus), service_name_(service_name), object_path_(object_path) {
54 LOG_IF(FATAL, !object_path_.IsValid()) << object_path_.value();
55 DVLOG(1) << "Creating ObjectManager for " << service_name_
56 << " " << object_path_.value();
58 bus_->AssertOnOriginThread();
59 object_proxy_ = bus_->GetObjectProxy(service_name_, object_path_);
60 object_proxy_->SetNameOwnerChangedCallback(base::BindRepeating(
61 &ObjectManager::NameOwnerChanged, weak_ptr_factory_.GetWeakPtr()));
64 ObjectManager::~ObjectManager() {
65 // Clean up Object structures
66 for (ObjectMap::iterator iter = object_map_.begin();
67 iter != object_map_.end(); ++iter) {
68 Object* object = iter->second;
70 for (Object::PropertiesMap::iterator piter = object->properties_map.begin();
71 piter != object->properties_map.end(); ++piter) {
72 PropertySet* properties = piter->second;
80 void ObjectManager::RegisterInterface(const std::string& interface_name,
81 Interface* interface) {
82 interface_map_[interface_name] = interface;
85 void ObjectManager::UnregisterInterface(const std::string& interface_name) {
86 InterfaceMap::iterator iter = interface_map_.find(interface_name);
87 if (iter != interface_map_.end())
88 interface_map_.erase(iter);
91 bool ObjectManager::IsInterfaceRegisteredForTesting(
92 const std::string& interface_name) const {
93 return interface_map_.count(interface_name);
96 std::vector<ObjectPath> ObjectManager::GetObjects() {
97 std::vector<ObjectPath> object_paths;
99 for (ObjectMap::iterator iter = object_map_.begin();
100 iter != object_map_.end(); ++iter)
101 object_paths.push_back(iter->first);
106 std::vector<ObjectPath> ObjectManager::GetObjectsWithInterface(
107 const std::string& interface_name) {
108 std::vector<ObjectPath> object_paths;
110 for (ObjectMap::iterator oiter = object_map_.begin();
111 oiter != object_map_.end(); ++oiter) {
112 Object* object = oiter->second;
114 Object::PropertiesMap::iterator piter =
115 object->properties_map.find(interface_name);
116 if (piter != object->properties_map.end())
117 object_paths.push_back(oiter->first);
123 ObjectProxy* ObjectManager::GetObjectProxy(const ObjectPath& object_path) {
124 ObjectMap::iterator iter = object_map_.find(object_path);
125 if (iter == object_map_.end())
128 Object* object = iter->second;
129 return object->object_proxy;
132 PropertySet* ObjectManager::GetProperties(const ObjectPath& object_path,
133 const std::string& interface_name) {
134 ObjectMap::iterator iter = object_map_.find(object_path);
135 if (iter == object_map_.end())
138 Object* object = iter->second;
139 Object::PropertiesMap::iterator piter =
140 object->properties_map.find(interface_name);
141 if (piter == object->properties_map.end())
144 return piter->second;
147 void ObjectManager::GetManagedObjects() {
148 MethodCall method_call(kObjectManagerInterface,
149 kObjectManagerGetManagedObjects);
151 object_proxy_->CallMethod(&method_call, ObjectProxy::TIMEOUT_USE_DEFAULT,
152 base::BindOnce(&ObjectManager::OnGetManagedObjects,
153 weak_ptr_factory_.GetWeakPtr()));
156 void ObjectManager::CleanUp() {
158 bus_->AssertOnDBusThread();
159 DCHECK(!cleanup_called_);
161 cleanup_called_ = true;
166 bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this);
168 bus_->RemoveMatch(match_rule_, &error);
169 if (error.IsValid()) {
170 LOG(ERROR) << "Failed to remove match rule: " << match_rule_;
174 // After Cleanup(), the Bus doesn't own `this` anymore and might be deleted
179 bool ObjectManager::SetupMatchRuleAndFilter() {
180 DCHECK(!setup_success_);
182 if (cleanup_called_) {
187 bus_->AssertOnDBusThread();
189 if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
192 // Try to get |service_name_owner_| from dbus if we haven't received any
193 // NameOwnerChanged signals.
194 if (service_name_owner_.empty()) {
195 service_name_owner_ =
196 bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
199 const std::string match_rule =
201 "type='signal', sender='%s', interface='%s', member='%s'",
202 service_name_.c_str(),
203 kPropertiesInterface,
206 bus_->AddFilterFunction(&ObjectManager::HandleMessageThunk, this);
209 bus_->AddMatch(match_rule, &error);
210 if (error.IsValid()) {
211 LOG(ERROR) << "ObjectManager failed to add match rule \"" << match_rule
212 << "\". Got " << error.name() << ": " << error.message();
213 bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this);
217 match_rule_ = match_rule;
218 setup_success_ = true;
223 void ObjectManager::OnSetupMatchRuleAndFilterComplete(bool success) {
225 LOG(WARNING) << service_name_ << " " << object_path_.value()
226 << ": Failed to set up match rule.";
229 DCHECK(object_proxy_);
230 DCHECK(setup_success_);
232 // |object_proxy_| is no longer valid if the Bus was shut down before this
233 // call. Don't initiate any other action from the origin thread.
234 if (cleanup_called_) {
239 bus_->AssertOnOriginThread();
241 object_proxy_->ConnectToSignal(
242 kObjectManagerInterface, kObjectManagerInterfacesAdded,
243 base::BindRepeating(&ObjectManager::InterfacesAddedReceived,
244 weak_ptr_factory_.GetWeakPtr()),
245 base::BindOnce(&ObjectManager::InterfacesAddedConnected,
246 weak_ptr_factory_.GetWeakPtr()));
248 object_proxy_->ConnectToSignal(
249 kObjectManagerInterface, kObjectManagerInterfacesRemoved,
250 base::BindRepeating(&ObjectManager::InterfacesRemovedReceived,
251 weak_ptr_factory_.GetWeakPtr()),
252 base::BindOnce(&ObjectManager::InterfacesRemovedConnected,
253 weak_ptr_factory_.GetWeakPtr()));
255 if (!service_name_owner_.empty())
260 DBusHandlerResult ObjectManager::HandleMessageThunk(DBusConnection* connection,
261 DBusMessage* raw_message,
263 ObjectManager* self = reinterpret_cast<ObjectManager*>(user_data);
264 return self->HandleMessage(connection, raw_message);
267 DBusHandlerResult ObjectManager::HandleMessage(DBusConnection* connection,
268 DBusMessage* raw_message) {
270 bus_->AssertOnDBusThread();
272 // Handle the message only if it is a signal.
273 // Note that the match rule in SetupMatchRuleAndFilter() is configured to
274 // only accept signals, but we check here just in case.
275 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
276 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
278 // raw_message will be unrefed on exit of the function. Increment the
279 // reference so we can use it in Signal.
280 dbus_message_ref(raw_message);
281 std::unique_ptr<Signal> signal(Signal::FromRawMessage(raw_message));
283 const std::string interface = signal->GetInterface();
284 const std::string member = signal->GetMember();
286 statistics::AddReceivedSignal(service_name_, interface, member);
288 // Handle the signal only if it is PropertiesChanged.
289 // Note that the match rule in SetupMatchRuleAndFilter() is configured to
290 // only accept PropertiesChanged signals, but we check here just in case.
291 const std::string absolute_signal_name =
292 GetAbsoluteMemberName(interface, member);
293 const std::string properties_changed_signal_name =
294 GetAbsoluteMemberName(kPropertiesInterface, kPropertiesChanged);
295 if (absolute_signal_name != properties_changed_signal_name)
296 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
298 VLOG(1) << "Signal received: " << signal->ToString();
300 // Handle the signal only if it is from the service that the ObjectManager
301 // instance is interested in.
302 // Note that the match rule in SetupMatchRuleAndFilter() is configured to
303 // only accept messages from the service name of our interest. However, the
304 // service='...' filter does not work as intended. See crbug.com/507206#14
305 // and #15 for details, hence it's necessary to check the sender here.
306 std::string sender = signal->GetSender();
307 if (service_name_owner_ != sender)
308 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
310 const ObjectPath path = signal->GetPath();
312 if (bus_->HasDBusThread()) {
313 // Post a task to run the method in the origin thread. Transfer ownership of
314 // |signal| to NotifyPropertiesChanged, which will handle the clean up.
315 Signal* released_signal = signal.release();
316 bus_->GetOriginTaskRunner()->PostTask(
317 FROM_HERE, base::BindOnce(&ObjectManager::NotifyPropertiesChanged, this,
318 path, released_signal));
320 // If the D-Bus thread is not used, just call the callback on the
321 // current thread. Transfer the ownership of |signal| to
322 // NotifyPropertiesChanged.
323 NotifyPropertiesChanged(path, signal.release());
326 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
327 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
328 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
331 void ObjectManager::NotifyPropertiesChanged(
332 const dbus::ObjectPath object_path,
335 bus_->AssertOnOriginThread();
337 NotifyPropertiesChangedHelper(object_path, signal);
339 // Delete the message on the D-Bus thread. See comments in HandleMessage.
340 bus_->GetDBusTaskRunner()->PostTask(
341 FROM_HERE, base::BindOnce(&base::DeletePointer<Signal>, signal));
344 void ObjectManager::NotifyPropertiesChangedHelper(
345 const dbus::ObjectPath object_path,
348 bus_->AssertOnOriginThread();
350 MessageReader reader(signal);
351 std::string interface;
352 if (!reader.PopString(&interface)) {
353 LOG(WARNING) << "Property changed signal has wrong parameters: "
354 << "expected interface name: " << signal->ToString();
358 PropertySet* properties = GetProperties(object_path, interface);
360 properties->ChangedReceived(signal);
363 void ObjectManager::OnGetManagedObjects(Response* response) {
364 if (response != nullptr) {
365 MessageReader reader(response);
366 MessageReader array_reader(nullptr);
367 if (!reader.PopArray(&array_reader))
370 while (array_reader.HasMoreData()) {
371 MessageReader dict_entry_reader(nullptr);
372 ObjectPath object_path;
373 if (!array_reader.PopDictEntry(&dict_entry_reader) ||
374 !dict_entry_reader.PopObjectPath(&object_path))
377 UpdateObject(object_path, &dict_entry_reader);
381 LOG(WARNING) << service_name_ << " " << object_path_.value()
382 << ": Failed to get managed objects";
386 void ObjectManager::InterfacesAddedReceived(Signal* signal) {
388 MessageReader reader(signal);
389 ObjectPath object_path;
390 if (!reader.PopObjectPath(&object_path)) {
391 LOG(WARNING) << service_name_ << " " << object_path_.value()
392 << ": InterfacesAdded signal has incorrect parameters: "
393 << signal->ToString();
397 UpdateObject(object_path, &reader);
400 void ObjectManager::InterfacesAddedConnected(const std::string& interface_name,
401 const std::string& signal_name,
403 LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
404 << ": Failed to connect to InterfacesAdded signal.";
407 void ObjectManager::InterfacesRemovedReceived(Signal* signal) {
409 MessageReader reader(signal);
410 ObjectPath object_path;
411 std::vector<std::string> interface_names;
412 if (!reader.PopObjectPath(&object_path) ||
413 !reader.PopArrayOfStrings(&interface_names)) {
414 LOG(WARNING) << service_name_ << " " << object_path_.value()
415 << ": InterfacesRemoved signal has incorrect parameters: "
416 << signal->ToString();
420 for (size_t i = 0; i < interface_names.size(); ++i)
421 RemoveInterface(object_path, interface_names[i]);
424 void ObjectManager::InterfacesRemovedConnected(
425 const std::string& interface_name,
426 const std::string& signal_name,
428 LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
429 << ": Failed to connect to "
430 << "InterfacesRemoved signal.";
433 void ObjectManager::UpdateObject(const ObjectPath& object_path,
434 MessageReader* reader) {
436 MessageReader array_reader(nullptr);
437 if (!reader->PopArray(&array_reader))
440 while (array_reader.HasMoreData()) {
441 MessageReader dict_entry_reader(nullptr);
442 std::string interface_name;
443 if (!array_reader.PopDictEntry(&dict_entry_reader) ||
444 !dict_entry_reader.PopString(&interface_name))
447 AddInterface(object_path, interface_name, &dict_entry_reader);
452 void ObjectManager::AddInterface(const ObjectPath& object_path,
453 const std::string& interface_name,
454 MessageReader* reader) {
455 InterfaceMap::iterator iiter = interface_map_.find(interface_name);
456 if (iiter == interface_map_.end())
458 Interface* interface = iiter->second;
460 ObjectMap::iterator oiter = object_map_.find(object_path);
462 if (oiter == object_map_.end()) {
463 object = object_map_[object_path] = new Object;
464 object->object_proxy = bus_->GetObjectProxy(service_name_, object_path);
466 object = oiter->second;
468 Object::PropertiesMap::iterator piter =
469 object->properties_map.find(interface_name);
470 PropertySet* property_set;
471 const bool interface_added = (piter == object->properties_map.end());
472 if (interface_added) {
473 property_set = object->properties_map[interface_name] =
474 interface->CreateProperties(object->object_proxy,
475 object_path, interface_name);
477 property_set = piter->second;
479 property_set->UpdatePropertiesFromReader(reader);
482 interface->ObjectAdded(object_path, interface_name);
485 void ObjectManager::RemoveInterface(const ObjectPath& object_path,
486 const std::string& interface_name) {
487 ObjectMap::iterator oiter = object_map_.find(object_path);
488 if (oiter == object_map_.end())
490 Object* object = oiter->second;
492 Object::PropertiesMap::iterator piter =
493 object->properties_map.find(interface_name);
494 if (piter == object->properties_map.end())
497 // Inform the interface before removing the properties structure or object
498 // in case it needs details from them to make its own decisions.
499 InterfaceMap::iterator iiter = interface_map_.find(interface_name);
500 if (iiter != interface_map_.end()) {
501 Interface* interface = iiter->second;
502 interface->ObjectRemoved(object_path, interface_name);
505 delete piter->second;
506 object->properties_map.erase(piter);
508 if (object->properties_map.empty()) {
509 object_map_.erase(oiter);
514 void ObjectManager::UpdateServiceNameOwner(const std::string& new_owner) {
515 bus_->AssertOnDBusThread();
516 service_name_owner_ = new_owner;
519 void ObjectManager::NameOwnerChanged(const std::string& old_owner,
520 const std::string& new_owner) {
521 bus_->AssertOnOriginThread();
523 bus_->GetDBusTaskRunner()->PostTask(
525 base::BindOnce(&ObjectManager::UpdateServiceNameOwner, this, new_owner));
527 if (!old_owner.empty()) {
528 ObjectMap::iterator iter = object_map_.begin();
529 while (iter != object_map_.end()) {
530 ObjectMap::iterator tmp = iter;
533 // PropertiesMap is mutated by RemoveInterface, and also Object is
534 // destroyed; easier to collect the object path and interface names
535 // and remove them safely.
536 const dbus::ObjectPath object_path = tmp->first;
537 Object* object = tmp->second;
538 std::vector<std::string> interfaces;
540 for (Object::PropertiesMap::iterator piter =
541 object->properties_map.begin();
542 piter != object->properties_map.end(); ++piter)
543 interfaces.push_back(piter->first);
545 for (std::vector<std::string>::iterator iiter = interfaces.begin();
546 iiter != interfaces.end(); ++iiter)
547 RemoveInterface(object_path, *iiter);
552 if (!new_owner.empty())