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