1// Copyright 2014 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 "chromeos/dbus/bluetooth_gatt_descriptor_service_provider.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/memory/weak_ptr.h"
10#include "base/strings/string_util.h"
11#include "base/threading/platform_thread.h"
12#include "chromeos/dbus/dbus_thread_manager.h"
13#include "chromeos/dbus/fake_bluetooth_gatt_descriptor_service_provider.h"
14#include "dbus/exported_object.h"
15#include "dbus/message.h"
16#include "third_party/cros_system_api/dbus/service_constants.h"
17
18namespace chromeos {
19namespace {
20const char kErrorInvalidArgs[] =
21    "org.freedesktop.DBus.Error.InvalidArgs";
22const char kErrorPropertyReadOnly[] =
23    "org.freedesktop.DBus.Error.PropertyReadOnly";
24const char kErrorFailed[] =
25    "org.freedesktop.DBus.Error.Failed";
26}  // namespace
27
28// The BluetoothGattDescriptorServiceProvider implementation used in production.
29class BluetoothGattDescriptorServiceProviderImpl
30    : public BluetoothGattDescriptorServiceProvider {
31 public:
32  BluetoothGattDescriptorServiceProviderImpl(
33      dbus::Bus* bus,
34      const dbus::ObjectPath& object_path,
35      Delegate* delegate,
36      const std::string& uuid,
37      const std::vector<std::string>& permissions,
38      const dbus::ObjectPath& characteristic_path)
39      : origin_thread_id_(base::PlatformThread::CurrentId()),
40        uuid_(uuid),
41        bus_(bus),
42        delegate_(delegate),
43        object_path_(object_path),
44        characteristic_path_(characteristic_path),
45        weak_ptr_factory_(this) {
46    VLOG(1) << "Created Bluetooth GATT characteristic descriptor: "
47            << object_path.value() << " UUID: " << uuid;
48    DCHECK(bus_);
49    DCHECK(delegate_);
50    DCHECK(!uuid_.empty());
51    DCHECK(object_path_.IsValid());
52    DCHECK(characteristic_path_.IsValid());
53    DCHECK(StartsWithASCII(
54        object_path_.value(), characteristic_path_.value() + "/", true));
55
56    exported_object_ = bus_->GetExportedObject(object_path_);
57
58    exported_object_->ExportMethod(
59        dbus::kDBusPropertiesInterface,
60        dbus::kDBusPropertiesGet,
61        base::Bind(&BluetoothGattDescriptorServiceProviderImpl::Get,
62                   weak_ptr_factory_.GetWeakPtr()),
63        base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
64                   weak_ptr_factory_.GetWeakPtr()));
65
66    exported_object_->ExportMethod(
67        dbus::kDBusPropertiesInterface,
68        dbus::kDBusPropertiesSet,
69        base::Bind(&BluetoothGattDescriptorServiceProviderImpl::Set,
70                   weak_ptr_factory_.GetWeakPtr()),
71        base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
72                   weak_ptr_factory_.GetWeakPtr()));
73
74    exported_object_->ExportMethod(
75        dbus::kDBusPropertiesInterface,
76        dbus::kDBusPropertiesGetAll,
77        base::Bind(&BluetoothGattDescriptorServiceProviderImpl::GetAll,
78                   weak_ptr_factory_.GetWeakPtr()),
79        base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
80                   weak_ptr_factory_.GetWeakPtr()));
81  }
82
83  virtual ~BluetoothGattDescriptorServiceProviderImpl() {
84    VLOG(1) << "Cleaning up Bluetooth GATT characteristic descriptor: "
85            << object_path_.value();
86    bus_->UnregisterExportedObject(object_path_);
87  }
88
89  // BluetoothGattDescriptorServiceProvider override.
90  virtual void SendValueChanged(const std::vector<uint8>& value) OVERRIDE {
91    VLOG(2) << "Emitting a PropertiesChanged signal for descriptor value.";
92    dbus::Signal signal(
93        dbus::kDBusPropertiesInterface,
94        dbus::kDBusPropertiesChangedSignal);
95    dbus::MessageWriter writer(&signal);
96    dbus::MessageWriter array_writer(NULL);
97    dbus::MessageWriter dict_entry_writer(NULL);
98    dbus::MessageWriter variant_writer(NULL);
99
100    // interface_name
101    writer.AppendString(
102        bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface);
103
104    // changed_properties
105    writer.OpenArray("{sv}", &array_writer);
106    array_writer.OpenDictEntry(&dict_entry_writer);
107    dict_entry_writer.AppendString(bluetooth_gatt_descriptor::kValueProperty);
108    dict_entry_writer.OpenVariant("ay", &variant_writer);
109    variant_writer.AppendArrayOfBytes(value.data(), value.size());
110    dict_entry_writer.CloseContainer(&variant_writer);
111    array_writer.CloseContainer(&dict_entry_writer);
112    writer.CloseContainer(&array_writer);
113
114    // invalidated_properties.
115    writer.OpenArray("s", &array_writer);
116    writer.CloseContainer(&array_writer);
117
118    exported_object_->SendSignal(&signal);
119  }
120
121 private:
122  // Returns true if the current thread is on the origin thread.
123  bool OnOriginThread() {
124    return base::PlatformThread::CurrentId() == origin_thread_id_;
125  }
126
127  // Called by dbus:: when the Bluetooth daemon fetches a single property of
128  // the descriptor.
129  void Get(dbus::MethodCall* method_call,
130           dbus::ExportedObject::ResponseSender response_sender) {
131    VLOG(2) << "BluetoothGattDescriptorServiceProvider::Get: "
132            << object_path_.value();
133    DCHECK(OnOriginThread());
134
135    dbus::MessageReader reader(method_call);
136
137    std::string interface_name;
138    std::string property_name;
139    if (!reader.PopString(&interface_name) ||
140        !reader.PopString(&property_name) ||
141        reader.HasMoreData()) {
142      scoped_ptr<dbus::ErrorResponse> error_response =
143          dbus::ErrorResponse::FromMethodCall(
144              method_call, kErrorInvalidArgs, "Expected 'ss'.");
145      response_sender.Run(error_response.PassAs<dbus::Response>());
146      return;
147    }
148
149    // Only the GATT descriptor interface is supported.
150    if (interface_name !=
151        bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface) {
152      scoped_ptr<dbus::ErrorResponse> error_response =
153          dbus::ErrorResponse::FromMethodCall(
154              method_call, kErrorInvalidArgs,
155              "No such interface: '" + interface_name + "'.");
156      response_sender.Run(error_response.PassAs<dbus::Response>());
157      return;
158    }
159
160    // If getting the "Value" property, obtain the value from the delegate.
161    if (property_name == bluetooth_gatt_descriptor::kValueProperty) {
162      DCHECK(delegate_);
163      delegate_->GetDescriptorValue(
164          base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnGet,
165                     weak_ptr_factory_.GetWeakPtr(),
166                     method_call, response_sender),
167          base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnFailure,
168                     weak_ptr_factory_.GetWeakPtr(),
169                     method_call, response_sender));
170      return;
171    }
172
173    scoped_ptr<dbus::Response> response =
174        dbus::Response::FromMethodCall(method_call);
175    dbus::MessageWriter writer(response.get());
176    dbus::MessageWriter variant_writer(NULL);
177
178    // TODO(armansito): Process the "Permissions" property below.
179    if (property_name == bluetooth_gatt_descriptor::kUUIDProperty) {
180      writer.OpenVariant("s", &variant_writer);
181      variant_writer.AppendString(uuid_);
182      writer.CloseContainer(&variant_writer);
183    } else if (property_name ==
184               bluetooth_gatt_descriptor::kCharacteristicProperty) {
185      writer.OpenVariant("o", &variant_writer);
186      variant_writer.AppendObjectPath(characteristic_path_);
187      writer.CloseContainer(&variant_writer);
188    } else {
189      response = dbus::ErrorResponse::FromMethodCall(
190          method_call, kErrorInvalidArgs,
191          "No such property: '" + property_name + "'.")
192          .PassAs<dbus::Response>();
193    }
194
195    response_sender.Run(response.Pass());
196  }
197
198  // Called by dbus:: when the Bluetooth daemon sets a single property of the
199  // descriptor.
200  void Set(dbus::MethodCall* method_call,
201           dbus::ExportedObject::ResponseSender response_sender) {
202    VLOG(2) << "BluetoothGattDescriptorServiceProvider::Set: "
203            << object_path_.value();
204    DCHECK(OnOriginThread());
205
206    dbus::MessageReader reader(method_call);
207
208    std::string interface_name;
209    std::string property_name;
210    dbus::MessageReader variant_reader(NULL);
211    if (!reader.PopString(&interface_name) ||
212        !reader.PopString(&property_name) ||
213        !reader.PopVariant(&variant_reader) ||
214        reader.HasMoreData()) {
215      scoped_ptr<dbus::ErrorResponse> error_response =
216          dbus::ErrorResponse::FromMethodCall(
217              method_call, kErrorInvalidArgs, "Expected 'ssv'.");
218      response_sender.Run(error_response.PassAs<dbus::Response>());
219      return;
220    }
221
222    // Only the GATT descriptor interface is allowed.
223    if (interface_name !=
224        bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface) {
225      scoped_ptr<dbus::ErrorResponse> error_response =
226          dbus::ErrorResponse::FromMethodCall(
227              method_call, kErrorInvalidArgs,
228              "No such interface: '" + interface_name + "'.");
229      response_sender.Run(error_response.PassAs<dbus::Response>());
230      return;
231    }
232
233    // Only the "Value" property is writeable.
234    if (property_name != bluetooth_gatt_descriptor::kValueProperty) {
235      std::string error_name;
236      std::string error_message;
237      if (property_name == bluetooth_gatt_descriptor::kUUIDProperty ||
238          property_name == bluetooth_gatt_descriptor::kCharacteristicProperty) {
239        error_name = kErrorPropertyReadOnly;
240        error_message = "Read-only property: '" + property_name + "'.";
241      } else {
242        error_name = kErrorInvalidArgs;
243        error_message = "No such property: '" + property_name + "'.";
244      }
245      scoped_ptr<dbus::ErrorResponse> error_response =
246          dbus::ErrorResponse::FromMethodCall(
247              method_call, error_name, error_message);
248      response_sender.Run(error_response.PassAs<dbus::Response>());
249      return;
250    }
251
252    // Obtain the value.
253    const uint8* bytes = NULL;
254    size_t length = 0;
255    if (!variant_reader.PopArrayOfBytes(&bytes, &length)) {
256      scoped_ptr<dbus::ErrorResponse> error_response =
257          dbus::ErrorResponse::FromMethodCall(
258              method_call, kErrorInvalidArgs,
259              "Property '" + property_name + "' has type 'ay'.");
260      response_sender.Run(error_response.PassAs<dbus::Response>());
261      return;
262    }
263
264    // Pass the set request onto the delegate.
265    std::vector<uint8> value(bytes, bytes + length);
266    DCHECK(delegate_);
267    delegate_->SetDescriptorValue(
268        value,
269        base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnSet,
270                   weak_ptr_factory_.GetWeakPtr(),
271                   method_call, response_sender),
272        base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnFailure,
273                   weak_ptr_factory_.GetWeakPtr(),
274                   method_call, response_sender));
275  }
276
277  // Called by dbus:: when the Bluetooth daemon fetches all properties of the
278  // descriptor.
279  void GetAll(dbus::MethodCall* method_call,
280              dbus::ExportedObject::ResponseSender response_sender) {
281    VLOG(2) << "BluetoothGattDescriptorServiceProvider::GetAll: "
282            << object_path_.value();
283    DCHECK(OnOriginThread());
284
285    dbus::MessageReader reader(method_call);
286
287    std::string interface_name;
288    if (!reader.PopString(&interface_name) || reader.HasMoreData()) {
289      scoped_ptr<dbus::ErrorResponse> error_response =
290          dbus::ErrorResponse::FromMethodCall(
291              method_call, kErrorInvalidArgs, "Expected 's'.");
292      response_sender.Run(error_response.PassAs<dbus::Response>());
293      return;
294    }
295
296    // Only the GATT descriptor interface is supported.
297    if (interface_name !=
298        bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface) {
299      scoped_ptr<dbus::ErrorResponse> error_response =
300          dbus::ErrorResponse::FromMethodCall(
301              method_call, kErrorInvalidArgs,
302              "No such interface: '" + interface_name + "'.");
303      response_sender.Run(error_response.PassAs<dbus::Response>());
304      return;
305    }
306
307    // Try to obtain the value from the delegate. We will construct the
308    // response in the success callback.
309    DCHECK(delegate_);
310    delegate_->GetDescriptorValue(
311        base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnGetAll,
312                   weak_ptr_factory_.GetWeakPtr(),
313                   method_call, response_sender),
314        base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnFailure,
315                   weak_ptr_factory_.GetWeakPtr(),
316                   method_call, response_sender));
317  }
318
319  // Called by dbus:: when a method is exported.
320  void OnExported(const std::string& interface_name,
321                  const std::string& method_name,
322                  bool success) {
323    LOG_IF(WARNING, !success) << "Failed to export "
324                              << interface_name << "." << method_name;
325  }
326
327  // Called by the Delegate in response to a method to call to get all
328  // properties, in which the delegate has successfully returned the
329  // descriptor value.
330  void OnGetAll(dbus::MethodCall* method_call,
331                dbus::ExportedObject::ResponseSender response_sender,
332                const std::vector<uint8>& value) {
333    VLOG(2) << "Descriptor value obtained from delegate. Responding to "
334            << "GetAll.";
335
336    scoped_ptr<dbus::Response> response =
337        dbus::Response::FromMethodCall(method_call);
338    dbus::MessageWriter writer(response.get());
339    dbus::MessageWriter array_writer(NULL);
340    dbus::MessageWriter dict_entry_writer(NULL);
341    dbus::MessageWriter variant_writer(NULL);
342
343    writer.OpenArray("{sv}", &array_writer);
344
345    array_writer.OpenDictEntry(&dict_entry_writer);
346    dict_entry_writer.AppendString(
347        bluetooth_gatt_descriptor::kUUIDProperty);
348    dict_entry_writer.AppendVariantOfString(uuid_);
349    array_writer.CloseContainer(&dict_entry_writer);
350
351    array_writer.OpenDictEntry(&dict_entry_writer);
352    dict_entry_writer.AppendString(
353        bluetooth_gatt_descriptor::kCharacteristicProperty);
354    dict_entry_writer.AppendVariantOfObjectPath(characteristic_path_);
355    array_writer.CloseContainer(&dict_entry_writer);
356
357    array_writer.OpenDictEntry(&dict_entry_writer);
358    dict_entry_writer.AppendString(
359        bluetooth_gatt_descriptor::kValueProperty);
360    dict_entry_writer.OpenVariant("ay", &variant_writer);
361    variant_writer.AppendArrayOfBytes(value.data(), value.size());
362    dict_entry_writer.CloseContainer(&variant_writer);
363    array_writer.CloseContainer(&dict_entry_writer);
364
365    // TODO(armansito): Process "Permissions" property.
366
367    writer.CloseContainer(&array_writer);
368
369    response_sender.Run(response.Pass());
370  }
371
372  // Called by the Delegate in response to a successful method call to get the
373  // descriptor value.
374  void OnGet(dbus::MethodCall* method_call,
375             dbus::ExportedObject::ResponseSender response_sender,
376             const std::vector<uint8>& value) {
377    VLOG(2) << "Returning descriptor value obtained from delegate.";
378    scoped_ptr<dbus::Response> response =
379        dbus::Response::FromMethodCall(method_call);
380    dbus::MessageWriter writer(response.get());
381    dbus::MessageWriter variant_writer(NULL);
382
383    writer.OpenVariant("ay", &variant_writer);
384    variant_writer.AppendArrayOfBytes(value.data(), value.size());
385    writer.CloseContainer(&variant_writer);
386
387    response_sender.Run(response.Pass());
388  }
389
390  // Called by the Delegate in response to a successful method call to set the
391  // descriptor value.
392  void OnSet(dbus::MethodCall* method_call,
393             dbus::ExportedObject::ResponseSender response_sender) {
394    VLOG(2) << "Successfully set descriptor value. Return success.";
395    response_sender.Run(dbus::Response::FromMethodCall(method_call));
396  }
397
398  // Called by the Delegate in response to a failed method call to get or set
399  // the descriptor value.
400  void OnFailure(dbus::MethodCall* method_call,
401                 dbus::ExportedObject::ResponseSender response_sender) {
402    VLOG(2) << "Failed to get/set descriptor value. Report error.";
403    scoped_ptr<dbus::ErrorResponse> error_response =
404        dbus::ErrorResponse::FromMethodCall(
405            method_call, kErrorFailed,
406            "Failed to get/set descriptor value.");
407    response_sender.Run(error_response.PassAs<dbus::Response>());
408  }
409
410  // Origin thread (i.e. the UI thread in production).
411  base::PlatformThreadId origin_thread_id_;
412
413  // 128-bit descriptor UUID of this object.
414  std::string uuid_;
415
416  // D-Bus bus object is exported on, not owned by this object and must
417  // outlive it.
418  dbus::Bus* bus_;
419
420  // Incoming methods to get and set the "Value" property are passed on to the
421  // delegate and callbacks passed to generate a reply. |delegate_| is generally
422  // the object that owns this one and must outlive it.
423  Delegate* delegate_;
424
425  // D-Bus object path of object we are exporting, kept so we can unregister
426  // again in our destructor.
427  dbus::ObjectPath object_path_;
428
429  // Object path of the GATT characteristic that the exported descriptor belongs
430  // to.
431  dbus::ObjectPath characteristic_path_;
432
433  // D-Bus object we are exporting, owned by this object.
434  scoped_refptr<dbus::ExportedObject> exported_object_;
435
436  // Weak pointer factory for generating 'this' pointers that might live longer
437  // than we do.
438  // Note: This should remain the last member so it'll be destroyed and
439  // invalidate its weak pointers before any other members are destroyed.
440  base::WeakPtrFactory<BluetoothGattDescriptorServiceProviderImpl>
441      weak_ptr_factory_;
442
443  DISALLOW_COPY_AND_ASSIGN(BluetoothGattDescriptorServiceProviderImpl);
444};
445
446BluetoothGattDescriptorServiceProvider::
447    BluetoothGattDescriptorServiceProvider() {
448}
449
450BluetoothGattDescriptorServiceProvider::
451    ~BluetoothGattDescriptorServiceProvider() {
452}
453
454// static
455BluetoothGattDescriptorServiceProvider*
456BluetoothGattDescriptorServiceProvider::Create(
457    dbus::Bus* bus,
458    const dbus::ObjectPath& object_path,
459    Delegate* delegate,
460    const std::string& uuid,
461    const std::vector<std::string>& permissions,
462    const dbus::ObjectPath& characteristic_path) {
463  if (!DBusThreadManager::Get()->IsUsingStub(DBusClientBundle::BLUETOOTH)) {
464    return new BluetoothGattDescriptorServiceProviderImpl(
465        bus, object_path, delegate, uuid, permissions, characteristic_path);
466  }
467  return new FakeBluetoothGattDescriptorServiceProvider(
468      object_path, delegate, uuid, permissions, characteristic_path);
469}
470
471}  // namespace chromeos
472