bluetooth_agent_service_provider.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 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_agent_service_provider.h" 6 7#include <string> 8 9#include "base/bind.h" 10#include "base/chromeos/chromeos_version.h" 11#include "base/logging.h" 12#include "base/memory/ref_counted.h" 13#include "base/threading/platform_thread.h" 14#include "dbus/bus.h" 15#include "dbus/exported_object.h" 16#include "dbus/message.h" 17#include "dbus/object_path.h" 18#include "third_party/cros_system_api/dbus/service_constants.h" 19 20namespace { 21 22// Constants used by BlueZ for the ConfirmModeChange method. 23const char kModeOff[] = "off"; 24const char kModeConnectable[] = "connectable"; 25const char kModeDiscoverable[] = "discoverable"; 26 27} // namespace 28 29namespace chromeos { 30 31// The BluetoothAgentServiceProvider implementation used in production. 32class BluetoothAgentServiceProviderImpl : public BluetoothAgentServiceProvider { 33 public: 34 BluetoothAgentServiceProviderImpl(dbus::Bus* bus, 35 const dbus::ObjectPath& object_path, 36 Delegate* delegate) 37 : origin_thread_id_(base::PlatformThread::CurrentId()), 38 bus_(bus), 39 delegate_(delegate), 40 object_path_(object_path), 41 weak_ptr_factory_(this) { 42 DVLOG(1) << "Creating BluetoothAdapterClientImpl for " 43 << object_path.value(); 44 45 exported_object_ = bus_->GetExportedObject(object_path_); 46 47 exported_object_->ExportMethod( 48 bluetooth_agent::kBluetoothAgentInterface, 49 bluetooth_agent::kRelease, 50 base::Bind(&BluetoothAgentServiceProviderImpl::Release, 51 weak_ptr_factory_.GetWeakPtr()), 52 base::Bind(&BluetoothAgentServiceProviderImpl::ReleaseExported, 53 weak_ptr_factory_.GetWeakPtr())); 54 55 exported_object_->ExportMethod( 56 bluetooth_agent::kBluetoothAgentInterface, 57 bluetooth_agent::kRequestPinCode, 58 base::Bind(&BluetoothAgentServiceProviderImpl::RequestPinCode, 59 weak_ptr_factory_.GetWeakPtr()), 60 base::Bind(&BluetoothAgentServiceProviderImpl::RequestPinCodeExported, 61 weak_ptr_factory_.GetWeakPtr())); 62 63 exported_object_->ExportMethod( 64 bluetooth_agent::kBluetoothAgentInterface, 65 bluetooth_agent::kRequestPasskey, 66 base::Bind(&BluetoothAgentServiceProviderImpl::RequestPasskey, 67 weak_ptr_factory_.GetWeakPtr()), 68 base::Bind(&BluetoothAgentServiceProviderImpl::RequestPasskeyExported, 69 weak_ptr_factory_.GetWeakPtr())); 70 71 exported_object_->ExportMethod( 72 bluetooth_agent::kBluetoothAgentInterface, 73 bluetooth_agent::kDisplayPinCode, 74 base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPinCode, 75 weak_ptr_factory_.GetWeakPtr()), 76 base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPinCodeExported, 77 weak_ptr_factory_.GetWeakPtr())); 78 79 exported_object_->ExportMethod( 80 bluetooth_agent::kBluetoothAgentInterface, 81 bluetooth_agent::kDisplayPasskey, 82 base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPasskey, 83 weak_ptr_factory_.GetWeakPtr()), 84 base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPasskeyExported, 85 weak_ptr_factory_.GetWeakPtr())); 86 87 exported_object_->ExportMethod( 88 bluetooth_agent::kBluetoothAgentInterface, 89 bluetooth_agent::kRequestConfirmation, 90 base::Bind(&BluetoothAgentServiceProviderImpl::RequestConfirmation, 91 weak_ptr_factory_.GetWeakPtr()), 92 base::Bind( 93 &BluetoothAgentServiceProviderImpl::RequestConfirmationExported, 94 weak_ptr_factory_.GetWeakPtr())); 95 96 exported_object_->ExportMethod( 97 bluetooth_agent::kBluetoothAgentInterface, 98 bluetooth_agent::kAuthorize, 99 base::Bind(&BluetoothAgentServiceProviderImpl::Authorize, 100 weak_ptr_factory_.GetWeakPtr()), 101 base::Bind(&BluetoothAgentServiceProviderImpl::AuthorizeExported, 102 weak_ptr_factory_.GetWeakPtr())); 103 104 exported_object_->ExportMethod( 105 bluetooth_agent::kBluetoothAgentInterface, 106 bluetooth_agent::kConfirmModeChange, 107 base::Bind(&BluetoothAgentServiceProviderImpl::ConfirmModeChange, 108 weak_ptr_factory_.GetWeakPtr()), 109 base::Bind( 110 &BluetoothAgentServiceProviderImpl::ConfirmModeChangeExported, 111 weak_ptr_factory_.GetWeakPtr())); 112 113 exported_object_->ExportMethod( 114 bluetooth_agent::kBluetoothAgentInterface, 115 bluetooth_agent::kCancel, 116 base::Bind(&BluetoothAgentServiceProviderImpl::Cancel, 117 weak_ptr_factory_.GetWeakPtr()), 118 base::Bind(&BluetoothAgentServiceProviderImpl::CancelExported, 119 weak_ptr_factory_.GetWeakPtr())); 120 } 121 122 virtual ~BluetoothAgentServiceProviderImpl() { 123 // Unregister the object path so we can reuse with a new agent. 124 bus_->UnregisterExportedObject(object_path_); 125 } 126 127 private: 128 // Returns true if the current thread is on the origin thread. 129 bool OnOriginThread() { 130 return base::PlatformThread::CurrentId() == origin_thread_id_; 131 } 132 133 // Called by dbus:: when the agent is unregistered from the Bluetooth 134 // daemon, generally at the end of a pairing request. 135 void Release(dbus::MethodCall* method_call, 136 dbus::ExportedObject::ResponseSender response_sender) { 137 DCHECK(OnOriginThread()); 138 DCHECK(delegate_); 139 140 delegate_->Release(); 141 142 dbus::Response* response = dbus::Response::FromMethodCall(method_call); 143 response_sender.Run(response); 144 } 145 146 // Called by dbus:: when the Release method is exported. 147 void ReleaseExported(const std::string& interface_name, 148 const std::string& method_name, 149 bool success) { 150 LOG_IF(WARNING, !success) << "Failed to export " 151 << interface_name << "." << method_name; 152 } 153 154 // Called by dbus:: when the Bluetooth daemon requires a PIN Code for 155 // device authentication. 156 void RequestPinCode(dbus::MethodCall* method_call, 157 dbus::ExportedObject::ResponseSender response_sender) { 158 DCHECK(OnOriginThread()); 159 DCHECK(delegate_); 160 161 dbus::MessageReader reader(method_call); 162 dbus::ObjectPath device_path; 163 if (!reader.PopObjectPath(&device_path)) { 164 LOG(WARNING) << "RequestPinCode called with incorrect paramters: " 165 << method_call->ToString(); 166 return; 167 } 168 169 Delegate::PinCodeCallback callback = base::Bind( 170 &BluetoothAgentServiceProviderImpl::OnPinCode, 171 weak_ptr_factory_.GetWeakPtr(), 172 method_call, 173 response_sender); 174 175 delegate_->RequestPinCode(device_path, callback); 176 } 177 178 // Called by dbus:: when the RequestPinCode method is exported. 179 void RequestPinCodeExported(const std::string& interface_name, 180 const std::string& method_name, 181 bool success) { 182 LOG_IF(WARNING, !success) << "Failed to export " 183 << interface_name << "." << method_name; 184 } 185 186 // Called by dbus:: when the Bluetooth daemon requires a Passkey for 187 // device authentication. 188 void RequestPasskey(dbus::MethodCall* method_call, 189 dbus::ExportedObject::ResponseSender response_sender) { 190 DCHECK(OnOriginThread()); 191 DCHECK(delegate_); 192 193 dbus::MessageReader reader(method_call); 194 dbus::ObjectPath device_path; 195 if (!reader.PopObjectPath(&device_path)) { 196 LOG(WARNING) << "RequestPasskey called with incorrect paramters: " 197 << method_call->ToString(); 198 return; 199 } 200 201 Delegate::PasskeyCallback callback = base::Bind( 202 &BluetoothAgentServiceProviderImpl::OnPasskey, 203 weak_ptr_factory_.GetWeakPtr(), 204 method_call, 205 response_sender); 206 207 delegate_->RequestPasskey(device_path, callback); 208 } 209 210 // Called by dbus:: when the RequestPasskey method is exported. 211 void RequestPasskeyExported(const std::string& interface_name, 212 const std::string& method_name, 213 bool success) { 214 LOG_IF(WARNING, !success) << "Failed to export " 215 << interface_name << "." << method_name; 216 } 217 218 // Called by dbus:: when the Bluetooth daemon requires that the user 219 // enter a PIN Code into the remote device so that it may be 220 // authenticated. 221 void DisplayPinCode(dbus::MethodCall* method_call, 222 dbus::ExportedObject::ResponseSender response_sender) { 223 DCHECK(OnOriginThread()); 224 DCHECK(delegate_); 225 226 dbus::MessageReader reader(method_call); 227 dbus::ObjectPath device_path; 228 std::string pincode; 229 if (!reader.PopObjectPath(&device_path) || 230 !reader.PopString(&pincode)) { 231 LOG(WARNING) << "DisplayPinCode called with incorrect paramters: " 232 << method_call->ToString(); 233 return; 234 } 235 236 delegate_->DisplayPinCode(device_path, pincode); 237 238 dbus::Response* response = dbus::Response::FromMethodCall(method_call); 239 response_sender.Run(response); 240 } 241 242 // Called by dbus:: when the DisplayPinCode method is exported. 243 void DisplayPinCodeExported(const std::string& interface_name, 244 const std::string& method_name, 245 bool success) { 246 LOG_IF(WARNING, !success) << "Failed to export " 247 << interface_name << "." << method_name; 248 } 249 250 // Called by dbus:: when the Bluetooth daemon requires that the user 251 // enter a Passkey into the remote device so that it may be 252 // authenticated. 253 void DisplayPasskey(dbus::MethodCall* method_call, 254 dbus::ExportedObject::ResponseSender response_sender) { 255 DCHECK(OnOriginThread()); 256 DCHECK(delegate_); 257 258 dbus::MessageReader reader(method_call); 259 dbus::ObjectPath device_path; 260 uint32 passkey; 261 if (!reader.PopObjectPath(&device_path) || 262 !reader.PopUint32(&passkey)) { 263 LOG(WARNING) << "DisplayPasskey called with incorrect paramters: " 264 << method_call->ToString(); 265 return; 266 } 267 268 delegate_->DisplayPasskey(device_path, passkey); 269 270 dbus::Response* response = dbus::Response::FromMethodCall(method_call); 271 response_sender.Run(response); 272 } 273 274 // Called by dbus:: when the DisplayPasskey method is exported. 275 void DisplayPasskeyExported(const std::string& interface_name, 276 const std::string& method_name, 277 bool success) { 278 LOG_IF(WARNING, !success) << "Failed to export " 279 << interface_name << "." << method_name; 280 } 281 282 // Called by dbus:: when the Bluetooth daemon requires that the user 283 // confirm that a Passkey is displayed on the screen of the remote 284 // device so that it may be authenticated. 285 void RequestConfirmation( 286 dbus::MethodCall* method_call, 287 dbus::ExportedObject::ResponseSender response_sender) { 288 DCHECK(OnOriginThread()); 289 DCHECK(delegate_); 290 291 dbus::MessageReader reader(method_call); 292 dbus::ObjectPath device_path; 293 uint32 passkey; 294 if (!reader.PopObjectPath(&device_path) || 295 !reader.PopUint32(&passkey)) { 296 LOG(WARNING) << "RequestConfirmation called with incorrect paramters: " 297 << method_call->ToString(); 298 return; 299 } 300 301 Delegate::ConfirmationCallback callback = base::Bind( 302 &BluetoothAgentServiceProviderImpl::OnConfirmation, 303 weak_ptr_factory_.GetWeakPtr(), 304 method_call, 305 response_sender); 306 307 delegate_->RequestConfirmation(device_path, passkey, callback); 308 } 309 310 // Called by dbus:: when the RequestConfirmation method is exported. 311 void RequestConfirmationExported(const std::string& interface_name, 312 const std::string& method_name, 313 bool success) { 314 LOG_IF(WARNING, !success) << "Failed to export " 315 << interface_name << "." << method_name; 316 } 317 318 // Called by dbus:: when the Bluetooth daemon requires that the user 319 // confirm that that a remote device is authorized to connect to a service 320 // UUID. 321 void Authorize(dbus::MethodCall* method_call, 322 dbus::ExportedObject::ResponseSender response_sender) { 323 DCHECK(OnOriginThread()); 324 DCHECK(delegate_); 325 326 dbus::MessageReader reader(method_call); 327 dbus::ObjectPath device_path; 328 std::string uuid; 329 if (!reader.PopObjectPath(&device_path) || 330 !reader.PopString(&uuid)) { 331 LOG(WARNING) << "Authorize called with incorrect paramters: " 332 << method_call->ToString(); 333 return; 334 } 335 336 Delegate::ConfirmationCallback callback = base::Bind( 337 &BluetoothAgentServiceProviderImpl::OnConfirmation, 338 weak_ptr_factory_.GetWeakPtr(), 339 method_call, 340 response_sender); 341 342 delegate_->Authorize(device_path, uuid, callback); 343 } 344 345 // Called by dbus:: when the Authorize method is exported. 346 void AuthorizeExported(const std::string& interface_name, 347 const std::string& method_name, 348 bool success) { 349 LOG_IF(WARNING, !success) << "Failed to export " 350 << interface_name << "." << method_name; 351 } 352 353 // Called by dbus:: when the Bluetooth daemon requires that the user 354 // confirm that the adapter may change mode. 355 void ConfirmModeChange(dbus::MethodCall* method_call, 356 dbus::ExportedObject::ResponseSender response_sender) { 357 DCHECK(OnOriginThread()); 358 DCHECK(delegate_); 359 360 dbus::MessageReader reader(method_call); 361 std::string mode_str; 362 if (!reader.PopString(&mode_str)) { 363 LOG(WARNING) << "ConfirmModeChange called with incorrect paramters: " 364 << method_call->ToString(); 365 return; 366 } 367 368 Delegate::Mode mode; 369 if (mode_str == kModeOff) { 370 mode = Delegate::OFF; 371 } else if (mode_str == kModeConnectable) { 372 mode = Delegate::CONNECTABLE; 373 } else if (mode_str == kModeDiscoverable) { 374 mode = Delegate::DISCOVERABLE; 375 } else { 376 LOG(WARNING) << "ConfirmModeChange called with unknown mode: " 377 << mode_str; 378 return; 379 } 380 381 Delegate::ConfirmationCallback callback = base::Bind( 382 &BluetoothAgentServiceProviderImpl::OnConfirmation, 383 weak_ptr_factory_.GetWeakPtr(), 384 method_call, 385 response_sender); 386 387 delegate_->ConfirmModeChange(mode, callback); 388 } 389 390 // Called by dbus:: when the ConfirmModeChange method is exported. 391 void ConfirmModeChangeExported(const std::string& interface_name, 392 const std::string& method_name, 393 bool success) { 394 LOG_IF(WARNING, !success) << "Failed to export " 395 << interface_name << "." << method_name; 396 } 397 398 // Called by dbus:: when the request failed before a reply was returned 399 // from the device. 400 void Cancel(dbus::MethodCall* method_call, 401 dbus::ExportedObject::ResponseSender response_sender) { 402 DCHECK(OnOriginThread()); 403 DCHECK(delegate_); 404 405 delegate_->Cancel(); 406 407 dbus::Response* response = dbus::Response::FromMethodCall(method_call); 408 response_sender.Run(response); 409 } 410 411 // Called by dbus:: when the Cancel method is exported. 412 void CancelExported(const std::string& interface_name, 413 const std::string& method_name, 414 bool success) { 415 LOG_IF(WARNING, !success) << "Failed to export " 416 << interface_name << "." << method_name; 417 } 418 419 // Called by the Delegate to response to a method requesting a PIN code. 420 void OnPinCode(dbus::MethodCall* method_call, 421 dbus::ExportedObject::ResponseSender response_sender, 422 Delegate::Status status, 423 const std::string& pincode) { 424 DCHECK(OnOriginThread()); 425 426 switch (status) { 427 case Delegate::SUCCESS: { 428 dbus::Response* response = dbus::Response::FromMethodCall(method_call); 429 dbus::MessageWriter writer(response); 430 writer.AppendString(pincode); 431 response_sender.Run(response); 432 break; 433 } 434 case Delegate::REJECTED: { 435 dbus::ErrorResponse* response = dbus::ErrorResponse::FromMethodCall( 436 method_call, bluetooth_agent::kErrorRejected, "rejected"); 437 response_sender.Run(response); 438 break; 439 } 440 case Delegate::CANCELLED: { 441 dbus::ErrorResponse* response = dbus::ErrorResponse::FromMethodCall( 442 method_call, bluetooth_agent::kErrorCanceled, "canceled"); 443 response_sender.Run(response); 444 break; 445 } 446 default: 447 NOTREACHED() << "Unexpected status code from delegate: " << status; 448 } 449 } 450 451 // Called by the Delegate to response to a method requesting a Passkey. 452 void OnPasskey(dbus::MethodCall* method_call, 453 dbus::ExportedObject::ResponseSender response_sender, 454 Delegate::Status status, 455 uint32 passkey) { 456 DCHECK(OnOriginThread()); 457 458 switch (status) { 459 case Delegate::SUCCESS: { 460 dbus::Response* response = dbus::Response::FromMethodCall(method_call); 461 dbus::MessageWriter writer(response); 462 writer.AppendUint32(passkey); 463 response_sender.Run(response); 464 break; 465 } 466 case Delegate::REJECTED: { 467 dbus::ErrorResponse* response = dbus::ErrorResponse::FromMethodCall( 468 method_call, bluetooth_agent::kErrorRejected, "rejected"); 469 response_sender.Run(response); 470 break; 471 } 472 case Delegate::CANCELLED: { 473 dbus::ErrorResponse* response = dbus::ErrorResponse::FromMethodCall( 474 method_call, bluetooth_agent::kErrorCanceled, "canceled"); 475 response_sender.Run(response); 476 break; 477 } 478 default: 479 NOTREACHED() << "Unexpected status code from delegate: " << status; 480 } 481 } 482 483 // Called by the Delegate in response to a method requiring confirmation. 484 void OnConfirmation(dbus::MethodCall* method_call, 485 dbus::ExportedObject::ResponseSender response_sender, 486 Delegate::Status status) { 487 DCHECK(OnOriginThread()); 488 489 switch (status) { 490 case Delegate::SUCCESS: { 491 dbus::Response* response = dbus::Response::FromMethodCall(method_call); 492 response_sender.Run(response); 493 break; 494 } 495 case Delegate::REJECTED: { 496 dbus::ErrorResponse* response = dbus::ErrorResponse::FromMethodCall( 497 method_call, bluetooth_agent::kErrorRejected, "rejected"); 498 response_sender.Run(response); 499 break; 500 } 501 case Delegate::CANCELLED: { 502 dbus::ErrorResponse* response = dbus::ErrorResponse::FromMethodCall( 503 method_call, bluetooth_agent::kErrorCanceled, "canceled"); 504 response_sender.Run(response); 505 break; 506 } 507 default: 508 NOTREACHED() << "Unexpected status code from delegate: " << status; 509 } 510 } 511 512 // Origin thread (i.e. the UI thread in production). 513 base::PlatformThreadId origin_thread_id_; 514 515 // D-Bus bus object is exported on, not owned by this object and must 516 // outlive it. 517 dbus::Bus* bus_; 518 519 // All incoming method calls are passed on to the Delegate and a callback 520 // passed to generate the reply. |delegate_| is generally the object that 521 // owns this one, and must outlive it. 522 Delegate* delegate_; 523 524 // D-Bus object path of object we are exporting, kept so we can unregister 525 // again in our destructor. 526 dbus::ObjectPath object_path_; 527 528 // D-Bus object we are exporting, owned by this object. 529 scoped_refptr<dbus::ExportedObject> exported_object_; 530 531 // Weak pointer factory for generating 'this' pointers that might live longer 532 // than we do. 533 // Note: This should remain the last member so it'll be destroyed and 534 // invalidate its weak pointers before any other members are destroyed. 535 base::WeakPtrFactory<BluetoothAgentServiceProviderImpl> weak_ptr_factory_; 536 537 DISALLOW_COPY_AND_ASSIGN(BluetoothAgentServiceProviderImpl); 538}; 539 540// The BluetoothAgentServiceProvider implementation used on Linux desktop, 541// which does nothing. 542class BluetoothAgentServiceProviderStubImpl 543 : public BluetoothAgentServiceProvider { 544 public: 545 explicit BluetoothAgentServiceProviderStubImpl(Delegate* delegate_) { 546 } 547 548 virtual ~BluetoothAgentServiceProviderStubImpl() { 549 } 550}; 551 552BluetoothAgentServiceProvider::BluetoothAgentServiceProvider() { 553} 554 555BluetoothAgentServiceProvider::~BluetoothAgentServiceProvider() { 556} 557 558// static 559BluetoothAgentServiceProvider* BluetoothAgentServiceProvider::Create( 560 dbus::Bus* bus, 561 const dbus::ObjectPath& object_path, 562 Delegate* delegate) { 563 if (base::chromeos::IsRunningOnChromeOS()) { 564 return new BluetoothAgentServiceProviderImpl(bus, object_path, delegate); 565 } else { 566 return new BluetoothAgentServiceProviderStubImpl(delegate); 567 } 568} 569 570} // namespace chromeos 571