blob: caf0c31f282569b8e6229b779ae854c42d46dfe2 [file] [log] [blame]
Christopher Wiley639477c2014-03-27 14:49:39 -07001// Copyright 2014 The Chromium OS 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 "buffet/exported_property_set.h"
6
7#include <base/bind.h>
8#include <dbus/property.h> // For kPropertyInterface
9
10#include "buffet/dbus_utils.h"
11
12namespace buffet {
13
14namespace dbus_utils {
15
16ExportedPropertySet::ExportedPropertySet(dbus::ExportedObject* exported_object)
17 : exported_object_(exported_object), weak_ptr_factory_(this) { }
18
19void ExportedPropertySet::ClaimPropertiesInterface() {
20 exported_object_->ExportMethodAndBlock(
21 dbus::kPropertiesInterface, dbus::kPropertiesGetAll,
22 base::Bind(&ExportedPropertySet::HandleGetAll,
23 weak_ptr_factory_.GetWeakPtr()));
24 exported_object_->ExportMethodAndBlock(
25 dbus::kPropertiesInterface, dbus::kPropertiesGet,
26 base::Bind(&ExportedPropertySet::HandleGet,
27 weak_ptr_factory_.GetWeakPtr()));
28 exported_object_->ExportMethodAndBlock(
29 dbus::kPropertiesInterface, dbus::kPropertiesSet,
30 base::Bind(&ExportedPropertySet::HandleSet,
31 weak_ptr_factory_.GetWeakPtr()));
32}
33
34ExportedPropertySet::~ExportedPropertySet() { }
35
36void ExportedPropertySet::RegisterProperty(
37 const std::string& interface_name,
38 const std::string& property_name,
39 ExportedPropertyBase* exported_property) {
40 properties_[interface_name][property_name] = exported_property;
41 // Technically, the property set exists longer than the properties themselves,
42 // so we could use Unretained here rather than a weak pointer.
43 ExportedPropertyBase::OnUpdateCallback cb = base::Bind(
44 &ExportedPropertySet::HandlePropertyUpdated,
45 weak_ptr_factory_.GetWeakPtr(),
46 interface_name, property_name);
47 exported_property->SetUpdateCallback(cb);
48}
49
50void ExportedPropertySet::HandleGetAll(
51 dbus::MethodCall* method_call,
52 dbus::ExportedObject::ResponseSender response_sender) {
53 dbus::MessageReader reader(method_call);
54 std::string interface_name;
55 if (!reader.PopString(&interface_name)) {
56 response_sender.Run(
57 GetBadArgsError(method_call, "No interface name specified."));
58 return;
59 }
60 if (reader.HasMoreData()) {
61 response_sender.Run(
62 GetBadArgsError(method_call, "Too many arguments to GetAll."));
63 return;
64 }
65 auto property_map_itr = properties_.find(interface_name);
66 if (property_map_itr == properties_.end()) {
67 response_sender.Run(
68 GetBadArgsError(method_call, "No such interface on object."));
69 return;
70 }
71 scoped_ptr<dbus::Response> response(
72 dbus::Response::FromMethodCall(method_call));
73 dbus::MessageWriter resp_writer(response.get());
74 dbus::MessageWriter dict_writer(nullptr);
75 resp_writer.OpenArray("{sv}", &dict_writer);
76 for (const auto& kv : property_map_itr->second) {
77 dbus::MessageWriter entry_writer(nullptr);
78 dict_writer.OpenDictEntry(&entry_writer);
79 entry_writer.AppendString(kv.first);
80 kv.second->AppendValueToWriter(&entry_writer);
81 dict_writer.CloseContainer(&entry_writer);
82 }
83 resp_writer.CloseContainer(&dict_writer);
84 response_sender.Run(response.Pass());
85}
86
87void ExportedPropertySet::HandleGet(
88 dbus::MethodCall* method_call,
89 dbus::ExportedObject::ResponseSender response_sender) {
90 dbus::MessageReader reader(method_call);
91 std::string interface_name, property_name;
92 if (!reader.PopString(&interface_name)) {
93 response_sender.Run(
94 GetBadArgsError(method_call, "No interface name specified."));
95 return;
96 }
97 if (!reader.PopString(&property_name)) {
98 response_sender.Run(
99 GetBadArgsError(method_call, "No property name specified."));
100 return;
101 }
102 if (reader.HasMoreData()) {
103 response_sender.Run(
104 GetBadArgsError(method_call, "Too many arguments to Get."));
105 return;
106 }
107 auto property_map_itr = properties_.find(interface_name);
108 if (property_map_itr == properties_.end()) {
109 response_sender.Run(
110 GetBadArgsError(method_call, "No such interface on object."));
111 return;
112 }
113 LOG(ERROR) << "Looking for " << property_name << " on " << interface_name;
114 auto property_itr = property_map_itr->second.find(property_name);
115 if (property_itr == property_map_itr->second.end()) {
116 response_sender.Run(
117 GetBadArgsError(method_call, "No such property on interface."));
118 return;
119 }
120 scoped_ptr<dbus::Response> response(
121 dbus::Response::FromMethodCall(method_call));
122 dbus::MessageWriter resp_writer(response.get());
123 property_itr->second->AppendValueToWriter(&resp_writer);
124 response_sender.Run(response.Pass());
125}
126
127void ExportedPropertySet::HandleSet(
128 dbus::MethodCall* method_call,
129 dbus::ExportedObject::ResponseSender response_sender) {
130 scoped_ptr<dbus::ErrorResponse> error_resp(
131 dbus::ErrorResponse::FromMethodCall(
132 method_call, "org.freedesktop.DBus.Error.NotSupported", ""));
133 scoped_ptr<dbus::Response> response(error_resp.release());
134 response_sender.Run(response.Pass());
135}
136
137void ExportedPropertySet::HandlePropertyUpdated(
138 const std::string& interface,
139 const std::string& name,
140 const ExportedPropertyBase* property) {
Christopher Wiley0ffe3b02014-04-01 17:33:29 -0700141 dbus::Signal signal(dbus::kPropertiesInterface, dbus::kPropertiesChanged);
142 WriteSignalForPropertyUpdate(interface, name, property, &signal);
143 // This sends the signal asyncronously. However, the raw message inside
144 // the signal object is ref-counted, so we're fine to allocate the Signal
145 // object on our local stack.
146 exported_object_->SendSignal(&signal);
147}
148
149void ExportedPropertySet::WriteSignalForPropertyUpdate(
150 const std::string& interface,
151 const std::string& name,
152 const ExportedPropertyBase* property,
153 dbus::Signal* signal) const {
154 dbus::MessageWriter writer(signal);
155 dbus::MessageWriter array_writer(nullptr);
156 dbus::MessageWriter dict_writer(nullptr);
157 writer.AppendString(interface);
158 writer.OpenArray("{sv}", &array_writer);
159 array_writer.OpenDictEntry(&dict_writer);
160 dict_writer.AppendString(name);
161 property->AppendValueToWriter(&dict_writer);
162 array_writer.CloseContainer(&dict_writer);
163 writer.CloseContainer(&array_writer);
164 // The interface specification tells us to include this list of properties
165 // which have changed, but for whom no value is conveyed. Currently, we
166 // don't do anything interesting here.
167 std::vector<std::string> invalidated_properties;
168 writer.AppendArrayOfStrings(invalidated_properties);
Christopher Wiley639477c2014-03-27 14:49:39 -0700169}
170
171template <typename T>
172void AppendPropertyToWriter(dbus::MessageWriter* writer, const T& value);
173
174template <>
175void AppendPropertyToWriter(dbus::MessageWriter* writer, const bool& value) {
176 writer->AppendVariantOfBool(value);
177}
178
179template <>
180void AppendPropertyToWriter(dbus::MessageWriter* writer, const uint8& value) {
181 writer->AppendVariantOfByte(value);
182}
183
184template <>
185void AppendPropertyToWriter(dbus::MessageWriter* writer, const int16& value) {
186 writer->AppendVariantOfInt16(value);
187}
188
189template <>
190void AppendPropertyToWriter(dbus::MessageWriter* writer, const uint16& value) {
191 writer->AppendVariantOfUint16(value);
192}
193
194template <>
195void AppendPropertyToWriter(dbus::MessageWriter* writer, const int32& value) {
196 writer->AppendVariantOfInt32(value);
197}
198
199template <>
200void AppendPropertyToWriter(dbus::MessageWriter* writer, const uint32& value) {
201 writer->AppendVariantOfUint32(value);
202}
203
204template <>
205void AppendPropertyToWriter(dbus::MessageWriter* writer, const int64& value) {
206 writer->AppendVariantOfInt64(value);
207}
208
209template <>
210void AppendPropertyToWriter(dbus::MessageWriter* writer, const uint64& value) {
211 writer->AppendVariantOfUint64(value);
212}
213
214template <>
215void AppendPropertyToWriter(dbus::MessageWriter* writer, const double& value) {
216 writer->AppendVariantOfDouble(value);
217}
218
219template <>
220void AppendPropertyToWriter(
221 dbus::MessageWriter* writer, const std::string& value) {
222 writer->AppendVariantOfString(value);
223}
224
225template <>
226void AppendPropertyToWriter(
227 dbus::MessageWriter* writer, const dbus::ObjectPath& value) {
228 writer->AppendVariantOfObjectPath(value);
229}
230
231template <>
232void AppendPropertyToWriter(
233 dbus::MessageWriter* writer, const std::vector<std::string>& value) {
234 dbus::MessageWriter variant_writer(nullptr);
235 writer->OpenVariant("as", &variant_writer);
236 variant_writer.AppendArrayOfStrings(value);
237 writer->CloseContainer(&variant_writer);
238}
239
240template <>
241void AppendPropertyToWriter(
242 dbus::MessageWriter* writer, const std::vector<dbus::ObjectPath>& value) {
243 dbus::MessageWriter variant_writer(nullptr);
244 writer->OpenVariant("ao", &variant_writer);
245 variant_writer.AppendArrayOfObjectPaths(value);
246 writer->CloseContainer(&variant_writer);
247}
248
249template <>
250void AppendPropertyToWriter(
251 dbus::MessageWriter* writer, const std::vector<uint8>& value) {
252 dbus::MessageWriter variant_writer(nullptr);
253 writer->OpenVariant("ay", &variant_writer);
254 variant_writer.AppendArrayOfBytes(value.data(), value.size());
255 writer->CloseContainer(&variant_writer);
256}
257
258template <typename T>
259ExportedProperty<T>::ExportedProperty() {}
260
261template <typename T>
262ExportedProperty<T>::~ExportedProperty() {}
263
264template <typename T>
265const T& ExportedProperty<T>::value() const { return value_; }
266
267template <typename T>
268void ExportedProperty<T>::SetValue(const T& new_value) {
269 if (value_ == new_value) {
270 return;
271 }
272 value_ = new_value;
273 // These is a brief period after the construction of an ExportedProperty
274 // when this callback is not initialized because the property has not
275 // been registered with the parent ExportedPropertySet. During this period
276 // users should be initializing values via SetValue, and no notifications
277 // should be triggered by the ExportedPropertySet.
278 if (!on_update_.is_null()) {
279 on_update_.Run(this);
280 }
281}
282
283template <typename T>
284void ExportedProperty<T>::SetUpdateCallback(const OnUpdateCallback& cb) {
285 on_update_ = cb;
286}
287
288template <typename T>
Christopher Wiley0ffe3b02014-04-01 17:33:29 -0700289void ExportedProperty<T>::AppendValueToWriter(
290 dbus::MessageWriter* writer) const {
Christopher Wiley639477c2014-03-27 14:49:39 -0700291 AppendPropertyToWriter(writer, value_);
292}
293
294template class ExportedProperty<bool>;
295template class ExportedProperty<uint8>;
296template class ExportedProperty<int16>;
297template class ExportedProperty<uint16>;
298template class ExportedProperty<int32>;
299template class ExportedProperty<uint32>;
300template class ExportedProperty<int64>;
301template class ExportedProperty<uint64>;
302template class ExportedProperty<double>;
303template class ExportedProperty<std::string>;
304template class ExportedProperty<dbus::ObjectPath>;
305template class ExportedProperty<std::vector<std::string>>;
306template class ExportedProperty<std::vector<dbus::ObjectPath>>;
307template class ExportedProperty<std::vector<uint8>>;
308
309} // namespace dbus_utils
310
311} // namespace buffet