OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "device/bluetooth/bluetooth_adapter_chromeos.h" | 5 #include "device/bluetooth/bluetooth_adapter_chromeos.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
12 #include "base/sys_info.h" | 12 #include "base/sys_info.h" |
13 #include "chromeos/dbus/bluetooth_adapter_client.h" | 13 #include "chromeos/dbus/bluetooth_adapter_client.h" |
| 14 #include "chromeos/dbus/bluetooth_agent_manager_client.h" |
| 15 #include "chromeos/dbus/bluetooth_agent_service_provider.h" |
14 #include "chromeos/dbus/bluetooth_device_client.h" | 16 #include "chromeos/dbus/bluetooth_device_client.h" |
15 #include "chromeos/dbus/bluetooth_input_client.h" | 17 #include "chromeos/dbus/bluetooth_input_client.h" |
16 #include "chromeos/dbus/dbus_thread_manager.h" | 18 #include "chromeos/dbus/dbus_thread_manager.h" |
17 #include "device/bluetooth/bluetooth_device.h" | 19 #include "device/bluetooth/bluetooth_device.h" |
18 #include "device/bluetooth/bluetooth_device_chromeos.h" | 20 #include "device/bluetooth/bluetooth_device_chromeos.h" |
| 21 #include "third_party/cros_system_api/dbus/service_constants.h" |
19 | 22 |
20 using device::BluetoothAdapter; | 23 using device::BluetoothAdapter; |
21 using device::BluetoothDevice; | 24 using device::BluetoothDevice; |
22 | 25 |
| 26 namespace { |
| 27 |
| 28 // The agent path is relatively meaningless since BlueZ only supports one |
| 29 // at time and will fail in an attempt to register another with "Already Exists" |
| 30 const char kAgentPath[] = "/org/chromium/bluetooth_agent"; |
| 31 |
| 32 // Histogram enumerations for pairing methods. |
| 33 enum UMAPairingMethod { |
| 34 UMA_PAIRING_METHOD_NONE, |
| 35 UMA_PAIRING_METHOD_REQUEST_PINCODE, |
| 36 UMA_PAIRING_METHOD_REQUEST_PASSKEY, |
| 37 UMA_PAIRING_METHOD_DISPLAY_PINCODE, |
| 38 UMA_PAIRING_METHOD_DISPLAY_PASSKEY, |
| 39 UMA_PAIRING_METHOD_CONFIRM_PASSKEY, |
| 40 // NOTE: Add new pairing methods immediately above this line. Make sure to |
| 41 // update the enum list in tools/histogram/histograms.xml accordinly. |
| 42 UMA_PAIRING_METHOD_COUNT |
| 43 }; |
| 44 |
| 45 void OnUnregisterAgentError(const std::string& error_name, |
| 46 const std::string& error_message) { |
| 47 LOG(WARNING) << "Failed to unregister pairing agent: " |
| 48 << error_name << ": " << error_message; |
| 49 } |
| 50 |
| 51 } // namespace |
| 52 |
23 namespace chromeos { | 53 namespace chromeos { |
24 | 54 |
25 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS() | 55 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS() |
26 : weak_ptr_factory_(this) { | 56 : weak_ptr_factory_(this) { |
27 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this); | 57 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this); |
28 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this); | 58 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this); |
29 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this); | 59 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this); |
30 | 60 |
31 std::vector<dbus::ObjectPath> object_paths = | 61 std::vector<dbus::ObjectPath> object_paths = |
32 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters(); | 62 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters(); |
33 | 63 |
34 if (!object_paths.empty()) { | 64 if (!object_paths.empty()) { |
35 VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available."; | 65 VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available."; |
36 SetAdapter(object_paths[0]); | 66 SetAdapter(object_paths[0]); |
37 } | 67 } |
| 68 |
| 69 // The agent path is relatively meaningless since BlueZ only supports |
| 70 // one per application at a time. |
| 71 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus(); |
| 72 agent_.reset(BluetoothAgentServiceProvider::Create( |
| 73 system_bus, dbus::ObjectPath(kAgentPath), this)); |
| 74 DCHECK(agent_.get()); |
| 75 |
| 76 VLOG(1) << "Registering pairing agent"; |
| 77 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()-> |
| 78 RegisterAgent( |
| 79 dbus::ObjectPath(kAgentPath), |
| 80 bluetooth_agent_manager::kKeyboardDisplayCapability, |
| 81 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent, |
| 82 weak_ptr_factory_.GetWeakPtr()), |
| 83 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError, |
| 84 weak_ptr_factory_.GetWeakPtr())); |
38 } | 85 } |
39 | 86 |
40 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() { | 87 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() { |
41 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this); | 88 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this); |
42 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this); | 89 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this); |
43 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this); | 90 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this); |
| 91 |
| 92 // Clean up after ourselves. Ignore failures since the class is going away. |
| 93 VLOG(1) << "Unregistering pairing agent"; |
| 94 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()-> |
| 95 UnregisterAgent( |
| 96 dbus::ObjectPath(kAgentPath), |
| 97 base::Bind(&base::DoNothing), |
| 98 base::Bind(&OnUnregisterAgentError)); |
44 } | 99 } |
45 | 100 |
46 void BluetoothAdapterChromeOS::AddObserver( | 101 void BluetoothAdapterChromeOS::AddObserver( |
47 BluetoothAdapter::Observer* observer) { | 102 BluetoothAdapter::Observer* observer) { |
48 DCHECK(observer); | 103 DCHECK(observer); |
49 observers_.AddObserver(observer); | 104 observers_.AddObserver(observer); |
50 } | 105 } |
51 | 106 |
52 void BluetoothAdapterChromeOS::RemoveObserver( | 107 void BluetoothAdapterChromeOS::RemoveObserver( |
53 BluetoothAdapter::Observer* observer) { | 108 BluetoothAdapter::Observer* observer) { |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
270 GetProperties(object_path); | 325 GetProperties(object_path); |
271 | 326 |
272 // Properties structure can be removed, which triggers a change in the | 327 // Properties structure can be removed, which triggers a change in the |
273 // BluetoothDevice::IsConnectable() property, as does a change in the | 328 // BluetoothDevice::IsConnectable() property, as does a change in the |
274 // actual reconnect_mode property. | 329 // actual reconnect_mode property. |
275 if (!properties || | 330 if (!properties || |
276 property_name == properties->reconnect_mode.name()) | 331 property_name == properties->reconnect_mode.name()) |
277 NotifyDeviceChanged(device_chromeos); | 332 NotifyDeviceChanged(device_chromeos); |
278 } | 333 } |
279 | 334 |
| 335 void BluetoothAdapterChromeOS::Release() { |
| 336 DCHECK(agent_.get()); |
| 337 VLOG(1) << "Release"; |
| 338 |
| 339 // Called after we unregister the pairing agent, e.g. when changing I/O |
| 340 // capabilities. Nothing much to be done right now. |
| 341 } |
| 342 |
| 343 void BluetoothAdapterChromeOS::RequestPinCode( |
| 344 const dbus::ObjectPath& device_path, |
| 345 const PinCodeCallback& callback) { |
| 346 DCHECK(agent_.get()); |
| 347 VLOG(1) << device_path.value() << ": RequestPinCode"; |
| 348 |
| 349 BluetoothDeviceChromeOS* device_chromeos; |
| 350 PairingContext* pairing_context; |
| 351 if (!GetDeviceAndPairingContext(device_path, |
| 352 &device_chromeos, &pairing_context)) |
| 353 return; |
| 354 |
| 355 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", |
| 356 UMA_PAIRING_METHOD_REQUEST_PINCODE, |
| 357 UMA_PAIRING_METHOD_COUNT); |
| 358 |
| 359 DCHECK(pairing_context->pincode_callback_.is_null()); |
| 360 pairing_context->pincode_callback_ = callback; |
| 361 pairing_context->pairing_delegate_->RequestPinCode(device_chromeos); |
| 362 pairing_context->pairing_delegate_used_ = true; |
| 363 } |
| 364 |
| 365 void BluetoothAdapterChromeOS::DisplayPinCode( |
| 366 const dbus::ObjectPath& device_path, |
| 367 const std::string& pincode) { |
| 368 DCHECK(agent_.get()); |
| 369 VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode; |
| 370 |
| 371 BluetoothDeviceChromeOS* device_chromeos; |
| 372 PairingContext* pairing_context; |
| 373 if (!GetDeviceAndPairingContext(device_path, |
| 374 &device_chromeos, &pairing_context)) |
| 375 return; |
| 376 |
| 377 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", |
| 378 UMA_PAIRING_METHOD_DISPLAY_PINCODE, |
| 379 UMA_PAIRING_METHOD_COUNT); |
| 380 |
| 381 pairing_context->pairing_delegate_->DisplayPinCode(device_chromeos, pincode); |
| 382 pairing_context->pairing_delegate_used_ = true; |
| 383 } |
| 384 |
| 385 void BluetoothAdapterChromeOS::RequestPasskey( |
| 386 const dbus::ObjectPath& device_path, |
| 387 const PasskeyCallback& callback) { |
| 388 DCHECK(agent_.get()); |
| 389 VLOG(1) << device_path.value() << ": RequestPasskey"; |
| 390 |
| 391 BluetoothDeviceChromeOS* device_chromeos; |
| 392 PairingContext* pairing_context; |
| 393 if (!GetDeviceAndPairingContext(device_path, |
| 394 &device_chromeos, &pairing_context)) |
| 395 return; |
| 396 |
| 397 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", |
| 398 UMA_PAIRING_METHOD_REQUEST_PASSKEY, |
| 399 UMA_PAIRING_METHOD_COUNT); |
| 400 |
| 401 DCHECK(pairing_context->passkey_callback_.is_null()); |
| 402 pairing_context->passkey_callback_ = callback; |
| 403 pairing_context->pairing_delegate_->RequestPasskey(device_chromeos); |
| 404 pairing_context->pairing_delegate_used_ = true; |
| 405 } |
| 406 |
| 407 void BluetoothAdapterChromeOS::DisplayPasskey( |
| 408 const dbus::ObjectPath& device_path, |
| 409 uint32 passkey, |
| 410 uint16 entered) { |
| 411 DCHECK(agent_.get()); |
| 412 VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey |
| 413 << " (" << entered << " entered)"; |
| 414 |
| 415 BluetoothDeviceChromeOS* device_chromeos; |
| 416 PairingContext* pairing_context; |
| 417 if (!GetDeviceAndPairingContext(device_path, |
| 418 &device_chromeos, &pairing_context)) |
| 419 return; |
| 420 |
| 421 if (entered == 0) |
| 422 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", |
| 423 UMA_PAIRING_METHOD_DISPLAY_PASSKEY, |
| 424 UMA_PAIRING_METHOD_COUNT); |
| 425 |
| 426 if (entered == 0) |
| 427 pairing_context->pairing_delegate_->DisplayPasskey(device_chromeos, |
| 428 passkey); |
| 429 |
| 430 pairing_context->pairing_delegate_->KeysEntered(device_chromeos, entered); |
| 431 pairing_context->pairing_delegate_used_ = true; |
| 432 } |
| 433 |
| 434 void BluetoothAdapterChromeOS::RequestConfirmation( |
| 435 const dbus::ObjectPath& device_path, |
| 436 uint32 passkey, |
| 437 const ConfirmationCallback& callback) { |
| 438 DCHECK(agent_.get()); |
| 439 VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey; |
| 440 |
| 441 BluetoothDeviceChromeOS* device_chromeos; |
| 442 PairingContext* pairing_context; |
| 443 if (!GetDeviceAndPairingContext(device_path, |
| 444 &device_chromeos, &pairing_context)) |
| 445 return; |
| 446 |
| 447 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", |
| 448 UMA_PAIRING_METHOD_CONFIRM_PASSKEY, |
| 449 UMA_PAIRING_METHOD_COUNT); |
| 450 |
| 451 DCHECK(pairing_context->confirmation_callback_.is_null()); |
| 452 pairing_context->confirmation_callback_ = callback; |
| 453 pairing_context->pairing_delegate_->ConfirmPasskey(device_chromeos, passkey); |
| 454 pairing_context->pairing_delegate_used_ = true; |
| 455 } |
| 456 |
| 457 void BluetoothAdapterChromeOS::RequestAuthorization( |
| 458 const dbus::ObjectPath& device_path, |
| 459 const ConfirmationCallback& callback) { |
| 460 DCHECK(agent_.get()); |
| 461 VLOG(1) << device_path.value() << ": RequestAuthorization"; |
| 462 |
| 463 // TODO(keybuk): implement |
| 464 callback.Run(CANCELLED); |
| 465 } |
| 466 |
| 467 void BluetoothAdapterChromeOS::AuthorizeService( |
| 468 const dbus::ObjectPath& device_path, |
| 469 const std::string& uuid, |
| 470 const ConfirmationCallback& callback) { |
| 471 DCHECK(agent_.get()); |
| 472 VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid; |
| 473 |
| 474 // TODO(keybuk): implement |
| 475 callback.Run(CANCELLED); |
| 476 } |
| 477 |
| 478 void BluetoothAdapterChromeOS::Cancel() { |
| 479 DCHECK(agent_.get()); |
| 480 VLOG(1) << "Cancel"; |
| 481 } |
| 482 |
| 483 bool BluetoothAdapterChromeOS::PairingContext::ExpectingPinCode() const { |
| 484 return !pincode_callback_.is_null(); |
| 485 } |
| 486 |
| 487 bool BluetoothAdapterChromeOS::PairingContext::ExpectingPasskey() const { |
| 488 return !passkey_callback_.is_null(); |
| 489 } |
| 490 |
| 491 bool BluetoothAdapterChromeOS::PairingContext::ExpectingConfirmation() const { |
| 492 return !confirmation_callback_.is_null(); |
| 493 } |
| 494 |
| 495 void BluetoothAdapterChromeOS::PairingContext::SetPinCode( |
| 496 const std::string& pincode) { |
| 497 if (pincode_callback_.is_null()) |
| 498 return; |
| 499 |
| 500 pincode_callback_.Run(SUCCESS, pincode); |
| 501 pincode_callback_.Reset(); |
| 502 } |
| 503 |
| 504 void BluetoothAdapterChromeOS::PairingContext::SetPasskey(uint32 passkey) { |
| 505 if (passkey_callback_.is_null()) |
| 506 return; |
| 507 |
| 508 passkey_callback_.Run(SUCCESS, passkey); |
| 509 passkey_callback_.Reset(); |
| 510 } |
| 511 |
| 512 void BluetoothAdapterChromeOS::PairingContext::ConfirmPairing() { |
| 513 if (confirmation_callback_.is_null()) |
| 514 return; |
| 515 |
| 516 confirmation_callback_.Run(SUCCESS); |
| 517 confirmation_callback_.Reset(); |
| 518 } |
| 519 |
| 520 bool BluetoothAdapterChromeOS::PairingContext::RejectPairing() { |
| 521 return RunPairingCallbacks(REJECTED); |
| 522 } |
| 523 |
| 524 bool BluetoothAdapterChromeOS::PairingContext::CancelPairing() { |
| 525 return RunPairingCallbacks(CANCELLED); |
| 526 } |
| 527 |
| 528 BluetoothAdapterChromeOS::PairingContext::PairingContext( |
| 529 BluetoothDevice::PairingDelegate* pairing_delegate) |
| 530 : pairing_delegate_(pairing_delegate), |
| 531 pairing_delegate_used_(false) { |
| 532 VLOG(1) << "Created PairingContext"; |
| 533 } |
| 534 |
| 535 BluetoothAdapterChromeOS::PairingContext::~PairingContext() { |
| 536 VLOG(1) << "Destroying PairingContext"; |
| 537 |
| 538 if (!pairing_delegate_used_) |
| 539 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", |
| 540 UMA_PAIRING_METHOD_NONE, |
| 541 UMA_PAIRING_METHOD_COUNT); |
| 542 |
| 543 DCHECK(pincode_callback_.is_null()); |
| 544 DCHECK(passkey_callback_.is_null()); |
| 545 DCHECK(confirmation_callback_.is_null()); |
| 546 |
| 547 if (pairing_delegate_used_) |
| 548 pairing_delegate_->DismissDisplayOrConfirm(); |
| 549 pairing_delegate_ = NULL; |
| 550 } |
| 551 |
| 552 bool BluetoothAdapterChromeOS::PairingContext::RunPairingCallbacks( |
| 553 BluetoothAgentServiceProvider::Delegate::Status status) { |
| 554 pairing_delegate_used_ = true; |
| 555 |
| 556 bool callback_run = false; |
| 557 if (!pincode_callback_.is_null()) { |
| 558 pincode_callback_.Run(status, ""); |
| 559 pincode_callback_.Reset(); |
| 560 callback_run = true; |
| 561 } |
| 562 |
| 563 if (!passkey_callback_.is_null()) { |
| 564 passkey_callback_.Run(status, 0); |
| 565 passkey_callback_.Reset(); |
| 566 callback_run = true; |
| 567 } |
| 568 |
| 569 if (!confirmation_callback_.is_null()) { |
| 570 confirmation_callback_.Run(status); |
| 571 confirmation_callback_.Reset(); |
| 572 callback_run = true; |
| 573 } |
| 574 |
| 575 return callback_run; |
| 576 } |
| 577 |
| 578 bool BluetoothAdapterChromeOS::GetDeviceAndPairingContext( |
| 579 const dbus::ObjectPath& object_path, |
| 580 BluetoothDeviceChromeOS** device_chromeos, |
| 581 PairingContext** pairing_context) |
| 582 { |
| 583 *device_chromeos = GetDeviceWithPath(object_path); |
| 584 if (!device_chromeos) { |
| 585 LOG(WARNING) << "Pairing Agent request for unknown device: " |
| 586 << object_path.value(); |
| 587 return false; |
| 588 } |
| 589 |
| 590 *pairing_context = (*device_chromeos)->pairing_context_.get(); |
| 591 if (*pairing_context) |
| 592 return true; |
| 593 |
| 594 // TODO(keybuk): this is the point we need a default pairing delegate, create |
| 595 // a PairingContext with that passed in, set it as the context on the device |
| 596 // and return true. |
| 597 return false; |
| 598 } |
| 599 |
| 600 void BluetoothAdapterChromeOS::OnRegisterAgent() { |
| 601 VLOG(1) << "Pairing agent registered"; |
| 602 } |
| 603 |
| 604 void BluetoothAdapterChromeOS::OnRegisterAgentError( |
| 605 const std::string& error_name, |
| 606 const std::string& error_message) { |
| 607 LOG(WARNING) << ": Failed to register pairing agent: " |
| 608 << error_name << ": " << error_message; |
| 609 |
| 610 agent_.reset(); |
| 611 } |
| 612 |
280 BluetoothDeviceChromeOS* | 613 BluetoothDeviceChromeOS* |
281 BluetoothAdapterChromeOS::GetDeviceWithPath( | 614 BluetoothAdapterChromeOS::GetDeviceWithPath( |
282 const dbus::ObjectPath& object_path) { | 615 const dbus::ObjectPath& object_path) { |
283 for (DevicesMap::iterator iter = devices_.begin(); | 616 for (DevicesMap::iterator iter = devices_.begin(); |
284 iter != devices_.end(); ++iter) { | 617 iter != devices_.end(); ++iter) { |
285 BluetoothDeviceChromeOS* device_chromeos = | 618 BluetoothDeviceChromeOS* device_chromeos = |
286 static_cast<BluetoothDeviceChromeOS*>(iter->second); | 619 static_cast<BluetoothDeviceChromeOS*>(iter->second); |
287 if (device_chromeos->object_path() == object_path) | 620 if (device_chromeos->object_path() == object_path) |
288 return device_chromeos; | 621 return device_chromeos; |
289 } | 622 } |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 void BluetoothAdapterChromeOS::OnStopDiscoveryError( | 765 void BluetoothAdapterChromeOS::OnStopDiscoveryError( |
433 const ErrorCallback& error_callback, | 766 const ErrorCallback& error_callback, |
434 const std::string& error_name, | 767 const std::string& error_name, |
435 const std::string& error_message) { | 768 const std::string& error_message) { |
436 LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: " | 769 LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: " |
437 << error_name << ": " << error_message; | 770 << error_name << ": " << error_message; |
438 error_callback.Run(); | 771 error_callback.Run(); |
439 } | 772 } |
440 | 773 |
441 } // namespace chromeos | 774 } // namespace chromeos |
OLD | NEW |