Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / dbus / object_manager.cc
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.
4
5 #include "dbus/object_manager.h"
6
7 #include "base/bind.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"
13 #include "dbus/bus.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"
20
21 namespace dbus {
22
23 ObjectManager::Object::Object()
24   : object_proxy(NULL) {
25 }
26
27 ObjectManager::Object::~Object() {
28 }
29
30 ObjectManager::ObjectManager(Bus* bus,
31                              const std::string& service_name,
32                              const ObjectPath& object_path)
33     : bus_(bus),
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();
41   DCHECK(bus_);
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()));
47
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(),
54       FROM_HERE,
55       base::Bind(&ObjectManager::SetupMatchRuleAndFilter, this),
56       base::Bind(&ObjectManager::OnSetupMatchRuleAndFilterComplete, this));
57 }
58
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;
64
65     for (Object::PropertiesMap::iterator piter = object->properties_map.begin();
66          piter != object->properties_map.end(); ++piter) {
67       PropertySet* properties = piter->second;
68       delete properties;
69     }
70
71     delete object;
72   }
73 }
74
75 void ObjectManager::RegisterInterface(const std::string& interface_name,
76                                       Interface* interface) {
77   interface_map_[interface_name] = interface;
78 }
79
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);
84 }
85
86 std::vector<ObjectPath> ObjectManager::GetObjects() {
87   std::vector<ObjectPath> object_paths;
88
89   for (ObjectMap::iterator iter = object_map_.begin();
90        iter != object_map_.end(); ++iter)
91     object_paths.push_back(iter->first);
92
93   return object_paths;
94 }
95
96 std::vector<ObjectPath> ObjectManager::GetObjectsWithInterface(
97       const std::string& interface_name) {
98   std::vector<ObjectPath> object_paths;
99
100   for (ObjectMap::iterator oiter = object_map_.begin();
101        oiter != object_map_.end(); ++oiter) {
102     Object* object = oiter->second;
103
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);
108   }
109
110   return object_paths;
111 }
112
113 ObjectProxy* ObjectManager::GetObjectProxy(const ObjectPath& object_path) {
114   ObjectMap::iterator iter = object_map_.find(object_path);
115   if (iter == object_map_.end())
116     return NULL;
117
118   Object* object = iter->second;
119   return object->object_proxy;
120 }
121
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())
126     return NULL;
127
128   Object* object = iter->second;
129   Object::PropertiesMap::iterator piter =
130       object->properties_map.find(interface_name);
131   if (piter == object->properties_map.end())
132     return NULL;
133
134   return piter->second;
135 }
136
137 void ObjectManager::GetManagedObjects() {
138   MethodCall method_call(kObjectManagerInterface,
139                          kObjectManagerGetManagedObjects);
140
141   object_proxy_->CallMethod(
142       &method_call,
143       ObjectProxy::TIMEOUT_USE_DEFAULT,
144       base::Bind(&ObjectManager::OnGetManagedObjects,
145                  weak_ptr_factory_.GetWeakPtr()));
146 }
147
148 void ObjectManager::CleanUp() {
149   DCHECK(bus_);
150   bus_->AssertOnDBusThread();
151   DCHECK(!cleanup_called_);
152
153   cleanup_called_ = true;
154
155   if (!setup_success_)
156     return;
157
158   if (!bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this))
159     LOG(ERROR) << "Failed to remove filter function";
160
161   ScopedDBusError error;
162   bus_->RemoveMatch(match_rule_, error.get());
163   if (error.is_set())
164     LOG(ERROR) << "Failed to remove match rule: " << match_rule_;
165
166   match_rule_.clear();
167 }
168
169 void ObjectManager::InitializeObjects() {
170   DCHECK(bus_);
171   DCHECK(object_proxy_);
172   DCHECK(setup_success_);
173
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.
176   if (cleanup_called_)
177     return;
178
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()));
186
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()));
194
195   GetManagedObjects();
196 }
197
198 bool ObjectManager::SetupMatchRuleAndFilter() {
199   DCHECK(bus_);
200   DCHECK(!setup_success_);
201   bus_->AssertOnDBusThread();
202
203   if (cleanup_called_)
204     return false;
205
206   if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
207     return false;
208
209   service_name_owner_ =
210       bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
211
212   const std::string match_rule =
213       base::StringPrintf(
214           "type='signal', sender='%s', interface='%s', member='%s'",
215           service_name_.c_str(),
216           kPropertiesInterface,
217           kPropertiesChanged);
218
219   if (!bus_->AddFilterFunction(&ObjectManager::HandleMessageThunk, this)) {
220     LOG(ERROR) << "ObjectManager failed to add filter function";
221     return false;
222   }
223
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);
230     return false;
231   }
232
233   match_rule_ = match_rule;
234   setup_success_ = true;
235
236   return true;
237 }
238
239 void ObjectManager::OnSetupMatchRuleAndFilterComplete(bool success) {
240   LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
241                             << ": Failed to set up match rule.";
242   if (success)
243     InitializeObjects();
244 }
245
246 // static
247 DBusHandlerResult ObjectManager::HandleMessageThunk(DBusConnection* connection,
248                                                     DBusMessage* raw_message,
249                                                     void* user_data) {
250   ObjectManager* self = reinterpret_cast<ObjectManager*>(user_data);
251   return self->HandleMessage(connection, raw_message);
252 }
253
254 DBusHandlerResult ObjectManager::HandleMessage(DBusConnection* connection,
255                                                DBusMessage* raw_message) {
256   DCHECK(bus_);
257   bus_->AssertOnDBusThread();
258
259   if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
260     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
261
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));
267
268   const std::string interface = signal->GetInterface();
269   const std::string member = signal->GetMember();
270
271   statistics::AddReceivedSignal(service_name_, interface, member);
272
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;
280
281   VLOG(1) << "Signal received: " << signal->ToString();
282
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;
289   }
290
291   const ObjectPath path = signal->GetPath();
292
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(
298         FROM_HERE,
299         base::Bind(&ObjectManager::NotifyPropertiesChanged,
300                    this, path,
301                    released_signal));
302   } else {
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());
307   }
308
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;
312 }
313
314 void ObjectManager::NotifyPropertiesChanged(
315     const dbus::ObjectPath object_path,
316     Signal* signal) {
317   DCHECK(bus_);
318   bus_->AssertOnOriginThread();
319
320   NotifyPropertiesChangedHelper(object_path, signal);
321
322   // Delete the message on the D-Bus thread. See comments in HandleMessage.
323   bus_->GetDBusTaskRunner()->PostTask(
324       FROM_HERE,
325       base::Bind(&base::DeletePointer<Signal>, signal));
326 }
327
328 void ObjectManager::NotifyPropertiesChangedHelper(
329     const dbus::ObjectPath object_path,
330     Signal* signal) {
331   DCHECK(bus_);
332   bus_->AssertOnOriginThread();
333
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();
339     return;
340   }
341
342   PropertySet* properties = GetProperties(object_path, interface);
343   if (properties)
344     properties->ChangedReceived(signal);
345 }
346
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))
352       return;
353
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))
359         continue;
360
361       UpdateObject(object_path, &dict_entry_reader);
362     }
363
364   } else {
365     LOG(WARNING) << service_name_ << " " << object_path_.value()
366                  << ": Failed to get managed objects";
367   }
368 }
369
370 void ObjectManager::InterfacesAddedReceived(Signal* signal) {
371   DCHECK(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();
378     return;
379   }
380
381   UpdateObject(object_path, &reader);
382 }
383
384 void ObjectManager::InterfacesAddedConnected(const std::string& interface_name,
385                                              const std::string& signal_name,
386                                              bool success) {
387   LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
388                             << ": Failed to connect to InterfacesAdded signal.";
389 }
390
391 void ObjectManager::InterfacesRemovedReceived(Signal* signal) {
392   DCHECK(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();
401     return;
402   }
403
404   for (size_t i = 0; i < interface_names.size(); ++i)
405     RemoveInterface(object_path, interface_names[i]);
406 }
407
408 void ObjectManager::InterfacesRemovedConnected(
409     const std::string& interface_name,
410     const std::string& signal_name,
411     bool success) {
412   LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
413                             << ": Failed to connect to "
414                             << "InterfacesRemoved signal.";
415 }
416
417 void ObjectManager::UpdateObject(const ObjectPath& object_path,
418                                  MessageReader* reader) {
419   DCHECK(reader);
420   MessageReader array_reader(NULL);
421   if (!reader->PopArray(&array_reader))
422     return;
423
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))
429       continue;
430
431     AddInterface(object_path, interface_name, &dict_entry_reader);
432   }
433 }
434
435
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())
441     return;
442   Interface* interface = iiter->second;
443
444   ObjectMap::iterator oiter = object_map_.find(object_path);
445   Object* object;
446   if (oiter == object_map_.end()) {
447     object = object_map_[object_path] = new Object;
448     object->object_proxy = bus_->GetObjectProxy(service_name_, object_path);
449   } else
450     object = oiter->second;
451
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);
460   } else
461     property_set = piter->second;
462
463   property_set->UpdatePropertiesFromReader(reader);
464
465   if (interface_added)
466     interface->ObjectAdded(object_path, interface_name);
467 }
468
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())
473     return;
474   Object* object = oiter->second;
475
476   Object::PropertiesMap::iterator piter =
477       object->properties_map.find(interface_name);
478   if (piter == object->properties_map.end())
479     return;
480
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);
487   }
488
489   object->properties_map.erase(piter);
490
491   if (object->properties_map.empty()) {
492     object_map_.erase(oiter);
493     delete object;
494   }
495 }
496
497 void ObjectManager::NameOwnerChanged(const std::string& old_owner,
498                                      const std::string& new_owner) {
499   service_name_owner_ = new_owner;
500
501   if (!old_owner.empty()) {
502     ObjectMap::iterator iter = object_map_.begin();
503     while (iter != object_map_.end()) {
504       ObjectMap::iterator tmp = iter;
505       ++iter;
506
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;
513
514       for (Object::PropertiesMap::iterator piter =
515               object->properties_map.begin();
516            piter != object->properties_map.end(); ++piter)
517         interfaces.push_back(piter->first);
518
519       for (std::vector<std::string>::iterator iiter = interfaces.begin();
520            iiter != interfaces.end(); ++iiter)
521         RemoveInterface(object_path, *iiter);
522     }
523
524   }
525
526   if (!new_owner.empty())
527     GetManagedObjects();
528 }
529
530 }  // namespace dbus