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 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 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(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 446 BluetoothGattDescriptorServiceProvider:: 447 BluetoothGattDescriptorServiceProvider() { 448 } 449 450 BluetoothGattDescriptorServiceProvider:: 451 ~BluetoothGattDescriptorServiceProvider() { 452 } 453 454 // static 455 BluetoothGattDescriptorServiceProvider* 456 BluetoothGattDescriptorServiceProvider::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