Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chromeos / dbus / bluetooth_gatt_characteristic_service_provider.cc
blob545880ac522d00db8180a47d25e4ad3782cd9272
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.
5 #include "chromeos/dbus/bluetooth_gatt_characteristic_service_provider.h"
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"
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
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(base::StartsWith(object_path_.value(),
56 service_path_.value() + "/",
57 base::CompareCase::SENSITIVE));
59 exported_object_ = bus_->GetExportedObject(object_path_);
61 exported_object_->ExportMethod(
62 dbus::kDBusPropertiesInterface,
63 dbus::kDBusPropertiesGet,
64 base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::Get,
65 weak_ptr_factory_.GetWeakPtr()),
66 base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnExported,
67 weak_ptr_factory_.GetWeakPtr()));
69 exported_object_->ExportMethod(
70 dbus::kDBusPropertiesInterface,
71 dbus::kDBusPropertiesSet,
72 base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::Set,
73 weak_ptr_factory_.GetWeakPtr()),
74 base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnExported,
75 weak_ptr_factory_.GetWeakPtr()));
77 exported_object_->ExportMethod(
78 dbus::kDBusPropertiesInterface,
79 dbus::kDBusPropertiesGetAll,
80 base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::GetAll,
81 weak_ptr_factory_.GetWeakPtr()),
82 base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnExported,
83 weak_ptr_factory_.GetWeakPtr()));
86 ~BluetoothGattCharacteristicServiceProviderImpl() override {
87 VLOG(1) << "Cleaning up Bluetooth GATT characteristic: "
88 << object_path_.value();
89 bus_->UnregisterExportedObject(object_path_);
92 // BluetoothGattCharacteristicServiceProvider override.
93 void SendValueChanged(const std::vector<uint8>& value) override {
94 VLOG(2) << "Emitting a PropertiesChanged signal for characteristic value.";
95 dbus::Signal signal(
96 dbus::kDBusPropertiesInterface,
97 dbus::kDBusPropertiesChangedSignal);
98 dbus::MessageWriter writer(&signal);
99 dbus::MessageWriter array_writer(NULL);
100 dbus::MessageWriter dict_entry_writer(NULL);
101 dbus::MessageWriter variant_writer(NULL);
103 // interface_name
104 writer.AppendString(
105 bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface);
107 // changed_properties
108 writer.OpenArray("{sv}", &array_writer);
109 array_writer.OpenDictEntry(&dict_entry_writer);
110 dict_entry_writer.AppendString(
111 bluetooth_gatt_characteristic::kValueProperty);
112 dict_entry_writer.OpenVariant("ay", &variant_writer);
113 variant_writer.AppendArrayOfBytes(value.data(), value.size());
114 dict_entry_writer.CloseContainer(&variant_writer);
115 array_writer.CloseContainer(&dict_entry_writer);
116 writer.CloseContainer(&array_writer);
118 // invalidated_properties.
119 writer.OpenArray("s", &array_writer);
120 writer.CloseContainer(&array_writer);
122 exported_object_->SendSignal(&signal);
125 private:
126 // Returns true if the current thread is on the origin thread.
127 bool OnOriginThread() {
128 return base::PlatformThread::CurrentId() == origin_thread_id_;
131 // Called by dbus:: when the Bluetooth daemon fetches a single property of
132 // the characteristic.
133 void Get(dbus::MethodCall* method_call,
134 dbus::ExportedObject::ResponseSender response_sender) {
135 VLOG(2) << "BluetoothGattCharacteristicServiceProvider::Get: "
136 << object_path_.value();
137 DCHECK(OnOriginThread());
139 dbus::MessageReader reader(method_call);
141 std::string interface_name;
142 std::string property_name;
143 if (!reader.PopString(&interface_name) ||
144 !reader.PopString(&property_name) ||
145 reader.HasMoreData()) {
146 scoped_ptr<dbus::ErrorResponse> error_response =
147 dbus::ErrorResponse::FromMethodCall(
148 method_call, kErrorInvalidArgs, "Expected 'ss'.");
149 response_sender.Run(error_response.Pass());
150 return;
153 // Only the GATT characteristic interface is supported.
154 if (interface_name !=
155 bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface) {
156 scoped_ptr<dbus::ErrorResponse> error_response =
157 dbus::ErrorResponse::FromMethodCall(
158 method_call, kErrorInvalidArgs,
159 "No such interface: '" + interface_name + "'.");
160 response_sender.Run(error_response.Pass());
161 return;
164 // If getting the "Value" property, obtain the value from the delegate.
165 if (property_name == bluetooth_gatt_characteristic::kValueProperty) {
166 DCHECK(delegate_);
167 delegate_->GetCharacteristicValue(
168 base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnGet,
169 weak_ptr_factory_.GetWeakPtr(),
170 method_call, response_sender),
171 base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnFailure,
172 weak_ptr_factory_.GetWeakPtr(),
173 method_call, response_sender));
174 return;
177 scoped_ptr<dbus::Response> response =
178 dbus::Response::FromMethodCall(method_call);
179 dbus::MessageWriter writer(response.get());
180 dbus::MessageWriter variant_writer(NULL);
182 // TODO(armansito): Process the "Flags" and "Permissions" properties below.
183 if (property_name == bluetooth_gatt_characteristic::kUUIDProperty) {
184 writer.OpenVariant("s", &variant_writer);
185 variant_writer.AppendString(uuid_);
186 writer.CloseContainer(&variant_writer);
187 } else if (property_name ==
188 bluetooth_gatt_characteristic::kServiceProperty) {
189 writer.OpenVariant("o", &variant_writer);
190 variant_writer.AppendObjectPath(service_path_);
191 writer.CloseContainer(&variant_writer);
192 } else {
193 response = dbus::ErrorResponse::FromMethodCall(
194 method_call,
195 kErrorInvalidArgs,
196 "No such property: '" + property_name + "'.");
199 response_sender.Run(response.Pass());
202 // Called by dbus:: when the Bluetooth daemon sets a single property of the
203 // characteristic.
204 void Set(dbus::MethodCall* method_call,
205 dbus::ExportedObject::ResponseSender response_sender) {
206 VLOG(2) << "BluetoothGattCharacteristicServiceProvider::Set: "
207 << object_path_.value();
208 DCHECK(OnOriginThread());
210 dbus::MessageReader reader(method_call);
212 std::string interface_name;
213 std::string property_name;
214 dbus::MessageReader variant_reader(NULL);
215 if (!reader.PopString(&interface_name) ||
216 !reader.PopString(&property_name) ||
217 !reader.PopVariant(&variant_reader) ||
218 reader.HasMoreData()) {
219 scoped_ptr<dbus::ErrorResponse> error_response =
220 dbus::ErrorResponse::FromMethodCall(
221 method_call, kErrorInvalidArgs, "Expected 'ssv'.");
222 response_sender.Run(error_response.Pass());
223 return;
226 // Only the GATT characteristic interface is allowed.
227 if (interface_name !=
228 bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface) {
229 scoped_ptr<dbus::ErrorResponse> error_response =
230 dbus::ErrorResponse::FromMethodCall(
231 method_call, kErrorInvalidArgs,
232 "No such interface: '" + interface_name + "'.");
233 response_sender.Run(error_response.Pass());
234 return;
237 // Only the "Value" property is writeable.
238 if (property_name != bluetooth_gatt_characteristic::kValueProperty) {
239 std::string error_name;
240 std::string error_message;
241 if (property_name == bluetooth_gatt_characteristic::kUUIDProperty ||
242 property_name == bluetooth_gatt_characteristic::kServiceProperty) {
243 error_name = kErrorPropertyReadOnly;
244 error_message = "Read-only property: '" + property_name + "'.";
245 } else {
246 error_name = kErrorInvalidArgs;
247 error_message = "No such property: '" + property_name + "'.";
249 scoped_ptr<dbus::ErrorResponse> error_response =
250 dbus::ErrorResponse::FromMethodCall(
251 method_call, error_name, error_message);
252 response_sender.Run(error_response.Pass());
253 return;
256 // Obtain the value.
257 const uint8* bytes = NULL;
258 size_t length = 0;
259 if (!variant_reader.PopArrayOfBytes(&bytes, &length)) {
260 scoped_ptr<dbus::ErrorResponse> error_response =
261 dbus::ErrorResponse::FromMethodCall(
262 method_call, kErrorInvalidArgs,
263 "Property '" + property_name + "' has type 'ay'.");
264 response_sender.Run(error_response.Pass());
265 return;
268 // Pass the set request onto the delegate.
269 std::vector<uint8> value(bytes, bytes + length);
270 DCHECK(delegate_);
271 delegate_->SetCharacteristicValue(
272 value,
273 base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnSet,
274 weak_ptr_factory_.GetWeakPtr(),
275 method_call, response_sender),
276 base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnFailure,
277 weak_ptr_factory_.GetWeakPtr(),
278 method_call, response_sender));
281 // Called by dbus:: when the Bluetooth daemon fetches all properties of the
282 // characteristic.
283 void GetAll(dbus::MethodCall* method_call,
284 dbus::ExportedObject::ResponseSender response_sender) {
285 VLOG(2) << "BluetoothGattCharacteristicServiceProvider::GetAll: "
286 << object_path_.value();
287 DCHECK(OnOriginThread());
289 dbus::MessageReader reader(method_call);
291 std::string interface_name;
292 if (!reader.PopString(&interface_name) || reader.HasMoreData()) {
293 scoped_ptr<dbus::ErrorResponse> error_response =
294 dbus::ErrorResponse::FromMethodCall(
295 method_call, kErrorInvalidArgs, "Expected 's'.");
296 response_sender.Run(error_response.Pass());
297 return;
300 // Only the GATT characteristic interface is supported.
301 if (interface_name !=
302 bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface) {
303 scoped_ptr<dbus::ErrorResponse> error_response =
304 dbus::ErrorResponse::FromMethodCall(
305 method_call, kErrorInvalidArgs,
306 "No such interface: '" + interface_name + "'.");
307 response_sender.Run(error_response.Pass());
308 return;
311 // Try to obtain the value from the delegate. We will construct the
312 // response in the success callback.
313 DCHECK(delegate_);
314 delegate_->GetCharacteristicValue(
315 base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnGetAll,
316 weak_ptr_factory_.GetWeakPtr(),
317 method_call, response_sender),
318 base::Bind(&BluetoothGattCharacteristicServiceProviderImpl::OnFailure,
319 weak_ptr_factory_.GetWeakPtr(),
320 method_call, response_sender));
323 // Called by dbus:: when a method is exported.
324 void OnExported(const std::string& interface_name,
325 const std::string& method_name,
326 bool success) {
327 LOG_IF(WARNING, !success) << "Failed to export "
328 << interface_name << "." << method_name;
331 // Called by the Delegate in response to a method to call to get all
332 // properties, in which the delegate has successfully returned the
333 // characteristic value.
334 void OnGetAll(dbus::MethodCall* method_call,
335 dbus::ExportedObject::ResponseSender response_sender,
336 const std::vector<uint8>& value) {
337 VLOG(2) << "Characteristic value obtained from delegate. Responding to "
338 << "GetAll.";
340 scoped_ptr<dbus::Response> response =
341 dbus::Response::FromMethodCall(method_call);
342 dbus::MessageWriter writer(response.get());
343 dbus::MessageWriter array_writer(NULL);
344 dbus::MessageWriter dict_entry_writer(NULL);
345 dbus::MessageWriter variant_writer(NULL);
347 writer.OpenArray("{sv}", &array_writer);
349 array_writer.OpenDictEntry(&dict_entry_writer);
350 dict_entry_writer.AppendString(
351 bluetooth_gatt_characteristic::kUUIDProperty);
352 dict_entry_writer.AppendVariantOfString(uuid_);
353 array_writer.CloseContainer(&dict_entry_writer);
355 array_writer.OpenDictEntry(&dict_entry_writer);
356 dict_entry_writer.AppendString(
357 bluetooth_gatt_characteristic::kServiceProperty);
358 dict_entry_writer.AppendVariantOfObjectPath(service_path_);
359 array_writer.CloseContainer(&dict_entry_writer);
361 array_writer.OpenDictEntry(&dict_entry_writer);
362 dict_entry_writer.AppendString(
363 bluetooth_gatt_characteristic::kValueProperty);
364 dict_entry_writer.OpenVariant("ay", &variant_writer);
365 variant_writer.AppendArrayOfBytes(value.data(), value.size());
366 dict_entry_writer.CloseContainer(&variant_writer);
367 array_writer.CloseContainer(&dict_entry_writer);
369 // TODO(armansito): Process Flags & Permissions properties.
371 writer.CloseContainer(&array_writer);
373 response_sender.Run(response.Pass());
376 // Called by the Delegate in response to a successful method call to get the
377 // characteristic value.
378 void OnGet(dbus::MethodCall* method_call,
379 dbus::ExportedObject::ResponseSender response_sender,
380 const std::vector<uint8>& value) {
381 VLOG(2) << "Returning characteristic value obtained from delegate.";
382 scoped_ptr<dbus::Response> response =
383 dbus::Response::FromMethodCall(method_call);
384 dbus::MessageWriter writer(response.get());
385 dbus::MessageWriter variant_writer(NULL);
387 writer.OpenVariant("ay", &variant_writer);
388 variant_writer.AppendArrayOfBytes(value.data(), value.size());
389 writer.CloseContainer(&variant_writer);
391 response_sender.Run(response.Pass());
394 // Called by the Delegate in response to a successful method call to set the
395 // characteristic value.
396 void OnSet(dbus::MethodCall* method_call,
397 dbus::ExportedObject::ResponseSender response_sender) {
398 VLOG(2) << "Successfully set characteristic value. Return success.";
399 response_sender.Run(dbus::Response::FromMethodCall(method_call));
402 // Called by the Delegate in response to a failed method call to get or set
403 // the characteristic value.
404 void OnFailure(dbus::MethodCall* method_call,
405 dbus::ExportedObject::ResponseSender response_sender) {
406 VLOG(2) << "Failed to get/set characteristic value. Report error.";
407 scoped_ptr<dbus::ErrorResponse> error_response =
408 dbus::ErrorResponse::FromMethodCall(
409 method_call, kErrorFailed,
410 "Failed to get/set characteristic value.");
411 response_sender.Run(error_response.Pass());
414 // Origin thread (i.e. the UI thread in production).
415 base::PlatformThreadId origin_thread_id_;
417 // 128-bit characteristic UUID of this object.
418 std::string uuid_;
420 // D-Bus bus object is exported on, not owned by this object and must
421 // outlive it.
422 dbus::Bus* bus_;
424 // Incoming methods to get and set the "Value" property are passed on to the
425 // delegate and callbacks passed to generate a reply. |delegate_| is generally
426 // the object that owns this one and must outlive it.
427 Delegate* delegate_;
429 // D-Bus object path of object we are exporting, kept so we can unregister
430 // again in our destructor.
431 dbus::ObjectPath object_path_;
433 // Object path of the GATT service that the exported characteristic belongs
434 // to.
435 dbus::ObjectPath service_path_;
437 // D-Bus object we are exporting, owned by this object.
438 scoped_refptr<dbus::ExportedObject> exported_object_;
440 // Weak pointer factory for generating 'this' pointers that might live longer
441 // than we do.
442 // Note: This should remain the last member so it'll be destroyed and
443 // invalidate its weak pointers before any other members are destroyed.
444 base::WeakPtrFactory<BluetoothGattCharacteristicServiceProviderImpl>
445 weak_ptr_factory_;
447 DISALLOW_COPY_AND_ASSIGN(BluetoothGattCharacteristicServiceProviderImpl);
450 BluetoothGattCharacteristicServiceProvider::
451 BluetoothGattCharacteristicServiceProvider() {
454 BluetoothGattCharacteristicServiceProvider::
455 ~BluetoothGattCharacteristicServiceProvider() {
458 // static
459 BluetoothGattCharacteristicServiceProvider*
460 BluetoothGattCharacteristicServiceProvider::Create(
461 dbus::Bus* bus,
462 const dbus::ObjectPath& object_path,
463 Delegate* delegate,
464 const std::string& uuid,
465 const std::vector<std::string>& flags,
466 const std::vector<std::string>& permissions,
467 const dbus::ObjectPath& service_path) {
468 if (!DBusThreadManager::Get()->IsUsingStub(DBusClientBundle::BLUETOOTH)) {
469 return new BluetoothGattCharacteristicServiceProviderImpl(
470 bus, object_path, delegate, uuid, flags, permissions, service_path);
472 return new FakeBluetoothGattCharacteristicServiceProvider(
473 object_path, delegate, uuid, flags, permissions, service_path);
476 } // namespace chromeos