1 // Copyright 2016 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 "device/bluetooth/dbus/bluetooth_gatt_descriptor_service_provider_impl.h"
6
7 #include <cstddef>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/logging.h"
12 #include "base/strings/string_util.h"
13 #include "device/bluetooth/dbus/bluetooth_gatt_attribute_helpers.h"
14 #include "third_party/cros_system_api/dbus/service_constants.h"
15
16 namespace bluez {
17
18 namespace {
19
20 const char kErrorInvalidArgs[] = "org.freedesktop.DBus.Error.InvalidArgs";
21 const char kErrorPropertyReadOnly[] =
22 "org.freedesktop.DBus.Error.PropertyReadOnly";
23 const char kErrorFailed[] = "org.freedesktop.DBus.Error.Failed";
24
25 } // namespace
26
27 // The BluetoothGattDescriptorServiceProvider implementation used in production.
28 BluetoothGattDescriptorServiceProviderImpl::
BluetoothGattDescriptorServiceProviderImpl(dbus::Bus * bus,const dbus::ObjectPath & object_path,std::unique_ptr<BluetoothGattAttributeValueDelegate> delegate,const std::string & uuid,const std::vector<std::string> & flags,const dbus::ObjectPath & characteristic_path)29 BluetoothGattDescriptorServiceProviderImpl(
30 dbus::Bus* bus,
31 const dbus::ObjectPath& object_path,
32 std::unique_ptr<BluetoothGattAttributeValueDelegate> delegate,
33 const std::string& uuid,
34 const std::vector<std::string>& flags,
35 const dbus::ObjectPath& characteristic_path)
36 : origin_thread_id_(base::PlatformThread::CurrentId()),
37 uuid_(uuid),
38 flags_(flags),
39 bus_(bus),
40 delegate_(std::move(delegate)),
41 object_path_(object_path),
42 characteristic_path_(characteristic_path) {
43 DVLOG(1) << "Created Bluetooth GATT characteristic descriptor: "
44 << object_path.value() << " UUID: " << uuid;
45 if (!bus_)
46 return;
47
48 DCHECK(delegate_);
49 DCHECK(!uuid_.empty());
50 DCHECK(object_path_.IsValid());
51 DCHECK(characteristic_path_.IsValid());
52 DCHECK(base::StartsWith(object_path_.value(),
53 characteristic_path_.value() + "/",
54 base::CompareCase::SENSITIVE));
55
56 exported_object_ = bus_->GetExportedObject(object_path_);
57
58 exported_object_->ExportMethod(
59 dbus::kDBusPropertiesInterface, dbus::kDBusPropertiesGet,
60 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::Get,
61 weak_ptr_factory_.GetWeakPtr()),
62 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
63 weak_ptr_factory_.GetWeakPtr()));
64
65 exported_object_->ExportMethod(
66 dbus::kDBusPropertiesInterface, dbus::kDBusPropertiesSet,
67 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::Set,
68 weak_ptr_factory_.GetWeakPtr()),
69 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
70 weak_ptr_factory_.GetWeakPtr()));
71
72 exported_object_->ExportMethod(
73 dbus::kDBusPropertiesInterface, dbus::kDBusPropertiesGetAll,
74 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::GetAll,
75 weak_ptr_factory_.GetWeakPtr()),
76 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
77 weak_ptr_factory_.GetWeakPtr()));
78
79 // org.bluez.GattDescriptor1 interface:
80 exported_object_->ExportMethod(
81 bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface,
82 bluetooth_gatt_descriptor::kReadValue,
83 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::ReadValue,
84 weak_ptr_factory_.GetWeakPtr()),
85 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
86 weak_ptr_factory_.GetWeakPtr()));
87 exported_object_->ExportMethod(
88 bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface,
89 bluetooth_gatt_descriptor::kWriteValue,
90 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::WriteValue,
91 weak_ptr_factory_.GetWeakPtr()),
92 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
93 weak_ptr_factory_.GetWeakPtr()));
94 }
95
96 BluetoothGattDescriptorServiceProviderImpl::
~BluetoothGattDescriptorServiceProviderImpl()97 ~BluetoothGattDescriptorServiceProviderImpl() {
98 DVLOG(1) << "Cleaning up Bluetooth GATT characteristic descriptor: "
99 << object_path_.value();
100 if (bus_)
101 bus_->UnregisterExportedObject(object_path_);
102 }
103
SendValueChanged(const std::vector<uint8_t> & value)104 void BluetoothGattDescriptorServiceProviderImpl::SendValueChanged(
105 const std::vector<uint8_t>& value) {
106 DVLOG(2) << "Emitting a PropertiesChanged signal for descriptor value.";
107 dbus::Signal signal(dbus::kDBusPropertiesInterface,
108 dbus::kDBusPropertiesChangedSignal);
109 dbus::MessageWriter writer(&signal);
110 dbus::MessageWriter array_writer(NULL);
111 dbus::MessageWriter dict_entry_writer(NULL);
112 dbus::MessageWriter variant_writer(NULL);
113
114 // interface_name
115 writer.AppendString(
116 bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface);
117
118 // changed_properties
119 writer.OpenArray("{sv}", &array_writer);
120 array_writer.OpenDictEntry(&dict_entry_writer);
121 dict_entry_writer.AppendString(bluetooth_gatt_descriptor::kValueProperty);
122 dict_entry_writer.OpenVariant("ay", &variant_writer);
123 variant_writer.AppendArrayOfBytes(value.data(), value.size());
124 dict_entry_writer.CloseContainer(&variant_writer);
125 array_writer.CloseContainer(&dict_entry_writer);
126 writer.CloseContainer(&array_writer);
127
128 // invalidated_properties.
129 writer.OpenArray("s", &array_writer);
130 writer.CloseContainer(&array_writer);
131
132 exported_object_->SendSignal(&signal);
133 }
134
OnOriginThread()135 bool BluetoothGattDescriptorServiceProviderImpl::OnOriginThread() {
136 return base::PlatformThread::CurrentId() == origin_thread_id_;
137 }
138
Get(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)139 void BluetoothGattDescriptorServiceProviderImpl::Get(
140 dbus::MethodCall* method_call,
141 dbus::ExportedObject::ResponseSender response_sender) {
142 DVLOG(2) << "BluetoothGattDescriptorServiceProvider::Get: "
143 << object_path_.value();
144 DCHECK(OnOriginThread());
145
146 dbus::MessageReader reader(method_call);
147
148 std::string interface_name;
149 std::string property_name;
150 if (!reader.PopString(&interface_name) || !reader.PopString(&property_name) ||
151 reader.HasMoreData()) {
152 std::unique_ptr<dbus::ErrorResponse> error_response =
153 dbus::ErrorResponse::FromMethodCall(method_call, kErrorInvalidArgs,
154 "Expected 'ss'.");
155 std::move(response_sender).Run(std::move(error_response));
156 return;
157 }
158
159 // Only the GATT descriptor interface is supported.
160 if (interface_name !=
161 bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface) {
162 std::unique_ptr<dbus::ErrorResponse> error_response =
163 dbus::ErrorResponse::FromMethodCall(
164 method_call, kErrorInvalidArgs,
165 "No such interface: '" + interface_name + "'.");
166 std::move(response_sender).Run(std::move(error_response));
167 return;
168 }
169
170 std::unique_ptr<dbus::Response> response =
171 dbus::Response::FromMethodCall(method_call);
172 dbus::MessageWriter writer(response.get());
173 dbus::MessageWriter variant_writer(NULL);
174
175 if (property_name == bluetooth_gatt_descriptor::kUUIDProperty) {
176 writer.OpenVariant("s", &variant_writer);
177 variant_writer.AppendString(uuid_);
178 writer.CloseContainer(&variant_writer);
179 } else if (property_name ==
180 bluetooth_gatt_descriptor::kCharacteristicProperty) {
181 writer.OpenVariant("o", &variant_writer);
182 variant_writer.AppendObjectPath(characteristic_path_);
183 writer.CloseContainer(&variant_writer);
184 } else if (property_name == bluetooth_gatt_descriptor::kFlagsProperty) {
185 writer.OpenVariant("as", &variant_writer);
186 variant_writer.AppendArrayOfStrings(flags_);
187 writer.CloseContainer(&variant_writer);
188 } else {
189 response = dbus::ErrorResponse::FromMethodCall(
190 method_call, kErrorInvalidArgs,
191 "No such property: '" + property_name + "'.");
192 }
193
194 std::move(response_sender).Run(std::move(response));
195 }
196
Set(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)197 void BluetoothGattDescriptorServiceProviderImpl::Set(
198 dbus::MethodCall* method_call,
199 dbus::ExportedObject::ResponseSender response_sender) {
200 DVLOG(2) << "BluetoothGattDescriptorServiceProviderImpl::Set: "
201 << object_path_.value();
202 DCHECK(OnOriginThread());
203 // All of the properties on this interface are read-only, so just return
204 // error.
205 std::unique_ptr<dbus::ErrorResponse> error_response =
206 dbus::ErrorResponse::FromMethodCall(method_call, kErrorPropertyReadOnly,
207 "All properties are read-only.");
208 std::move(response_sender).Run(std::move(error_response));
209 }
210
GetAll(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)211 void BluetoothGattDescriptorServiceProviderImpl::GetAll(
212 dbus::MethodCall* method_call,
213 dbus::ExportedObject::ResponseSender response_sender) {
214 DVLOG(2) << "BluetoothGattDescriptorServiceProvider::GetAll: "
215 << object_path_.value();
216 DCHECK(OnOriginThread());
217
218 dbus::MessageReader reader(method_call);
219
220 std::string interface_name;
221 if (!reader.PopString(&interface_name) || reader.HasMoreData()) {
222 std::unique_ptr<dbus::ErrorResponse> error_response =
223 dbus::ErrorResponse::FromMethodCall(method_call, kErrorInvalidArgs,
224 "Expected 's'.");
225 std::move(response_sender).Run(std::move(error_response));
226 return;
227 }
228
229 // Only the GATT descriptor interface is supported.
230 if (interface_name !=
231 bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface) {
232 std::unique_ptr<dbus::ErrorResponse> error_response =
233 dbus::ErrorResponse::FromMethodCall(
234 method_call, kErrorInvalidArgs,
235 "No such interface: '" + interface_name + "'.");
236 std::move(response_sender).Run(std::move(error_response));
237 return;
238 }
239
240 std::unique_ptr<dbus::Response> response =
241 dbus::Response::FromMethodCall(method_call);
242 dbus::MessageWriter writer(response.get());
243 WriteProperties(&writer);
244 std::move(response_sender).Run(std::move(response));
245 }
246
ReadValue(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)247 void BluetoothGattDescriptorServiceProviderImpl::ReadValue(
248 dbus::MethodCall* method_call,
249 dbus::ExportedObject::ResponseSender response_sender) {
250 DVLOG(3) << "BluetoothGattDescriptorServiceProvider::ReadValue: "
251 << object_path_.value();
252 DCHECK(OnOriginThread());
253
254 dbus::MessageReader reader(method_call);
255 std::map<std::string, dbus::MessageReader> options;
256 dbus::ObjectPath device_path;
257 ReadOptions(&reader, &options);
258 auto it = options.find(bluetooth_gatt_descriptor::kOptionDevice);
259 if (it != options.end())
260 it->second.PopObjectPath(&device_path);
261
262 if (device_path.value().empty()) {
263 LOG(WARNING) << "ReadValue called with incorrect parameters: "
264 << method_call->ToString();
265 // Continue on with an empty device path. This will return a null device to
266 // the delegate, which should know how to handle it.
267 }
268
269 // GetValue() promises to only call either the success or error callback.
270 auto response_sender_adapted =
271 base::AdaptCallbackForRepeating(std::move(response_sender));
272
273 DCHECK(delegate_);
274 delegate_->GetValue(
275 device_path,
276 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnReadValue,
277 weak_ptr_factory_.GetWeakPtr(), method_call,
278 response_sender_adapted),
279 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnFailure,
280 weak_ptr_factory_.GetWeakPtr(), method_call,
281 response_sender_adapted));
282 }
283
WriteValue(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)284 void BluetoothGattDescriptorServiceProviderImpl::WriteValue(
285 dbus::MethodCall* method_call,
286 dbus::ExportedObject::ResponseSender response_sender) {
287 DVLOG(3) << "BluetoothGattDescriptorServiceProvider::WriteValue: "
288 << object_path_.value();
289 DCHECK(OnOriginThread());
290
291 dbus::MessageReader reader(method_call);
292 const uint8_t* bytes = NULL;
293 size_t length = 0;
294
295 std::vector<uint8_t> value;
296 if (!reader.PopArrayOfBytes(&bytes, &length)) {
297 LOG(WARNING) << "Error reading value parameter. WriteValue called with "
298 "incorrect parameters: "
299 << method_call->ToString();
300 }
301 if (bytes)
302 value.assign(bytes, bytes + length);
303
304 std::map<std::string, dbus::MessageReader> options;
305 dbus::ObjectPath device_path;
306 ReadOptions(&reader, &options);
307 auto it = options.find(bluetooth_gatt_descriptor::kOptionDevice);
308 if (it != options.end())
309 it->second.PopObjectPath(&device_path);
310
311 if (device_path.value().empty()) {
312 LOG(WARNING) << "WriteValue called with incorrect parameters: "
313 << method_call->ToString();
314 // Continue on with an empty device path. This will return a null device to
315 // the delegate, which should know how to handle it.
316 }
317
318 // SetValue() promises to only call either the success or error callback.
319 auto response_sender_adapted =
320 base::AdaptCallbackForRepeating(std::move(response_sender));
321
322 DCHECK(delegate_);
323 delegate_->SetValue(
324 device_path, value,
325 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnWriteValue,
326 weak_ptr_factory_.GetWeakPtr(), method_call,
327 response_sender_adapted),
328 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnFailure,
329 weak_ptr_factory_.GetWeakPtr(), method_call,
330 response_sender_adapted));
331 }
332
OnExported(const std::string & interface_name,const std::string & method_name,bool success)333 void BluetoothGattDescriptorServiceProviderImpl::OnExported(
334 const std::string& interface_name,
335 const std::string& method_name,
336 bool success) {
337 DVLOG_IF(1, !success) << "Failed to export " << interface_name << "."
338 << method_name;
339 }
340
OnReadValue(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender,const std::vector<uint8_t> & value)341 void BluetoothGattDescriptorServiceProviderImpl::OnReadValue(
342 dbus::MethodCall* method_call,
343 dbus::ExportedObject::ResponseSender response_sender,
344 const std::vector<uint8_t>& value) {
345 DVLOG(3) << "Descriptor value obtained from delegate. Responding to "
346 "ReadValue.";
347
348 std::unique_ptr<dbus::Response> response =
349 dbus::Response::FromMethodCall(method_call);
350 dbus::MessageWriter writer(response.get());
351 writer.AppendArrayOfBytes(value.data(), value.size());
352 std::move(response_sender).Run(std::move(response));
353 }
354
OnWriteValue(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)355 void BluetoothGattDescriptorServiceProviderImpl::OnWriteValue(
356 dbus::MethodCall* method_call,
357 dbus::ExportedObject::ResponseSender response_sender) {
358 DVLOG(3) << "Responding to WriteValue.";
359
360 std::unique_ptr<dbus::Response> response =
361 dbus::Response::FromMethodCall(method_call);
362 std::move(response_sender).Run(std::move(response));
363 }
364
WriteProperties(dbus::MessageWriter * writer)365 void BluetoothGattDescriptorServiceProviderImpl::WriteProperties(
366 dbus::MessageWriter* writer) {
367 dbus::MessageWriter array_writer(NULL);
368 dbus::MessageWriter dict_entry_writer(NULL);
369 dbus::MessageWriter variant_writer(NULL);
370
371 writer->OpenArray("{sv}", &array_writer);
372
373 // UUID:
374 array_writer.OpenDictEntry(&dict_entry_writer);
375 dict_entry_writer.AppendString(bluetooth_gatt_descriptor::kUUIDProperty);
376 dict_entry_writer.AppendVariantOfString(uuid_);
377 array_writer.CloseContainer(&dict_entry_writer);
378
379 // Characteristic:
380 array_writer.OpenDictEntry(&dict_entry_writer);
381 dict_entry_writer.AppendString(
382 bluetooth_gatt_descriptor::kCharacteristicProperty);
383 dict_entry_writer.AppendVariantOfObjectPath(characteristic_path_);
384 array_writer.CloseContainer(&dict_entry_writer);
385
386 // Flags:
387 array_writer.OpenDictEntry(&dict_entry_writer);
388 dict_entry_writer.AppendString(bluetooth_gatt_descriptor::kFlagsProperty);
389 dict_entry_writer.OpenVariant("as", &variant_writer);
390 variant_writer.AppendArrayOfStrings(flags_);
391 dict_entry_writer.CloseContainer(&variant_writer);
392 array_writer.CloseContainer(&dict_entry_writer);
393
394 writer->CloseContainer(&array_writer);
395 }
396
OnFailure(dbus::MethodCall * method_call,dbus::ExportedObject::ResponseSender response_sender)397 void BluetoothGattDescriptorServiceProviderImpl::OnFailure(
398 dbus::MethodCall* method_call,
399 dbus::ExportedObject::ResponseSender response_sender) {
400 DVLOG(2) << "Failed to get/set descriptor value. Report error.";
401 std::unique_ptr<dbus::ErrorResponse> error_response =
402 dbus::ErrorResponse::FromMethodCall(
403 method_call, kErrorFailed, "Failed to get/set descriptor value.");
404 std::move(response_sender).Run(std::move(error_response));
405 }
406
407 const dbus::ObjectPath&
object_path() const408 BluetoothGattDescriptorServiceProviderImpl::object_path() const {
409 return object_path_;
410 }
411
412 } // namespace bluez
413