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