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/logging.h"
9#include "dbus/bus.h"
10#include "dbus/message.h"
11#include "dbus/object_proxy.h"
12#include "dbus/property.h"
13
14namespace dbus {
15
16ObjectManager::Object::Object()
17  : object_proxy(NULL) {
18}
19
20ObjectManager::Object::~Object() {
21}
22
23ObjectManager::ObjectManager(Bus* bus,
24                             const std::string& service_name,
25                             const ObjectPath& object_path)
26    : bus_(bus),
27      service_name_(service_name),
28      object_path_(object_path),
29      weak_ptr_factory_(this) {
30  DVLOG(1) << "Creating ObjectManager for " << service_name_
31           << " " << object_path_.value();
32
33  DCHECK(bus_);
34  object_proxy_ = bus_->GetObjectProxy(service_name_, object_path_);
35  object_proxy_->SetNameOwnerChangedCallback(
36      base::Bind(&ObjectManager::NameOwnerChanged,
37                 weak_ptr_factory_.GetWeakPtr()));
38
39  object_proxy_->ConnectToSignal(
40      kObjectManagerInterface,
41      kObjectManagerInterfacesAdded,
42      base::Bind(&ObjectManager::InterfacesAddedReceived,
43                 weak_ptr_factory_.GetWeakPtr()),
44      base::Bind(&ObjectManager::InterfacesAddedConnected,
45                 weak_ptr_factory_.GetWeakPtr()));
46
47  object_proxy_->ConnectToSignal(
48      kObjectManagerInterface,
49      kObjectManagerInterfacesRemoved,
50      base::Bind(&ObjectManager::InterfacesRemovedReceived,
51                 weak_ptr_factory_.GetWeakPtr()),
52      base::Bind(&ObjectManager::InterfacesRemovedConnected,
53                 weak_ptr_factory_.GetWeakPtr()));
54
55  GetManagedObjects();
56}
57
58ObjectManager::~ObjectManager() {
59  // Clean up Object structures
60  for (ObjectMap::iterator iter = object_map_.begin();
61       iter != object_map_.end(); ++iter) {
62    Object* object = iter->second;
63
64    for (Object::PropertiesMap::iterator piter = object->properties_map.begin();
65         piter != object->properties_map.end(); ++piter) {
66      PropertySet* properties = piter->second;
67      delete properties;
68    }
69
70    delete object;
71  }
72}
73
74void ObjectManager::RegisterInterface(const std::string& interface_name,
75                                      Interface* interface) {
76  interface_map_[interface_name] = interface;
77}
78
79void ObjectManager::UnregisterInterface(const std::string& interface_name) {
80  InterfaceMap::iterator iter = interface_map_.find(interface_name);
81  if (iter != interface_map_.end())
82    interface_map_.erase(iter);
83}
84
85std::vector<ObjectPath> ObjectManager::GetObjects() {
86  std::vector<ObjectPath> object_paths;
87
88  for (ObjectMap::iterator iter = object_map_.begin();
89       iter != object_map_.end(); ++iter)
90    object_paths.push_back(iter->first);
91
92  return object_paths;
93}
94
95std::vector<ObjectPath> ObjectManager::GetObjectsWithInterface(
96      const std::string& interface_name) {
97  std::vector<ObjectPath> object_paths;
98
99  for (ObjectMap::iterator oiter = object_map_.begin();
100       oiter != object_map_.end(); ++oiter) {
101    Object* object = oiter->second;
102
103    Object::PropertiesMap::iterator piter =
104        object->properties_map.find(interface_name);
105    if (piter != object->properties_map.end())
106      object_paths.push_back(oiter->first);
107  }
108
109  return object_paths;
110}
111
112ObjectProxy* ObjectManager::GetObjectProxy(const ObjectPath& object_path) {
113  ObjectMap::iterator iter = object_map_.find(object_path);
114  if (iter == object_map_.end())
115    return NULL;
116
117  Object* object = iter->second;
118  return object->object_proxy;
119}
120
121PropertySet* ObjectManager::GetProperties(const ObjectPath& object_path,
122                                          const std::string& interface_name) {
123  ObjectMap::iterator iter = object_map_.find(object_path);
124  if (iter == object_map_.end())
125    return NULL;
126
127  Object* object = iter->second;
128  Object::PropertiesMap::iterator piter =
129      object->properties_map.find(interface_name);
130  if (piter == object->properties_map.end())
131    return NULL;
132
133  return piter->second;
134}
135
136void ObjectManager::GetManagedObjects() {
137  MethodCall method_call(kObjectManagerInterface,
138                         kObjectManagerGetManagedObjects);
139
140  object_proxy_->CallMethod(
141      &method_call,
142      ObjectProxy::TIMEOUT_USE_DEFAULT,
143      base::Bind(&ObjectManager::OnGetManagedObjects,
144                 weak_ptr_factory_.GetWeakPtr()));
145}
146
147void ObjectManager::OnGetManagedObjects(Response* response) {
148  if (response != NULL) {
149    MessageReader reader(response);
150    MessageReader array_reader(NULL);
151    if (!reader.PopArray(&array_reader))
152      return;
153
154    while (array_reader.HasMoreData()) {
155      MessageReader dict_entry_reader(NULL);
156      ObjectPath object_path;
157      if (!array_reader.PopDictEntry(&dict_entry_reader) ||
158          !dict_entry_reader.PopObjectPath(&object_path))
159        continue;
160
161      UpdateObject(object_path, &dict_entry_reader);
162    }
163
164  } else {
165    LOG(WARNING) << service_name_ << " " << object_path_.value()
166                 << ": Failed to get managed objects";
167  }
168}
169
170void ObjectManager::InterfacesAddedReceived(Signal* signal) {
171  DCHECK(signal);
172  MessageReader reader(signal);
173  ObjectPath object_path;
174  if (!reader.PopObjectPath(&object_path)) {
175    LOG(WARNING) << service_name_ << " " << object_path_.value()
176                 << ": InterfacesAdded signal has incorrect parameters: "
177                 << signal->ToString();
178    return;
179  }
180
181  UpdateObject(object_path, &reader);
182}
183
184void ObjectManager::InterfacesAddedConnected(const std::string& interface_name,
185                                             const std::string& signal_name,
186                                             bool success) {
187  LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
188                            << ": Failed to connect to InterfacesAdded signal.";
189}
190
191void ObjectManager::InterfacesRemovedReceived(Signal* signal) {
192  DCHECK(signal);
193  MessageReader reader(signal);
194  ObjectPath object_path;
195  std::vector<std::string> interface_names;
196  if (!reader.PopObjectPath(&object_path) ||
197      !reader.PopArrayOfStrings(&interface_names)) {
198    LOG(WARNING) << service_name_ << " " << object_path_.value()
199                 << ": InterfacesRemoved signal has incorrect parameters: "
200                 << signal->ToString();
201    return;
202  }
203
204  for (size_t i = 0; i < interface_names.size(); ++i)
205    RemoveInterface(object_path, interface_names[i]);
206}
207
208void ObjectManager::InterfacesRemovedConnected(
209    const std::string& interface_name,
210    const std::string& signal_name,
211    bool success) {
212  LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
213                            << ": Failed to connect to "
214                            << "InterfacesRemoved signal.";
215}
216
217void ObjectManager::UpdateObject(const ObjectPath& object_path,
218                                 MessageReader* reader) {
219  DCHECK(reader);
220  MessageReader array_reader(NULL);
221  if (!reader->PopArray(&array_reader))
222    return;
223
224  while (array_reader.HasMoreData()) {
225    MessageReader dict_entry_reader(NULL);
226    std::string interface_name;
227    if (!array_reader.PopDictEntry(&dict_entry_reader) ||
228        !dict_entry_reader.PopString(&interface_name))
229      continue;
230
231    AddInterface(object_path, interface_name, &dict_entry_reader);
232  }
233}
234
235
236void ObjectManager::AddInterface(const ObjectPath& object_path,
237                                 const std::string& interface_name,
238                                 MessageReader* reader) {
239  InterfaceMap::iterator iiter = interface_map_.find(interface_name);
240  if (iiter == interface_map_.end())
241    return;
242  Interface* interface = iiter->second;
243
244  ObjectMap::iterator oiter = object_map_.find(object_path);
245  Object* object;
246  if (oiter == object_map_.end()) {
247    object = object_map_[object_path] = new Object;
248    object->object_proxy = bus_->GetObjectProxy(service_name_, object_path);
249  } else
250    object = oiter->second;
251
252  Object::PropertiesMap::iterator piter =
253      object->properties_map.find(interface_name);
254  PropertySet* property_set;
255  const bool interface_added = (piter == object->properties_map.end());
256  if (interface_added) {
257    property_set = object->properties_map[interface_name] =
258        interface->CreateProperties(object->object_proxy,
259                                    object_path, interface_name);
260    property_set->ConnectSignals();
261  } else
262    property_set = piter->second;
263
264  property_set->UpdatePropertiesFromReader(reader);
265
266  if (interface_added)
267    interface->ObjectAdded(object_path, interface_name);
268}
269
270void ObjectManager::RemoveInterface(const ObjectPath& object_path,
271                                    const std::string& interface_name) {
272  ObjectMap::iterator oiter = object_map_.find(object_path);
273  if (oiter == object_map_.end())
274    return;
275  Object* object = oiter->second;
276
277  Object::PropertiesMap::iterator piter =
278      object->properties_map.find(interface_name);
279  if (piter == object->properties_map.end())
280    return;
281
282  // Inform the interface before removing the properties structure or object
283  // in case it needs details from them to make its own decisions.
284  InterfaceMap::iterator iiter = interface_map_.find(interface_name);
285  if (iiter != interface_map_.end()) {
286    Interface* interface = iiter->second;
287    interface->ObjectRemoved(object_path, interface_name);
288  }
289
290  object->properties_map.erase(piter);
291
292  if (object->properties_map.empty()) {
293    object_map_.erase(oiter);
294    delete object;
295  }
296}
297
298void ObjectManager::NameOwnerChanged(const std::string& old_owner,
299                                     const std::string& new_owner) {
300  if (!old_owner.empty()) {
301    ObjectMap::iterator iter = object_map_.begin();
302    while (iter != object_map_.end()) {
303      ObjectMap::iterator tmp = iter;
304      ++iter;
305
306      // PropertiesMap is mutated by RemoveInterface, and also Object is
307      // destroyed; easier to collect the object path and interface names
308      // and remove them safely.
309      const dbus::ObjectPath object_path = tmp->first;
310      Object* object = tmp->second;
311      std::vector<std::string> interfaces;
312
313      for (Object::PropertiesMap::iterator piter =
314              object->properties_map.begin();
315           piter != object->properties_map.end(); ++piter)
316        interfaces.push_back(piter->first);
317
318      for (std::vector<std::string>::iterator iiter = interfaces.begin();
319           iiter != interfaces.end(); ++iiter)
320        RemoveInterface(object_path, *iiter);
321    }
322
323  }
324
325  if (!new_owner.empty())
326    GetManagedObjects();
327}
328
329}  // namespace dbus
330