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
14 namespace dbus {
15
Object()16 ObjectManager::Object::Object()
17 : object_proxy(NULL) {
18 }
19
~Object()20 ObjectManager::Object::~Object() {
21 }
22
ObjectManager(Bus * bus,const std::string & service_name,const ObjectPath & object_path)23 ObjectManager::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
~ObjectManager()58 ObjectManager::~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
RegisterInterface(const std::string & interface_name,Interface * interface)74 void ObjectManager::RegisterInterface(const std::string& interface_name,
75 Interface* interface) {
76 interface_map_[interface_name] = interface;
77 }
78
UnregisterInterface(const std::string & interface_name)79 void 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
GetObjects()85 std::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
GetObjectsWithInterface(const std::string & interface_name)95 std::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
GetObjectProxy(const ObjectPath & object_path)112 ObjectProxy* 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
GetProperties(const ObjectPath & object_path,const std::string & interface_name)121 PropertySet* 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
GetManagedObjects()136 void 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
OnGetManagedObjects(Response * response)147 void 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
InterfacesAddedReceived(Signal * signal)170 void 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
InterfacesAddedConnected(const std::string & interface_name,const std::string & signal_name,bool success)184 void 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
InterfacesRemovedReceived(Signal * signal)191 void 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
InterfacesRemovedConnected(const std::string & interface_name,const std::string & signal_name,bool success)208 void 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
UpdateObject(const ObjectPath & object_path,MessageReader * reader)217 void 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
AddInterface(const ObjectPath & object_path,const std::string & interface_name,MessageReader * reader)236 void 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
RemoveInterface(const ObjectPath & object_path,const std::string & interface_name)270 void 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
NameOwnerChanged(const std::string & old_owner,const std::string & new_owner)298 void 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