Fix for Geolocation webTCT failures
[platform/framework/web/chromium-efl.git] / dbus / object_manager.cc
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.
4
5 #include "dbus/object_manager.h"
6
7 #include <stddef.h>
8
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"
15 #include "dbus/bus.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"
22
23 namespace dbus {
24
25 ObjectManager::Object::Object()
26   : object_proxy(nullptr) {
27 }
28
29 ObjectManager::Object::~Object() = default;
30
31 scoped_refptr<ObjectManager> ObjectManager::Create(
32     Bus* bus,
33     const std::string& service_name,
34     const ObjectPath& object_path) {
35   auto object_manager =
36       base::WrapRefCounted(new ObjectManager(bus, service_name, object_path));
37
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(
43       FROM_HERE,
44       base::BindOnce(&ObjectManager::SetupMatchRuleAndFilter, object_manager),
45       base::BindOnce(&ObjectManager::OnSetupMatchRuleAndFilterComplete,
46                      object_manager));
47   return object_manager;
48 }
49
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();
57   DCHECK(bus_);
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()));
62 }
63
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;
69
70     for (Object::PropertiesMap::iterator piter = object->properties_map.begin();
71          piter != object->properties_map.end(); ++piter) {
72       PropertySet* properties = piter->second;
73       delete properties;
74     }
75
76     delete object;
77   }
78 }
79
80 void ObjectManager::RegisterInterface(const std::string& interface_name,
81                                       Interface* interface) {
82   interface_map_[interface_name] = interface;
83 }
84
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);
89 }
90
91 bool ObjectManager::IsInterfaceRegisteredForTesting(
92     const std::string& interface_name) const {
93   return interface_map_.count(interface_name);
94 }
95
96 std::vector<ObjectPath> ObjectManager::GetObjects() {
97   std::vector<ObjectPath> object_paths;
98
99   for (ObjectMap::iterator iter = object_map_.begin();
100        iter != object_map_.end(); ++iter)
101     object_paths.push_back(iter->first);
102
103   return object_paths;
104 }
105
106 std::vector<ObjectPath> ObjectManager::GetObjectsWithInterface(
107       const std::string& interface_name) {
108   std::vector<ObjectPath> object_paths;
109
110   for (ObjectMap::iterator oiter = object_map_.begin();
111        oiter != object_map_.end(); ++oiter) {
112     Object* object = oiter->second;
113
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);
118   }
119
120   return object_paths;
121 }
122
123 ObjectProxy* ObjectManager::GetObjectProxy(const ObjectPath& object_path) {
124   ObjectMap::iterator iter = object_map_.find(object_path);
125   if (iter == object_map_.end())
126     return nullptr;
127
128   Object* object = iter->second;
129   return object->object_proxy;
130 }
131
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())
136     return nullptr;
137
138   Object* object = iter->second;
139   Object::PropertiesMap::iterator piter =
140       object->properties_map.find(interface_name);
141   if (piter == object->properties_map.end())
142     return nullptr;
143
144   return piter->second;
145 }
146
147 void ObjectManager::GetManagedObjects() {
148   MethodCall method_call(kObjectManagerInterface,
149                          kObjectManagerGetManagedObjects);
150
151   object_proxy_->CallMethod(&method_call, ObjectProxy::TIMEOUT_USE_DEFAULT,
152                             base::BindOnce(&ObjectManager::OnGetManagedObjects,
153                                            weak_ptr_factory_.GetWeakPtr()));
154 }
155
156 void ObjectManager::CleanUp() {
157   DCHECK(bus_);
158   bus_->AssertOnDBusThread();
159   DCHECK(!cleanup_called_);
160
161   cleanup_called_ = true;
162
163   if (!setup_success_)
164     return;
165
166   bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this);
167   Error error;
168   bus_->RemoveMatch(match_rule_, &error);
169   if (error.IsValid()) {
170     LOG(ERROR) << "Failed to remove match rule: " << match_rule_;
171   }
172
173   match_rule_.clear();
174   // After Cleanup(), the Bus doesn't own `this` anymore and might be deleted
175   // before `this`.
176   bus_ = nullptr;
177 }
178
179 bool ObjectManager::SetupMatchRuleAndFilter() {
180   DCHECK(!setup_success_);
181
182   if (cleanup_called_) {
183     return false;
184   }
185
186   DCHECK(bus_);
187   bus_->AssertOnDBusThread();
188
189   if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
190     return false;
191
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);
197   }
198
199   const std::string match_rule =
200       base::StringPrintf(
201           "type='signal', sender='%s', interface='%s', member='%s'",
202           service_name_.c_str(),
203           kPropertiesInterface,
204           kPropertiesChanged);
205
206   bus_->AddFilterFunction(&ObjectManager::HandleMessageThunk, this);
207
208   Error error;
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);
214     return false;
215   }
216
217   match_rule_ = match_rule;
218   setup_success_ = true;
219
220   return true;
221 }
222
223 void ObjectManager::OnSetupMatchRuleAndFilterComplete(bool success) {
224   if (!success) {
225     LOG(WARNING) << service_name_ << " " << object_path_.value()
226                  << ": Failed to set up match rule.";
227     return;
228   }
229   DCHECK(object_proxy_);
230   DCHECK(setup_success_);
231
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_) {
235     return;
236   }
237
238   DCHECK(bus_);
239   bus_->AssertOnOriginThread();
240
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()));
247
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()));
254
255   if (!service_name_owner_.empty())
256     GetManagedObjects();
257 }
258
259 // static
260 DBusHandlerResult ObjectManager::HandleMessageThunk(DBusConnection* connection,
261                                                     DBusMessage* raw_message,
262                                                     void* user_data) {
263   ObjectManager* self = reinterpret_cast<ObjectManager*>(user_data);
264   return self->HandleMessage(connection, raw_message);
265 }
266
267 DBusHandlerResult ObjectManager::HandleMessage(DBusConnection* connection,
268                                                DBusMessage* raw_message) {
269   DCHECK(bus_);
270   bus_->AssertOnDBusThread();
271
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;
277
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));
282
283   const std::string interface = signal->GetInterface();
284   const std::string member = signal->GetMember();
285
286   statistics::AddReceivedSignal(service_name_, interface, member);
287
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;
297
298   VLOG(1) << "Signal received: " << signal->ToString();
299
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;
309
310   const ObjectPath path = signal->GetPath();
311
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));
319   } else {
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());
324   }
325
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;
329 }
330
331 void ObjectManager::NotifyPropertiesChanged(
332     const dbus::ObjectPath object_path,
333     Signal* signal) {
334   DCHECK(bus_);
335   bus_->AssertOnOriginThread();
336
337   NotifyPropertiesChangedHelper(object_path, signal);
338
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));
342 }
343
344 void ObjectManager::NotifyPropertiesChangedHelper(
345     const dbus::ObjectPath object_path,
346     Signal* signal) {
347   DCHECK(bus_);
348   bus_->AssertOnOriginThread();
349
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();
355     return;
356   }
357
358   PropertySet* properties = GetProperties(object_path, interface);
359   if (properties)
360     properties->ChangedReceived(signal);
361 }
362
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))
368       return;
369
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))
375         continue;
376
377       UpdateObject(object_path, &dict_entry_reader);
378     }
379
380   } else {
381     LOG(WARNING) << service_name_ << " " << object_path_.value()
382                  << ": Failed to get managed objects";
383   }
384 }
385
386 void ObjectManager::InterfacesAddedReceived(Signal* signal) {
387   DCHECK(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();
394     return;
395   }
396
397   UpdateObject(object_path, &reader);
398 }
399
400 void ObjectManager::InterfacesAddedConnected(const std::string& interface_name,
401                                              const std::string& signal_name,
402                                              bool success) {
403   LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
404                             << ": Failed to connect to InterfacesAdded signal.";
405 }
406
407 void ObjectManager::InterfacesRemovedReceived(Signal* signal) {
408   DCHECK(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();
417     return;
418   }
419
420   for (size_t i = 0; i < interface_names.size(); ++i)
421     RemoveInterface(object_path, interface_names[i]);
422 }
423
424 void ObjectManager::InterfacesRemovedConnected(
425     const std::string& interface_name,
426     const std::string& signal_name,
427     bool success) {
428   LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
429                             << ": Failed to connect to "
430                             << "InterfacesRemoved signal.";
431 }
432
433 void ObjectManager::UpdateObject(const ObjectPath& object_path,
434                                  MessageReader* reader) {
435   DCHECK(reader);
436   MessageReader array_reader(nullptr);
437   if (!reader->PopArray(&array_reader))
438     return;
439
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))
445       continue;
446
447     AddInterface(object_path, interface_name, &dict_entry_reader);
448   }
449 }
450
451
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())
457     return;
458   Interface* interface = iiter->second;
459
460   ObjectMap::iterator oiter = object_map_.find(object_path);
461   Object* object;
462   if (oiter == object_map_.end()) {
463     object = object_map_[object_path] = new Object;
464     object->object_proxy = bus_->GetObjectProxy(service_name_, object_path);
465   } else
466     object = oiter->second;
467
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);
476   } else
477     property_set = piter->second;
478
479   property_set->UpdatePropertiesFromReader(reader);
480
481   if (interface_added)
482     interface->ObjectAdded(object_path, interface_name);
483 }
484
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())
489     return;
490   Object* object = oiter->second;
491
492   Object::PropertiesMap::iterator piter =
493       object->properties_map.find(interface_name);
494   if (piter == object->properties_map.end())
495     return;
496
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);
503   }
504
505   delete piter->second;
506   object->properties_map.erase(piter);
507
508   if (object->properties_map.empty()) {
509     object_map_.erase(oiter);
510     delete object;
511   }
512 }
513
514 void ObjectManager::UpdateServiceNameOwner(const std::string& new_owner) {
515   bus_->AssertOnDBusThread();
516   service_name_owner_ = new_owner;
517 }
518
519 void ObjectManager::NameOwnerChanged(const std::string& old_owner,
520                                      const std::string& new_owner) {
521   bus_->AssertOnOriginThread();
522
523   bus_->GetDBusTaskRunner()->PostTask(
524       FROM_HERE,
525       base::BindOnce(&ObjectManager::UpdateServiceNameOwner, this, new_owner));
526
527   if (!old_owner.empty()) {
528     ObjectMap::iterator iter = object_map_.begin();
529     while (iter != object_map_.end()) {
530       ObjectMap::iterator tmp = iter;
531       ++iter;
532
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;
539
540       for (Object::PropertiesMap::iterator piter =
541               object->properties_map.begin();
542            piter != object->properties_map.end(); ++piter)
543         interfaces.push_back(piter->first);
544
545       for (std::vector<std::string>::iterator iiter = interfaces.begin();
546            iiter != interfaces.end(); ++iiter)
547         RemoveInterface(object_path, *iiter);
548     }
549
550   }
551
552   if (!new_owner.empty())
553     GetManagedObjects();
554 }
555
556 }  // namespace dbus