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