Pepper: Fix crash on allocation failure.
[chromium-blink-merge.git] / chromeos / dbus / nfc_client_helpers.cc
blobb99502bc9ee4b76f2d49e7b1166239dc887de371
1 // Copyright 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.
5 #include "chromeos/dbus/nfc_client_helpers.h"
7 #include "base/stl_util.h"
8 #include "dbus/values_util.h"
10 namespace chromeos {
11 namespace nfc_client_helpers {
13 const char kNoResponseError[] = "org.chromium.Error.NoResponse";
14 const char kUnknownObjectError[] = "org.chromium.Error.UnknownObject";
16 void OnSuccess(const base::Closure& callback, dbus::Response* response) {
17 DCHECK(response);
18 callback.Run();
21 void OnError(const ErrorCallback& error_callback,
22 dbus::ErrorResponse* response) {
23 // Error response has optional error message argument.
24 std::string error_name;
25 std::string error_message;
26 if (response) {
27 dbus::MessageReader reader(response);
28 error_name = response->GetErrorName();
29 reader.PopString(&error_message);
30 } else {
31 error_name = kNoResponseError;
32 error_message = "";
34 error_callback.Run(error_name, error_message);
37 void AppendValueDataAsVariant(dbus::MessageWriter* writer,
38 const base::Value& value) {
39 switch (value.GetType()) {
40 case base::Value::TYPE_DICTIONARY: {
41 const base::DictionaryValue* dictionary = NULL;
42 value.GetAsDictionary(&dictionary);
43 dbus::MessageWriter variant_writer(NULL);
44 dbus::MessageWriter array_writer(NULL);
45 writer->OpenVariant("a{sv}", &variant_writer);
46 variant_writer.OpenArray("{sv}", &array_writer);
47 for (base::DictionaryValue::Iterator iter(*dictionary);
48 !iter.IsAtEnd(); iter.Advance()) {
49 dbus::MessageWriter entry_writer(NULL);
50 array_writer.OpenDictEntry(&entry_writer);
51 entry_writer.AppendString(iter.key());
52 AppendValueDataAsVariant(&entry_writer, iter.value());
53 array_writer.CloseContainer(&entry_writer);
55 variant_writer.CloseContainer(&array_writer);
56 writer->CloseContainer(&variant_writer);
57 break;
59 case base::Value::TYPE_LIST: {
60 const base::ListValue* list = NULL;
61 value.GetAsList(&list);
62 dbus::MessageWriter variant_writer(NULL);
63 dbus::MessageWriter array_writer(NULL);
64 writer->OpenVariant("av", &variant_writer);
65 variant_writer.OpenArray("v", &array_writer);
66 for (base::ListValue::const_iterator iter = list->begin();
67 iter != list->end(); ++iter) {
68 const base::Value* value = *iter;
69 AppendValueDataAsVariant(&array_writer, *value);
71 variant_writer.CloseContainer(&array_writer);
72 writer->CloseContainer(&variant_writer);
73 break;
75 case base::Value::TYPE_BOOLEAN:
76 case base::Value::TYPE_INTEGER:
77 case base::Value::TYPE_DOUBLE:
78 case base::Value::TYPE_STRING:
79 dbus::AppendBasicTypeValueDataAsVariant(writer, value);
80 break;
81 default:
82 DLOG(ERROR) << "Unexpected type: " << value.GetType();
86 DBusObjectMap::DBusObjectMap(const std::string& service_name,
87 Delegate* delegate,
88 dbus::Bus* bus)
89 : bus_(bus),
90 service_name_(service_name),
91 delegate_(delegate) {
92 DCHECK(bus_);
93 DCHECK(delegate_);
96 DBusObjectMap::~DBusObjectMap() {
97 // Clean up the Properties structures. We don't explicitly delete the object
98 // proxies, as they are owned by dbus::Bus.
99 for (ObjectMap::iterator iter = object_map_.begin();
100 iter != object_map_.end(); ++iter) {
101 const dbus::ObjectPath& object_path = iter->first;
102 ObjectPropertyPair pair = iter->second;
103 delegate_->ObjectRemoved(object_path);
104 CleanUpObjectPropertyPair(pair);
108 dbus::ObjectProxy* DBusObjectMap::GetObjectProxy(
109 const dbus::ObjectPath& object_path) {
110 return GetObjectPropertyPair(object_path).first;
113 NfcPropertySet* DBusObjectMap::GetObjectProperties(
114 const dbus::ObjectPath& object_path) {
115 return GetObjectPropertyPair(object_path).second;
118 void DBusObjectMap::UpdateObjects(const ObjectPathVector& object_paths) {
119 // This set is used to query if an object path was removed, while updating
120 // the removed paths below. The iterator is used as a hint to accelerate
121 // insertion.
122 std::set<dbus::ObjectPath> object_path_set;
123 std::set<dbus::ObjectPath>::iterator object_path_set_iter =
124 object_path_set.begin();
126 // Add all objects.
127 for (ObjectPathVector::const_iterator iter = object_paths.begin();
128 iter != object_paths.end(); ++iter) {
129 const dbus::ObjectPath &object_path = *iter;
130 AddObject(object_path);
131 // Neard usually returns object paths in ascending order. Give a hint here
132 // to make insertion amortized constant.
133 object_path_set_iter =
134 object_path_set.insert(object_path_set_iter, object_path);
137 // Remove all objects that are not in |object_paths|.
138 ObjectMap::const_iterator iter = object_map_.begin();
139 while (iter != object_map_.end()) {
140 // It is safe to use a const reference here, as DBusObjectMap::RemoveObject
141 // won't access it after the iterator becomes invalidated.
142 const dbus::ObjectPath &object_path = iter->first;
143 ++iter;
144 if (!ContainsKey(object_path_set, object_path))
145 RemoveObject(object_path);
149 bool DBusObjectMap::AddObject(const dbus::ObjectPath& object_path) {
150 ObjectMap::iterator iter = object_map_.find(object_path);
151 if (iter != object_map_.end())
152 return false;
154 DCHECK(bus_);
155 DCHECK(delegate_);
156 dbus::ObjectProxy* object_proxy = bus_->GetObjectProxy(service_name_,
157 object_path);
159 // Create the properties structure.
160 NfcPropertySet* properties = delegate_->CreateProperties(object_proxy);
161 properties->ConnectSignals();
162 properties->GetAll();
163 ObjectPropertyPair object = std::make_pair(object_proxy, properties);
164 object_map_[object_path] = object;
165 VLOG(1) << "Created proxy for object with Path: " << object_path.value()
166 << ", Service: " << service_name_;
167 delegate_->ObjectAdded(object_path);
168 return true;
171 void DBusObjectMap::RemoveObject(const dbus::ObjectPath& object_path) {
172 DCHECK(bus_);
173 DCHECK(delegate_);
174 ObjectMap::iterator iter = object_map_.find(object_path);
175 if (iter == object_map_.end())
176 return;
178 // Notify the delegate, so that it can perform any clean up that is
179 // necessary.
180 delegate_->ObjectRemoved(object_path);
182 // Clean up the object proxy and the properties structure.
183 ObjectPropertyPair pair = iter->second;
184 CleanUpObjectPropertyPair(pair);
185 object_map_.erase(iter);
186 VLOG(1) << "Object proxy removed for object path: "
187 << object_path.value();
190 void DBusObjectMap::RefreshProperties(const dbus::ObjectPath& object_path) {
191 NfcPropertySet* properties = GetObjectProperties(object_path);
192 if (properties)
193 properties->GetAll();
196 void DBusObjectMap::RefreshAllProperties() {
197 for (ObjectMap::const_iterator iter = object_map_.begin();
198 iter != object_map_.end(); ++iter) {
199 const dbus::ObjectPath& object_path = iter->first;
200 RefreshProperties(object_path);
204 ObjectPathVector DBusObjectMap::GetObjectPaths() {
205 std::vector<dbus::ObjectPath> object_paths;
206 for (ObjectMap::const_iterator iter = object_map_.begin();
207 iter != object_map_.end(); ++iter) {
208 const dbus::ObjectPath& object_path = iter->first;
209 object_paths.push_back(object_path);
211 return object_paths;
214 DBusObjectMap::ObjectPropertyPair DBusObjectMap::GetObjectPropertyPair(
215 const dbus::ObjectPath& object_path) {
216 ObjectMap::iterator iter = object_map_.find(object_path);
217 if (iter != object_map_.end())
218 return iter->second;
219 return std::make_pair(static_cast<dbus::ObjectProxy*>(NULL),
220 static_cast<NfcPropertySet*>(NULL));
223 void DBusObjectMap::CleanUpObjectPropertyPair(const ObjectPropertyPair& pair) {
224 // Don't remove the object proxy. There is a bug in dbus::Bus that causes a
225 // crash when object proxies are removed, due to the proxy objects not being
226 // properly reference counted. (See crbug.com/170182 and crbug.com/328264).
227 NfcPropertySet* properties = pair.second;
228 delete properties;
231 ObjectProxyTree::ObjectProxyTree() {
234 ObjectProxyTree::~ObjectProxyTree() {
235 for (PathsToObjectMapsType::iterator iter = paths_to_object_maps_.begin();
236 iter != paths_to_object_maps_.end(); ++iter) {
237 DBusObjectMap* object_map = iter->second;
238 delete object_map;
242 bool ObjectProxyTree::CreateObjectMap(const dbus::ObjectPath& object_path,
243 const std::string& service_name,
244 DBusObjectMap::Delegate* delegate,
245 dbus::Bus* bus) {
246 if (ContainsKey(paths_to_object_maps_, object_path)) {
247 LOG(ERROR) << "Mapping already exists for object path: "
248 << object_path.value();
249 return false;
251 paths_to_object_maps_[object_path] =
252 new DBusObjectMap(service_name, delegate, bus);
253 return true;
256 void ObjectProxyTree::RemoveObjectMap(const dbus::ObjectPath& object_path) {
257 PathsToObjectMapsType::iterator iter =
258 paths_to_object_maps_.find(object_path);
259 if (iter == paths_to_object_maps_.end())
260 return;
261 DBusObjectMap* object_map = iter->second;
262 paths_to_object_maps_.erase(iter);
263 delete object_map;
266 DBusObjectMap* ObjectProxyTree::GetObjectMap(
267 const dbus::ObjectPath& object_path) {
268 PathsToObjectMapsType::iterator iter =
269 paths_to_object_maps_.find(object_path);
270 if (iter == paths_to_object_maps_.end())
271 return NULL;
272 return iter->second;
275 dbus::ObjectProxy* ObjectProxyTree::FindObjectProxy(
276 const dbus::ObjectPath& object_proxy_path) {
277 for (PathsToObjectMapsType::iterator iter = paths_to_object_maps_.begin();
278 iter != paths_to_object_maps_.end(); ++iter) {
279 DBusObjectMap* object_map = iter->second;
280 dbus::ObjectProxy* object_proxy =
281 object_map->GetObjectProxy(object_proxy_path);
282 if (object_proxy)
283 return object_proxy;
285 return NULL;
288 NfcPropertySet* ObjectProxyTree::FindObjectProperties(
289 const dbus::ObjectPath& object_proxy_path) {
290 for (PathsToObjectMapsType::iterator iter = paths_to_object_maps_.begin();
291 iter != paths_to_object_maps_.end(); ++iter) {
292 DBusObjectMap* object_map = iter->second;
293 NfcPropertySet* properties =
294 object_map->GetObjectProperties(object_proxy_path);
295 if (properties)
296 return properties;
298 return NULL;
301 } // namespace nfc_client_helpers
302 } // namespace chromeos