Home | History | Annotate | Download | only in bluetooth
      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