Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chromeos / dbus / bluetooth_gatt_descriptor_service_provider.cc
blob3ed39b9315d06b7727ddbc52a40c8256f18309a1
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_descriptor_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_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"
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 BluetoothGattDescriptorServiceProvider implementation used in production.
29 class 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(base::StartsWith(object_path_.value(),
54 characteristic_path_.value() + "/",
55 base::CompareCase::SENSITIVE));
57 exported_object_ = bus_->GetExportedObject(object_path_);
59 exported_object_->ExportMethod(
60 dbus::kDBusPropertiesInterface,
61 dbus::kDBusPropertiesGet,
62 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::Get,
63 weak_ptr_factory_.GetWeakPtr()),
64 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
65 weak_ptr_factory_.GetWeakPtr()));
67 exported_object_->ExportMethod(
68 dbus::kDBusPropertiesInterface,
69 dbus::kDBusPropertiesSet,
70 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::Set,
71 weak_ptr_factory_.GetWeakPtr()),
72 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
73 weak_ptr_factory_.GetWeakPtr()));
75 exported_object_->ExportMethod(
76 dbus::kDBusPropertiesInterface,
77 dbus::kDBusPropertiesGetAll,
78 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::GetAll,
79 weak_ptr_factory_.GetWeakPtr()),
80 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnExported,
81 weak_ptr_factory_.GetWeakPtr()));
84 ~BluetoothGattDescriptorServiceProviderImpl() override {
85 VLOG(1) << "Cleaning up Bluetooth GATT characteristic descriptor: "
86 << object_path_.value();
87 bus_->UnregisterExportedObject(object_path_);
90 // BluetoothGattDescriptorServiceProvider override.
91 void SendValueChanged(const std::vector<uint8>& value) override {
92 VLOG(2) << "Emitting a PropertiesChanged signal for descriptor value.";
93 dbus::Signal signal(
94 dbus::kDBusPropertiesInterface,
95 dbus::kDBusPropertiesChangedSignal);
96 dbus::MessageWriter writer(&signal);
97 dbus::MessageWriter array_writer(NULL);
98 dbus::MessageWriter dict_entry_writer(NULL);
99 dbus::MessageWriter variant_writer(NULL);
101 // interface_name
102 writer.AppendString(
103 bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface);
105 // changed_properties
106 writer.OpenArray("{sv}", &array_writer);
107 array_writer.OpenDictEntry(&dict_entry_writer);
108 dict_entry_writer.AppendString(bluetooth_gatt_descriptor::kValueProperty);
109 dict_entry_writer.OpenVariant("ay", &variant_writer);
110 variant_writer.AppendArrayOfBytes(value.data(), value.size());
111 dict_entry_writer.CloseContainer(&variant_writer);
112 array_writer.CloseContainer(&dict_entry_writer);
113 writer.CloseContainer(&array_writer);
115 // invalidated_properties.
116 writer.OpenArray("s", &array_writer);
117 writer.CloseContainer(&array_writer);
119 exported_object_->SendSignal(&signal);
122 private:
123 // Returns true if the current thread is on the origin thread.
124 bool OnOriginThread() {
125 return base::PlatformThread::CurrentId() == origin_thread_id_;
128 // Called by dbus:: when the Bluetooth daemon fetches a single property of
129 // the descriptor.
130 void Get(dbus::MethodCall* method_call,
131 dbus::ExportedObject::ResponseSender response_sender) {
132 VLOG(2) << "BluetoothGattDescriptorServiceProvider::Get: "
133 << object_path_.value();
134 DCHECK(OnOriginThread());
136 dbus::MessageReader reader(method_call);
138 std::string interface_name;
139 std::string property_name;
140 if (!reader.PopString(&interface_name) ||
141 !reader.PopString(&property_name) ||
142 reader.HasMoreData()) {
143 scoped_ptr<dbus::ErrorResponse> error_response =
144 dbus::ErrorResponse::FromMethodCall(
145 method_call, kErrorInvalidArgs, "Expected 'ss'.");
146 response_sender.Run(error_response.Pass());
147 return;
150 // Only the GATT descriptor interface is supported.
151 if (interface_name !=
152 bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface) {
153 scoped_ptr<dbus::ErrorResponse> error_response =
154 dbus::ErrorResponse::FromMethodCall(
155 method_call, kErrorInvalidArgs,
156 "No such interface: '" + interface_name + "'.");
157 response_sender.Run(error_response.Pass());
158 return;
161 // If getting the "Value" property, obtain the value from the delegate.
162 if (property_name == bluetooth_gatt_descriptor::kValueProperty) {
163 DCHECK(delegate_);
164 delegate_->GetDescriptorValue(
165 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnGet,
166 weak_ptr_factory_.GetWeakPtr(),
167 method_call, response_sender),
168 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnFailure,
169 weak_ptr_factory_.GetWeakPtr(),
170 method_call, response_sender));
171 return;
174 scoped_ptr<dbus::Response> response =
175 dbus::Response::FromMethodCall(method_call);
176 dbus::MessageWriter writer(response.get());
177 dbus::MessageWriter variant_writer(NULL);
179 // TODO(armansito): Process the "Permissions" property below.
180 if (property_name == bluetooth_gatt_descriptor::kUUIDProperty) {
181 writer.OpenVariant("s", &variant_writer);
182 variant_writer.AppendString(uuid_);
183 writer.CloseContainer(&variant_writer);
184 } else if (property_name ==
185 bluetooth_gatt_descriptor::kCharacteristicProperty) {
186 writer.OpenVariant("o", &variant_writer);
187 variant_writer.AppendObjectPath(characteristic_path_);
188 writer.CloseContainer(&variant_writer);
189 } else {
190 response = dbus::ErrorResponse::FromMethodCall(
191 method_call,
192 kErrorInvalidArgs,
193 "No such property: '" + property_name + "'.");
196 response_sender.Run(response.Pass());
199 // Called by dbus:: when the Bluetooth daemon sets a single property of the
200 // descriptor.
201 void Set(dbus::MethodCall* method_call,
202 dbus::ExportedObject::ResponseSender response_sender) {
203 VLOG(2) << "BluetoothGattDescriptorServiceProvider::Set: "
204 << object_path_.value();
205 DCHECK(OnOriginThread());
207 dbus::MessageReader reader(method_call);
209 std::string interface_name;
210 std::string property_name;
211 dbus::MessageReader variant_reader(NULL);
212 if (!reader.PopString(&interface_name) ||
213 !reader.PopString(&property_name) ||
214 !reader.PopVariant(&variant_reader) ||
215 reader.HasMoreData()) {
216 scoped_ptr<dbus::ErrorResponse> error_response =
217 dbus::ErrorResponse::FromMethodCall(
218 method_call, kErrorInvalidArgs, "Expected 'ssv'.");
219 response_sender.Run(error_response.Pass());
220 return;
223 // Only the GATT descriptor interface is allowed.
224 if (interface_name !=
225 bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface) {
226 scoped_ptr<dbus::ErrorResponse> error_response =
227 dbus::ErrorResponse::FromMethodCall(
228 method_call, kErrorInvalidArgs,
229 "No such interface: '" + interface_name + "'.");
230 response_sender.Run(error_response.Pass());
231 return;
234 // Only the "Value" property is writeable.
235 if (property_name != bluetooth_gatt_descriptor::kValueProperty) {
236 std::string error_name;
237 std::string error_message;
238 if (property_name == bluetooth_gatt_descriptor::kUUIDProperty ||
239 property_name == bluetooth_gatt_descriptor::kCharacteristicProperty) {
240 error_name = kErrorPropertyReadOnly;
241 error_message = "Read-only property: '" + property_name + "'.";
242 } else {
243 error_name = kErrorInvalidArgs;
244 error_message = "No such property: '" + property_name + "'.";
246 scoped_ptr<dbus::ErrorResponse> error_response =
247 dbus::ErrorResponse::FromMethodCall(
248 method_call, error_name, error_message);
249 response_sender.Run(error_response.Pass());
250 return;
253 // Obtain the value.
254 const uint8* bytes = NULL;
255 size_t length = 0;
256 if (!variant_reader.PopArrayOfBytes(&bytes, &length)) {
257 scoped_ptr<dbus::ErrorResponse> error_response =
258 dbus::ErrorResponse::FromMethodCall(
259 method_call, kErrorInvalidArgs,
260 "Property '" + property_name + "' has type 'ay'.");
261 response_sender.Run(error_response.Pass());
262 return;
265 // Pass the set request onto the delegate.
266 std::vector<uint8> value(bytes, bytes + length);
267 DCHECK(delegate_);
268 delegate_->SetDescriptorValue(
269 value,
270 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnSet,
271 weak_ptr_factory_.GetWeakPtr(),
272 method_call, response_sender),
273 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnFailure,
274 weak_ptr_factory_.GetWeakPtr(),
275 method_call, response_sender));
278 // Called by dbus:: when the Bluetooth daemon fetches all properties of the
279 // descriptor.
280 void GetAll(dbus::MethodCall* method_call,
281 dbus::ExportedObject::ResponseSender response_sender) {
282 VLOG(2) << "BluetoothGattDescriptorServiceProvider::GetAll: "
283 << object_path_.value();
284 DCHECK(OnOriginThread());
286 dbus::MessageReader reader(method_call);
288 std::string interface_name;
289 if (!reader.PopString(&interface_name) || reader.HasMoreData()) {
290 scoped_ptr<dbus::ErrorResponse> error_response =
291 dbus::ErrorResponse::FromMethodCall(
292 method_call, kErrorInvalidArgs, "Expected 's'.");
293 response_sender.Run(error_response.Pass());
294 return;
297 // Only the GATT descriptor interface is supported.
298 if (interface_name !=
299 bluetooth_gatt_descriptor::kBluetoothGattDescriptorInterface) {
300 scoped_ptr<dbus::ErrorResponse> error_response =
301 dbus::ErrorResponse::FromMethodCall(
302 method_call, kErrorInvalidArgs,
303 "No such interface: '" + interface_name + "'.");
304 response_sender.Run(error_response.Pass());
305 return;
308 // Try to obtain the value from the delegate. We will construct the
309 // response in the success callback.
310 DCHECK(delegate_);
311 delegate_->GetDescriptorValue(
312 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnGetAll,
313 weak_ptr_factory_.GetWeakPtr(),
314 method_call, response_sender),
315 base::Bind(&BluetoothGattDescriptorServiceProviderImpl::OnFailure,
316 weak_ptr_factory_.GetWeakPtr(),
317 method_call, response_sender));
320 // Called by dbus:: when a method is exported.
321 void OnExported(const std::string& interface_name,
322 const std::string& method_name,
323 bool success) {
324 LOG_IF(WARNING, !success) << "Failed to export "
325 << interface_name << "." << method_name;
328 // Called by the Delegate in response to a method to call to get all
329 // properties, in which the delegate has successfully returned the
330 // descriptor value.
331 void OnGetAll(dbus::MethodCall* method_call,
332 dbus::ExportedObject::ResponseSender response_sender,
333 const std::vector<uint8>& value) {
334 VLOG(2) << "Descriptor value obtained from delegate. Responding to "
335 << "GetAll.";
337 scoped_ptr<dbus::Response> response =
338 dbus::Response::FromMethodCall(method_call);
339 dbus::MessageWriter writer(response.get());
340 dbus::MessageWriter array_writer(NULL);
341 dbus::MessageWriter dict_entry_writer(NULL);
342 dbus::MessageWriter variant_writer(NULL);
344 writer.OpenArray("{sv}", &array_writer);
346 array_writer.OpenDictEntry(&dict_entry_writer);
347 dict_entry_writer.AppendString(
348 bluetooth_gatt_descriptor::kUUIDProperty);
349 dict_entry_writer.AppendVariantOfString(uuid_);
350 array_writer.CloseContainer(&dict_entry_writer);
352 array_writer.OpenDictEntry(&dict_entry_writer);
353 dict_entry_writer.AppendString(
354 bluetooth_gatt_descriptor::kCharacteristicProperty);
355 dict_entry_writer.AppendVariantOfObjectPath(characteristic_path_);
356 array_writer.CloseContainer(&dict_entry_writer);
358 array_writer.OpenDictEntry(&dict_entry_writer);
359 dict_entry_writer.AppendString(
360 bluetooth_gatt_descriptor::kValueProperty);
361 dict_entry_writer.OpenVariant("ay", &variant_writer);
362 variant_writer.AppendArrayOfBytes(value.data(), value.size());
363 dict_entry_writer.CloseContainer(&variant_writer);
364 array_writer.CloseContainer(&dict_entry_writer);
366 // TODO(armansito): Process "Permissions" property.
368 writer.CloseContainer(&array_writer);
370 response_sender.Run(response.Pass());
373 // Called by the Delegate in response to a successful method call to get the
374 // descriptor value.
375 void OnGet(dbus::MethodCall* method_call,
376 dbus::ExportedObject::ResponseSender response_sender,
377 const std::vector<uint8>& value) {
378 VLOG(2) << "Returning descriptor value obtained from delegate.";
379 scoped_ptr<dbus::Response> response =
380 dbus::Response::FromMethodCall(method_call);
381 dbus::MessageWriter writer(response.get());
382 dbus::MessageWriter variant_writer(NULL);
384 writer.OpenVariant("ay", &variant_writer);
385 variant_writer.AppendArrayOfBytes(value.data(), value.size());
386 writer.CloseContainer(&variant_writer);
388 response_sender.Run(response.Pass());
391 // Called by the Delegate in response to a successful method call to set the
392 // descriptor value.
393 void OnSet(dbus::MethodCall* method_call,
394 dbus::ExportedObject::ResponseSender response_sender) {
395 VLOG(2) << "Successfully set descriptor value. Return success.";
396 response_sender.Run(dbus::Response::FromMethodCall(method_call));
399 // Called by the Delegate in response to a failed method call to get or set
400 // the descriptor value.
401 void OnFailure(dbus::MethodCall* method_call,
402 dbus::ExportedObject::ResponseSender response_sender) {
403 VLOG(2) << "Failed to get/set descriptor value. Report error.";
404 scoped_ptr<dbus::ErrorResponse> error_response =
405 dbus::ErrorResponse::FromMethodCall(
406 method_call, kErrorFailed,
407 "Failed to get/set descriptor value.");
408 response_sender.Run(error_response.Pass());
411 // Origin thread (i.e. the UI thread in production).
412 base::PlatformThreadId origin_thread_id_;
414 // 128-bit descriptor UUID of this object.
415 std::string uuid_;
417 // D-Bus bus object is exported on, not owned by this object and must
418 // outlive it.
419 dbus::Bus* bus_;
421 // Incoming methods to get and set the "Value" property are passed on to the
422 // delegate and callbacks passed to generate a reply. |delegate_| is generally
423 // the object that owns this one and must outlive it.
424 Delegate* delegate_;
426 // D-Bus object path of object we are exporting, kept so we can unregister
427 // again in our destructor.
428 dbus::ObjectPath object_path_;
430 // Object path of the GATT characteristic that the exported descriptor belongs
431 // to.
432 dbus::ObjectPath characteristic_path_;
434 // D-Bus object we are exporting, owned by this object.
435 scoped_refptr<dbus::ExportedObject> exported_object_;
437 // Weak pointer factory for generating 'this' pointers that might live longer
438 // than we do.
439 // Note: This should remain the last member so it'll be destroyed and
440 // invalidate its weak pointers before any other members are destroyed.
441 base::WeakPtrFactory<BluetoothGattDescriptorServiceProviderImpl>
442 weak_ptr_factory_;
444 DISALLOW_COPY_AND_ASSIGN(BluetoothGattDescriptorServiceProviderImpl);
447 BluetoothGattDescriptorServiceProvider::
448 BluetoothGattDescriptorServiceProvider() {
451 BluetoothGattDescriptorServiceProvider::
452 ~BluetoothGattDescriptorServiceProvider() {
455 // static
456 BluetoothGattDescriptorServiceProvider*
457 BluetoothGattDescriptorServiceProvider::Create(
458 dbus::Bus* bus,
459 const dbus::ObjectPath& object_path,
460 Delegate* delegate,
461 const std::string& uuid,
462 const std::vector<std::string>& permissions,
463 const dbus::ObjectPath& characteristic_path) {
464 if (!DBusThreadManager::Get()->IsUsingStub(DBusClientBundle::BLUETOOTH)) {
465 return new BluetoothGattDescriptorServiceProviderImpl(
466 bus, object_path, delegate, uuid, permissions, characteristic_path);
468 return new FakeBluetoothGattDescriptorServiceProvider(
469 object_path, delegate, uuid, permissions, characteristic_path);
472 } // namespace chromeos