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