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"
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
) {
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
;
27 dbus::MessageReader
reader(response
);
28 error_name
= response
->GetErrorName();
29 reader
.PopString(&error_message
);
31 error_name
= kNoResponseError
;
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
);
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
);
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
);
82 DLOG(ERROR
) << "Unexpected type: " << value
.GetType();
86 DBusObjectMap::DBusObjectMap(const std::string
& service_name
,
90 service_name_(service_name
),
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
122 std::set
<dbus::ObjectPath
> object_path_set
;
123 std::set
<dbus::ObjectPath
>::iterator object_path_set_iter
=
124 object_path_set
.begin();
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
;
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())
156 dbus::ObjectProxy
* object_proxy
= bus_
->GetObjectProxy(service_name_
,
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
);
171 void DBusObjectMap::RemoveObject(const dbus::ObjectPath
& object_path
) {
174 ObjectMap::iterator iter
= object_map_
.find(object_path
);
175 if (iter
== object_map_
.end())
178 // Notify the delegate, so that it can perform any clean up that is
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
);
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
);
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())
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
;
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
;
242 bool ObjectProxyTree::CreateObjectMap(const dbus::ObjectPath
& object_path
,
243 const std::string
& service_name
,
244 DBusObjectMap::Delegate
* delegate
,
246 if (ContainsKey(paths_to_object_maps_
, object_path
)) {
247 LOG(ERROR
) << "Mapping already exists for object path: "
248 << object_path
.value();
251 paths_to_object_maps_
[object_path
] =
252 new DBusObjectMap(service_name
, delegate
, bus
);
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())
261 DBusObjectMap
* object_map
= iter
->second
;
262 paths_to_object_maps_
.erase(iter
);
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())
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
);
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
);
301 } // namespace nfc_client_helpers
302 } // namespace chromeos