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 3 // found in the LICENSE file. 4 5 #include "device/bluetooth/bluetooth_adapter_chromeos.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/logging.h" 11 #include "base/metrics/histogram.h" 12 #include "base/sequenced_task_runner.h" 13 #include "base/single_thread_task_runner.h" 14 #include "base/sys_info.h" 15 #include "base/thread_task_runner_handle.h" 16 #include "chromeos/dbus/bluetooth_adapter_client.h" 17 #include "chromeos/dbus/bluetooth_agent_manager_client.h" 18 #include "chromeos/dbus/bluetooth_agent_service_provider.h" 19 #include "chromeos/dbus/bluetooth_device_client.h" 20 #include "chromeos/dbus/bluetooth_input_client.h" 21 #include "chromeos/dbus/dbus_thread_manager.h" 22 #include "device/bluetooth/bluetooth_device.h" 23 #include "device/bluetooth/bluetooth_device_chromeos.h" 24 #include "device/bluetooth/bluetooth_pairing_chromeos.h" 25 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h" 26 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h" 27 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h" 28 #include "device/bluetooth/bluetooth_socket_chromeos.h" 29 #include "device/bluetooth/bluetooth_socket_thread.h" 30 #include "device/bluetooth/bluetooth_uuid.h" 31 #include "third_party/cros_system_api/dbus/service_constants.h" 32 33 using device::BluetoothAdapter; 34 using device::BluetoothDevice; 35 using device::BluetoothSocket; 36 using device::BluetoothUUID; 37 38 namespace { 39 40 // The agent path is relatively meaningless since BlueZ only permits one to 41 // exist per D-Bus connection, it just has to be unique within Chromium. 42 const char kAgentPath[] = "/org/chromium/bluetooth_agent"; 43 44 void OnUnregisterAgentError(const std::string& error_name, 45 const std::string& error_message) { 46 // It's okay if the agent didn't exist, it means we never saw an adapter. 47 if (error_name == bluetooth_agent_manager::kErrorDoesNotExist) 48 return; 49 50 LOG(WARNING) << "Failed to unregister pairing agent: " 51 << error_name << ": " << error_message; 52 } 53 54 } // namespace 55 56 namespace device { 57 58 // static 59 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter( 60 const InitCallback& init_callback) { 61 return chromeos::BluetoothAdapterChromeOS::CreateAdapter(); 62 } 63 64 } 65 66 namespace chromeos { 67 68 // static 69 base::WeakPtr<BluetoothAdapter> BluetoothAdapterChromeOS::CreateAdapter() { 70 BluetoothAdapterChromeOS* adapter = new BluetoothAdapterChromeOS(); 71 return adapter->weak_ptr_factory_.GetWeakPtr(); 72 } 73 74 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS() 75 : num_discovery_sessions_(0), 76 discovery_request_pending_(false), 77 weak_ptr_factory_(this) { 78 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); 79 socket_thread_ = device::BluetoothSocketThread::Get(); 80 81 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this); 82 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this); 83 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this); 84 85 // Register the pairing agent. 86 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus(); 87 agent_.reset(BluetoothAgentServiceProvider::Create( 88 system_bus, dbus::ObjectPath(kAgentPath), this)); 89 DCHECK(agent_.get()); 90 91 std::vector<dbus::ObjectPath> object_paths = 92 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters(); 93 94 if (!object_paths.empty()) { 95 VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available."; 96 SetAdapter(object_paths[0]); 97 } 98 } 99 100 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() { 101 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this); 102 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this); 103 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this); 104 105 VLOG(1) << "Unregistering pairing agent"; 106 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()-> 107 UnregisterAgent( 108 dbus::ObjectPath(kAgentPath), 109 base::Bind(&base::DoNothing), 110 base::Bind(&OnUnregisterAgentError)); 111 } 112 113 void BluetoothAdapterChromeOS::AddObserver( 114 BluetoothAdapter::Observer* observer) { 115 DCHECK(observer); 116 observers_.AddObserver(observer); 117 } 118 119 void BluetoothAdapterChromeOS::RemoveObserver( 120 BluetoothAdapter::Observer* observer) { 121 DCHECK(observer); 122 observers_.RemoveObserver(observer); 123 } 124 125 std::string BluetoothAdapterChromeOS::GetAddress() const { 126 if (!IsPresent()) 127 return std::string(); 128 129 BluetoothAdapterClient::Properties* properties = 130 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 131 GetProperties(object_path_); 132 DCHECK(properties); 133 134 return BluetoothDevice::CanonicalizeAddress(properties->address.value()); 135 } 136 137 std::string BluetoothAdapterChromeOS::GetName() const { 138 if (!IsPresent()) 139 return std::string(); 140 141 BluetoothAdapterClient::Properties* properties = 142 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 143 GetProperties(object_path_); 144 DCHECK(properties); 145 146 return properties->alias.value(); 147 } 148 149 void BluetoothAdapterChromeOS::SetName(const std::string& name, 150 const base::Closure& callback, 151 const ErrorCallback& error_callback) { 152 if (!IsPresent()) 153 error_callback.Run(); 154 155 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 156 GetProperties(object_path_)->alias.Set( 157 name, 158 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted, 159 weak_ptr_factory_.GetWeakPtr(), 160 callback, 161 error_callback)); 162 } 163 164 bool BluetoothAdapterChromeOS::IsInitialized() const { 165 return true; 166 } 167 168 bool BluetoothAdapterChromeOS::IsPresent() const { 169 return !object_path_.value().empty(); 170 } 171 172 bool BluetoothAdapterChromeOS::IsPowered() const { 173 if (!IsPresent()) 174 return false; 175 176 BluetoothAdapterClient::Properties* properties = 177 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 178 GetProperties(object_path_); 179 180 return properties->powered.value(); 181 } 182 183 void BluetoothAdapterChromeOS::SetPowered( 184 bool powered, 185 const base::Closure& callback, 186 const ErrorCallback& error_callback) { 187 if (!IsPresent()) 188 error_callback.Run(); 189 190 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 191 GetProperties(object_path_)->powered.Set( 192 powered, 193 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted, 194 weak_ptr_factory_.GetWeakPtr(), 195 callback, 196 error_callback)); 197 } 198 199 bool BluetoothAdapterChromeOS::IsDiscoverable() const { 200 if (!IsPresent()) 201 return false; 202 203 BluetoothAdapterClient::Properties* properties = 204 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 205 GetProperties(object_path_); 206 207 return properties->discoverable.value(); 208 } 209 210 void BluetoothAdapterChromeOS::SetDiscoverable( 211 bool discoverable, 212 const base::Closure& callback, 213 const ErrorCallback& error_callback) { 214 if (!IsPresent()) 215 error_callback.Run(); 216 217 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 218 GetProperties(object_path_)->discoverable.Set( 219 discoverable, 220 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable, 221 weak_ptr_factory_.GetWeakPtr(), 222 callback, 223 error_callback)); 224 } 225 226 bool BluetoothAdapterChromeOS::IsDiscovering() const { 227 if (!IsPresent()) 228 return false; 229 230 BluetoothAdapterClient::Properties* properties = 231 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 232 GetProperties(object_path_); 233 234 return properties->discovering.value(); 235 } 236 237 void BluetoothAdapterChromeOS::CreateRfcommService( 238 const BluetoothUUID& uuid, 239 const ServiceOptions& options, 240 const CreateServiceCallback& callback, 241 const CreateServiceErrorCallback& error_callback) { 242 VLOG(1) << object_path_.value() << ": Creating RFCOMM service: " 243 << uuid.canonical_value(); 244 scoped_refptr<BluetoothSocketChromeOS> socket = 245 BluetoothSocketChromeOS::CreateBluetoothSocket( 246 ui_task_runner_, socket_thread_); 247 socket->Listen(this, 248 BluetoothSocketChromeOS::kRfcomm, 249 uuid, 250 options, 251 base::Bind(callback, socket), 252 error_callback); 253 } 254 255 void BluetoothAdapterChromeOS::CreateL2capService( 256 const BluetoothUUID& uuid, 257 const ServiceOptions& options, 258 const CreateServiceCallback& callback, 259 const CreateServiceErrorCallback& error_callback) { 260 VLOG(1) << object_path_.value() << ": Creating L2CAP service: " 261 << uuid.canonical_value(); 262 scoped_refptr<BluetoothSocketChromeOS> socket = 263 BluetoothSocketChromeOS::CreateBluetoothSocket( 264 ui_task_runner_, socket_thread_); 265 socket->Listen(this, 266 BluetoothSocketChromeOS::kL2cap, 267 uuid, 268 options, 269 base::Bind(callback, socket), 270 error_callback); 271 } 272 273 void BluetoothAdapterChromeOS::RemovePairingDelegateInternal( 274 BluetoothDevice::PairingDelegate* pairing_delegate) { 275 // Before removing a pairing delegate make sure that there aren't any devices 276 // currently using it; if there are, clear the pairing context which will 277 // make any responses no-ops. 278 for (DevicesMap::iterator iter = devices_.begin(); 279 iter != devices_.end(); ++iter) { 280 BluetoothDeviceChromeOS* device_chromeos = 281 static_cast<BluetoothDeviceChromeOS*>(iter->second); 282 283 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing(); 284 if (pairing && pairing->GetPairingDelegate() == pairing_delegate) 285 device_chromeos->EndPairing(); 286 } 287 } 288 289 void BluetoothAdapterChromeOS::AdapterAdded( 290 const dbus::ObjectPath& object_path) { 291 // Set the adapter to the newly added adapter only if no adapter is present. 292 if (!IsPresent()) 293 SetAdapter(object_path); 294 } 295 296 void BluetoothAdapterChromeOS::AdapterRemoved( 297 const dbus::ObjectPath& object_path) { 298 if (object_path == object_path_) 299 RemoveAdapter(); 300 } 301 302 void BluetoothAdapterChromeOS::AdapterPropertyChanged( 303 const dbus::ObjectPath& object_path, 304 const std::string& property_name) { 305 if (object_path != object_path_) 306 return; 307 308 BluetoothAdapterClient::Properties* properties = 309 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 310 GetProperties(object_path_); 311 312 if (property_name == properties->powered.name()) 313 PoweredChanged(properties->powered.value()); 314 else if (property_name == properties->discoverable.name()) 315 DiscoverableChanged(properties->discoverable.value()); 316 else if (property_name == properties->discovering.name()) 317 DiscoveringChanged(properties->discovering.value()); 318 } 319 320 void BluetoothAdapterChromeOS::DeviceAdded( 321 const dbus::ObjectPath& object_path) { 322 BluetoothDeviceClient::Properties* properties = 323 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 324 GetProperties(object_path); 325 if (properties->adapter.value() != object_path_) 326 return; 327 328 BluetoothDeviceChromeOS* device_chromeos = 329 new BluetoothDeviceChromeOS(this, 330 object_path, 331 ui_task_runner_, 332 socket_thread_); 333 DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end()); 334 335 devices_[device_chromeos->GetAddress()] = device_chromeos; 336 337 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, 338 DeviceAdded(this, device_chromeos)); 339 } 340 341 void BluetoothAdapterChromeOS::DeviceRemoved( 342 const dbus::ObjectPath& object_path) { 343 for (DevicesMap::iterator iter = devices_.begin(); 344 iter != devices_.end(); ++iter) { 345 BluetoothDeviceChromeOS* device_chromeos = 346 static_cast<BluetoothDeviceChromeOS*>(iter->second); 347 if (device_chromeos->object_path() == object_path) { 348 devices_.erase(iter); 349 350 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, 351 DeviceRemoved(this, device_chromeos)); 352 delete device_chromeos; 353 return; 354 } 355 } 356 } 357 358 void BluetoothAdapterChromeOS::DevicePropertyChanged( 359 const dbus::ObjectPath& object_path, 360 const std::string& property_name) { 361 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path); 362 if (!device_chromeos) 363 return; 364 365 BluetoothDeviceClient::Properties* properties = 366 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 367 GetProperties(object_path); 368 369 if (property_name == properties->bluetooth_class.name() || 370 property_name == properties->address.name() || 371 property_name == properties->alias.name() || 372 property_name == properties->paired.name() || 373 property_name == properties->trusted.name() || 374 property_name == properties->connected.name() || 375 property_name == properties->uuids.name() || 376 property_name == properties->rssi.name() || 377 property_name == properties->connection_rssi.name() || 378 property_name == properties->connection_tx_power.name()) 379 NotifyDeviceChanged(device_chromeos); 380 381 // When a device becomes paired, mark it as trusted so that the user does 382 // not need to approve every incoming connection 383 if (property_name == properties->paired.name() && 384 properties->paired.value() && !properties->trusted.value()) 385 device_chromeos->SetTrusted(); 386 387 // UMA connection counting 388 if (property_name == properties->connected.name()) { 389 // PlayStation joystick tries to reconnect after disconnection from USB. 390 // If it is still not trusted, set it, so it becomes available on the 391 // list of known devices. 392 if (properties->connected.value() && device_chromeos->IsTrustable() && 393 !properties->trusted.value()) 394 device_chromeos->SetTrusted(); 395 396 int count = 0; 397 398 for (DevicesMap::iterator iter = devices_.begin(); 399 iter != devices_.end(); ++iter) { 400 if (iter->second->IsPaired() && iter->second->IsConnected()) 401 ++count; 402 } 403 404 UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count); 405 } 406 } 407 408 void BluetoothAdapterChromeOS::InputPropertyChanged( 409 const dbus::ObjectPath& object_path, 410 const std::string& property_name) { 411 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path); 412 if (!device_chromeos) 413 return; 414 415 BluetoothInputClient::Properties* properties = 416 DBusThreadManager::Get()->GetBluetoothInputClient()-> 417 GetProperties(object_path); 418 419 // Properties structure can be removed, which triggers a change in the 420 // BluetoothDevice::IsConnectable() property, as does a change in the 421 // actual reconnect_mode property. 422 if (!properties || 423 property_name == properties->reconnect_mode.name()) 424 NotifyDeviceChanged(device_chromeos); 425 } 426 427 void BluetoothAdapterChromeOS::Released() { 428 DCHECK(agent_.get()); 429 VLOG(1) << "Release"; 430 431 // Called after we unregister the pairing agent, e.g. when changing I/O 432 // capabilities. Nothing much to be done right now. 433 } 434 435 void BluetoothAdapterChromeOS::RequestPinCode( 436 const dbus::ObjectPath& device_path, 437 const PinCodeCallback& callback) { 438 DCHECK(agent_.get()); 439 VLOG(1) << device_path.value() << ": RequestPinCode"; 440 441 BluetoothPairingChromeOS* pairing = GetPairing(device_path); 442 if (!pairing) { 443 callback.Run(REJECTED, ""); 444 return; 445 } 446 447 pairing->RequestPinCode(callback); 448 } 449 450 void BluetoothAdapterChromeOS::DisplayPinCode( 451 const dbus::ObjectPath& device_path, 452 const std::string& pincode) { 453 DCHECK(agent_.get()); 454 VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode; 455 456 BluetoothPairingChromeOS* pairing = GetPairing(device_path); 457 if (!pairing) 458 return; 459 460 pairing->DisplayPinCode(pincode); 461 } 462 463 void BluetoothAdapterChromeOS::RequestPasskey( 464 const dbus::ObjectPath& device_path, 465 const PasskeyCallback& callback) { 466 DCHECK(agent_.get()); 467 VLOG(1) << device_path.value() << ": RequestPasskey"; 468 469 BluetoothPairingChromeOS* pairing = GetPairing(device_path); 470 if (!pairing) { 471 callback.Run(REJECTED, 0); 472 return; 473 } 474 475 pairing->RequestPasskey(callback); 476 } 477 478 void BluetoothAdapterChromeOS::DisplayPasskey( 479 const dbus::ObjectPath& device_path, 480 uint32 passkey, 481 uint16 entered) { 482 DCHECK(agent_.get()); 483 VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey 484 << " (" << entered << " entered)"; 485 486 BluetoothPairingChromeOS* pairing = GetPairing(device_path); 487 if (!pairing) 488 return; 489 490 if (entered == 0) 491 pairing->DisplayPasskey(passkey); 492 493 pairing->KeysEntered(entered); 494 } 495 496 void BluetoothAdapterChromeOS::RequestConfirmation( 497 const dbus::ObjectPath& device_path, 498 uint32 passkey, 499 const ConfirmationCallback& callback) { 500 DCHECK(agent_.get()); 501 VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey; 502 503 BluetoothPairingChromeOS* pairing = GetPairing(device_path); 504 if (!pairing) { 505 callback.Run(REJECTED); 506 return; 507 } 508 509 pairing->RequestConfirmation(passkey, callback); 510 } 511 512 void BluetoothAdapterChromeOS::RequestAuthorization( 513 const dbus::ObjectPath& device_path, 514 const ConfirmationCallback& callback) { 515 DCHECK(agent_.get()); 516 VLOG(1) << device_path.value() << ": RequestAuthorization"; 517 518 BluetoothPairingChromeOS* pairing = GetPairing(device_path); 519 if (!pairing) { 520 callback.Run(REJECTED); 521 return; 522 } 523 524 pairing->RequestAuthorization(callback); 525 } 526 527 void BluetoothAdapterChromeOS::AuthorizeService( 528 const dbus::ObjectPath& device_path, 529 const std::string& uuid, 530 const ConfirmationCallback& callback) { 531 DCHECK(agent_.get()); 532 VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid; 533 534 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(device_path); 535 if (!device_chromeos) { 536 callback.Run(CANCELLED); 537 return; 538 } 539 540 // We always set paired devices to Trusted, so the only reason that this 541 // method call would ever be called is in the case of a race condition where 542 // our "Set('Trusted', true)" method call is still pending in the Bluetooth 543 // daemon because it's busy handling the incoming connection. 544 if (device_chromeos->IsPaired()) { 545 callback.Run(SUCCESS); 546 return; 547 } 548 549 // TODO(keybuk): reject service authorizations when not paired, determine 550 // whether this is acceptable long-term. 551 LOG(WARNING) << "Rejecting service connection from unpaired device " 552 << device_chromeos->GetAddress() << " for UUID " << uuid; 553 callback.Run(REJECTED); 554 } 555 556 void BluetoothAdapterChromeOS::Cancel() { 557 DCHECK(agent_.get()); 558 VLOG(1) << "Cancel"; 559 } 560 561 void BluetoothAdapterChromeOS::OnRegisterAgent() { 562 VLOG(1) << "Pairing agent registered, requesting to be made default"; 563 564 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()-> 565 RequestDefaultAgent( 566 dbus::ObjectPath(kAgentPath), 567 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent, 568 weak_ptr_factory_.GetWeakPtr()), 569 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError, 570 weak_ptr_factory_.GetWeakPtr())); 571 572 } 573 574 void BluetoothAdapterChromeOS::OnRegisterAgentError( 575 const std::string& error_name, 576 const std::string& error_message) { 577 // Our agent being already registered isn't an error. 578 if (error_name == bluetooth_agent_manager::kErrorAlreadyExists) 579 return; 580 581 LOG(WARNING) << ": Failed to register pairing agent: " 582 << error_name << ": " << error_message; 583 } 584 585 void BluetoothAdapterChromeOS::OnRequestDefaultAgent() { 586 VLOG(1) << "Pairing agent now default"; 587 } 588 589 void BluetoothAdapterChromeOS::OnRequestDefaultAgentError( 590 const std::string& error_name, 591 const std::string& error_message) { 592 LOG(WARNING) << ": Failed to make pairing agent default: " 593 << error_name << ": " << error_message; 594 } 595 596 BluetoothDeviceChromeOS* 597 BluetoothAdapterChromeOS::GetDeviceWithPath( 598 const dbus::ObjectPath& object_path) { 599 for (DevicesMap::iterator iter = devices_.begin(); 600 iter != devices_.end(); ++iter) { 601 BluetoothDeviceChromeOS* device_chromeos = 602 static_cast<BluetoothDeviceChromeOS*>(iter->second); 603 if (device_chromeos->object_path() == object_path) 604 return device_chromeos; 605 } 606 607 return NULL; 608 } 609 610 BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing( 611 const dbus::ObjectPath& object_path) 612 { 613 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path); 614 if (!device_chromeos) { 615 LOG(WARNING) << "Pairing Agent request for unknown device: " 616 << object_path.value(); 617 return NULL; 618 } 619 620 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing(); 621 if (pairing) 622 return pairing; 623 624 // The device doesn't have its own pairing context, so this is an incoming 625 // pairing request that should use our best default delegate (if we have one). 626 BluetoothDevice::PairingDelegate* pairing_delegate = DefaultPairingDelegate(); 627 if (!pairing_delegate) 628 return NULL; 629 630 return device_chromeos->BeginPairing(pairing_delegate); 631 } 632 633 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) { 634 DCHECK(!IsPresent()); 635 object_path_ = object_path; 636 637 VLOG(1) << object_path_.value() << ": using adapter."; 638 639 VLOG(1) << "Registering pairing agent"; 640 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()-> 641 RegisterAgent( 642 dbus::ObjectPath(kAgentPath), 643 bluetooth_agent_manager::kKeyboardDisplayCapability, 644 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent, 645 weak_ptr_factory_.GetWeakPtr()), 646 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError, 647 weak_ptr_factory_.GetWeakPtr())); 648 649 SetDefaultAdapterName(); 650 651 BluetoothAdapterClient::Properties* properties = 652 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 653 GetProperties(object_path_); 654 655 PresentChanged(true); 656 657 if (properties->powered.value()) 658 PoweredChanged(true); 659 if (properties->discoverable.value()) 660 DiscoverableChanged(true); 661 if (properties->discovering.value()) 662 DiscoveringChanged(true); 663 664 std::vector<dbus::ObjectPath> device_paths = 665 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> 666 GetDevicesForAdapter(object_path_); 667 668 for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin(); 669 iter != device_paths.end(); ++iter) { 670 DeviceAdded(*iter); 671 } 672 } 673 674 void BluetoothAdapterChromeOS::SetDefaultAdapterName() { 675 std::string board = base::SysInfo::GetLsbReleaseBoard(); 676 std::string alias; 677 if (board.substr(0, 6) == "stumpy") { 678 alias = "Chromebox"; 679 } else if (board.substr(0, 4) == "link") { 680 alias = "Chromebook Pixel"; 681 } else { 682 alias = "Chromebook"; 683 } 684 685 SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing)); 686 } 687 688 void BluetoothAdapterChromeOS::RemoveAdapter() { 689 DCHECK(IsPresent()); 690 VLOG(1) << object_path_.value() << ": adapter removed."; 691 692 BluetoothAdapterClient::Properties* properties = 693 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 694 GetProperties(object_path_); 695 696 object_path_ = dbus::ObjectPath(""); 697 698 if (properties->powered.value()) 699 PoweredChanged(false); 700 if (properties->discoverable.value()) 701 DiscoverableChanged(false); 702 if (properties->discovering.value()) 703 DiscoveringChanged(false); 704 705 // Copy the devices list here and clear the original so that when we 706 // send DeviceRemoved(), GetDevices() returns no devices. 707 DevicesMap devices = devices_; 708 devices_.clear(); 709 710 for (DevicesMap::iterator iter = devices.begin(); 711 iter != devices.end(); ++iter) { 712 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, 713 DeviceRemoved(this, iter->second)); 714 delete iter->second; 715 } 716 717 PresentChanged(false); 718 } 719 720 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) { 721 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, 722 AdapterPoweredChanged(this, powered)); 723 } 724 725 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) { 726 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, 727 AdapterDiscoverableChanged(this, discoverable)); 728 } 729 730 void BluetoothAdapterChromeOS::DiscoveringChanged( 731 bool discovering) { 732 // If the adapter stopped discovery due to a reason other than a request by 733 // us, reset the count to 0. 734 VLOG(1) << "Discovering changed: " << discovering; 735 if (!discovering && !discovery_request_pending_ 736 && num_discovery_sessions_ > 0) { 737 VLOG(1) << "Marking sessions as inactive."; 738 num_discovery_sessions_ = 0; 739 MarkDiscoverySessionsAsInactive(); 740 } 741 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, 742 AdapterDiscoveringChanged(this, discovering)); 743 } 744 745 void BluetoothAdapterChromeOS::PresentChanged(bool present) { 746 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, 747 AdapterPresentChanged(this, present)); 748 } 749 750 void BluetoothAdapterChromeOS::NotifyDeviceChanged( 751 BluetoothDeviceChromeOS* device) { 752 DCHECK(device->adapter_ == this); 753 754 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, 755 DeviceChanged(this, device)); 756 } 757 758 void BluetoothAdapterChromeOS::NotifyGattServiceAdded( 759 BluetoothRemoteGattServiceChromeOS* service) { 760 DCHECK_EQ(service->GetAdapter(), this); 761 DCHECK_EQ( 762 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_, 763 this); 764 765 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, 766 observers_, 767 GattServiceAdded(this, service->GetDevice(), service)); 768 } 769 770 void BluetoothAdapterChromeOS::NotifyGattServiceRemoved( 771 BluetoothRemoteGattServiceChromeOS* service) { 772 DCHECK_EQ(service->GetAdapter(), this); 773 DCHECK_EQ( 774 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_, 775 this); 776 777 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, 778 observers_, 779 GattServiceRemoved(this, service->GetDevice(), service)); 780 } 781 782 void BluetoothAdapterChromeOS::NotifyGattServiceChanged( 783 BluetoothRemoteGattServiceChromeOS* service) { 784 DCHECK_EQ(service->GetAdapter(), this); 785 786 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, 787 observers_, 788 GattServiceChanged(this, service)); 789 } 790 791 void BluetoothAdapterChromeOS::NotifyGattDiscoveryComplete( 792 BluetoothRemoteGattServiceChromeOS* service) { 793 DCHECK_EQ(service->GetAdapter(), this); 794 795 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, 796 observers_, 797 GattDiscoveryCompleteForService(this, service)); 798 } 799 800 void BluetoothAdapterChromeOS::NotifyGattCharacteristicAdded( 801 BluetoothRemoteGattCharacteristicChromeOS* characteristic) { 802 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>( 803 characteristic->GetService())->GetAdapter(), 804 this); 805 806 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, 807 observers_, 808 GattCharacteristicAdded(this, characteristic)); 809 } 810 811 void BluetoothAdapterChromeOS::NotifyGattCharacteristicRemoved( 812 BluetoothRemoteGattCharacteristicChromeOS* characteristic) { 813 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>( 814 characteristic->GetService())->GetAdapter(), 815 this); 816 817 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, 818 observers_, 819 GattCharacteristicRemoved(this, characteristic)); 820 } 821 822 void BluetoothAdapterChromeOS::NotifyGattDescriptorAdded( 823 BluetoothRemoteGattDescriptorChromeOS* descriptor) { 824 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>( 825 descriptor->GetCharacteristic()->GetService())->GetAdapter(), 826 this); 827 828 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, 829 observers_, 830 GattDescriptorAdded(this, descriptor)); 831 } 832 833 void BluetoothAdapterChromeOS::NotifyGattDescriptorRemoved( 834 BluetoothRemoteGattDescriptorChromeOS* descriptor) { 835 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>( 836 descriptor->GetCharacteristic()->GetService())->GetAdapter(), 837 this); 838 839 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, 840 observers_, 841 GattDescriptorRemoved(this, descriptor)); 842 } 843 844 void BluetoothAdapterChromeOS::NotifyGattCharacteristicValueChanged( 845 BluetoothRemoteGattCharacteristicChromeOS* characteristic, 846 const std::vector<uint8>& value) { 847 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>( 848 characteristic->GetService())->GetAdapter(), 849 this); 850 851 FOR_EACH_OBSERVER( 852 BluetoothAdapter::Observer, 853 observers_, 854 GattCharacteristicValueChanged(this, characteristic, value)); 855 } 856 857 void BluetoothAdapterChromeOS::NotifyGattDescriptorValueChanged( 858 BluetoothRemoteGattDescriptorChromeOS* descriptor, 859 const std::vector<uint8>& value) { 860 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>( 861 descriptor->GetCharacteristic()->GetService())->GetAdapter(), 862 this); 863 864 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, 865 observers_, 866 GattDescriptorValueChanged(this, descriptor, value)); 867 } 868 869 void BluetoothAdapterChromeOS::OnSetDiscoverable( 870 const base::Closure& callback, 871 const ErrorCallback& error_callback, 872 bool success) { 873 // Set the discoverable_timeout property to zero so the adapter remains 874 // discoverable forever. 875 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 876 GetProperties(object_path_)->discoverable_timeout.Set( 877 0, 878 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted, 879 weak_ptr_factory_.GetWeakPtr(), 880 callback, 881 error_callback)); 882 } 883 884 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted( 885 const base::Closure& callback, 886 const ErrorCallback& error_callback, 887 bool success) { 888 if (success) 889 callback.Run(); 890 else 891 error_callback.Run(); 892 } 893 894 void BluetoothAdapterChromeOS::AddDiscoverySession( 895 const base::Closure& callback, 896 const ErrorCallback& error_callback) { 897 VLOG(1) << __func__; 898 if (discovery_request_pending_) { 899 // The pending request is either to stop a previous session or to start a 900 // new one. Either way, queue this one. 901 DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0); 902 VLOG(1) << "Pending request to start/stop device discovery. Queueing " 903 << "request to start a new discovery session."; 904 discovery_request_queue_.push(std::make_pair(callback, error_callback)); 905 return; 906 } 907 908 // The adapter is already discovering. 909 if (num_discovery_sessions_ > 0) { 910 DCHECK(IsDiscovering()); 911 DCHECK(!discovery_request_pending_); 912 num_discovery_sessions_++; 913 callback.Run(); 914 return; 915 } 916 917 // There are no active discovery sessions. 918 DCHECK(num_discovery_sessions_ == 0); 919 920 // This is the first request to start device discovery. 921 discovery_request_pending_ = true; 922 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 923 StartDiscovery( 924 object_path_, 925 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery, 926 weak_ptr_factory_.GetWeakPtr(), 927 callback), 928 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError, 929 weak_ptr_factory_.GetWeakPtr(), 930 callback, 931 error_callback)); 932 } 933 934 void BluetoothAdapterChromeOS::RemoveDiscoverySession( 935 const base::Closure& callback, 936 const ErrorCallback& error_callback) { 937 VLOG(1) << __func__; 938 // There are active sessions other than the one currently being removed. 939 if (num_discovery_sessions_ > 1) { 940 DCHECK(IsDiscovering()); 941 DCHECK(!discovery_request_pending_); 942 num_discovery_sessions_--; 943 callback.Run(); 944 return; 945 } 946 947 // If there is a pending request to BlueZ, then queue this request. 948 if (discovery_request_pending_) { 949 VLOG(1) << "Pending request to start/stop device discovery. Queueing " 950 << "request to stop discovery session."; 951 error_callback.Run(); 952 return; 953 } 954 955 // There are no active sessions. Return error. 956 if (num_discovery_sessions_ == 0) { 957 // TODO(armansito): This should never happen once we have the 958 // DiscoverySession API. Replace this case with an assert once it's 959 // the deprecated methods have been removed. (See crbug.com/3445008). 960 VLOG(1) << "No active discovery sessions. Returning error."; 961 error_callback.Run(); 962 return; 963 } 964 965 // There is exactly one active discovery session. Request BlueZ to stop 966 // discovery. 967 DCHECK(num_discovery_sessions_ == 1); 968 discovery_request_pending_ = true; 969 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> 970 StopDiscovery( 971 object_path_, 972 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery, 973 weak_ptr_factory_.GetWeakPtr(), 974 callback), 975 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError, 976 weak_ptr_factory_.GetWeakPtr(), 977 error_callback)); 978 } 979 980 void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure& callback) { 981 // Report success on the original request and increment the count. 982 VLOG(1) << __func__; 983 DCHECK(discovery_request_pending_); 984 DCHECK(num_discovery_sessions_ == 0); 985 discovery_request_pending_ = false; 986 num_discovery_sessions_++; 987 callback.Run(); 988 989 // Try to add a new discovery session for each queued request. 990 ProcessQueuedDiscoveryRequests(); 991 } 992 993 void BluetoothAdapterChromeOS::OnStartDiscoveryError( 994 const base::Closure& callback, 995 const ErrorCallback& error_callback, 996 const std::string& error_name, 997 const std::string& error_message) { 998 LOG(WARNING) << object_path_.value() << ": Failed to start discovery: " 999 << error_name << ": " << error_message; 1000 1001 // Failed to start discovery. This can only happen if the count is at 0. 1002 DCHECK(num_discovery_sessions_ == 0); 1003 DCHECK(discovery_request_pending_); 1004 discovery_request_pending_ = false; 1005 1006 // Discovery request may fail if discovery was previously initiated by Chrome, 1007 // but the session were invalidated due to the discovery state unexpectedly 1008 // changing to false and then back to true. In this case, report success. 1009 if (error_name == bluetooth_device::kErrorInProgress && IsDiscovering()) { 1010 VLOG(1) << "Discovery previously initiated. Reporting success."; 1011 num_discovery_sessions_++; 1012 callback.Run(); 1013 } else { 1014 error_callback.Run(); 1015 } 1016 1017 // Try to add a new discovery session for each queued request. 1018 ProcessQueuedDiscoveryRequests(); 1019 } 1020 1021 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) { 1022 // Report success on the original request and decrement the count. 1023 VLOG(1) << __func__; 1024 DCHECK(discovery_request_pending_); 1025 DCHECK(num_discovery_sessions_ == 1); 1026 discovery_request_pending_ = false; 1027 num_discovery_sessions_--; 1028 callback.Run(); 1029 1030 // Try to add a new discovery session for each queued request. 1031 ProcessQueuedDiscoveryRequests(); 1032 } 1033 1034 void BluetoothAdapterChromeOS::OnStopDiscoveryError( 1035 const ErrorCallback& error_callback, 1036 const std::string& error_name, 1037 const std::string& error_message) { 1038 LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: " 1039 << error_name << ": " << error_message; 1040 1041 // Failed to stop discovery. This can only happen if the count is at 1. 1042 DCHECK(discovery_request_pending_); 1043 DCHECK(num_discovery_sessions_ == 1); 1044 discovery_request_pending_ = false; 1045 error_callback.Run(); 1046 1047 // Try to add a new discovery session for each queued request. 1048 ProcessQueuedDiscoveryRequests(); 1049 } 1050 1051 void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() { 1052 while (!discovery_request_queue_.empty()) { 1053 VLOG(1) << "Process queued discovery request."; 1054 DiscoveryCallbackPair callbacks = discovery_request_queue_.front(); 1055 discovery_request_queue_.pop(); 1056 AddDiscoverySession(callbacks.first, callbacks.second); 1057 1058 // If the queued request resulted in a pending call, then let it 1059 // asynchonously process the remaining queued requests once the pending 1060 // call returns. 1061 if (discovery_request_pending_) 1062 return; 1063 } 1064 } 1065 1066 } // namespace chromeos 1067