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.
5 #include "device/bluetooth/bluetooth_adapter_chromeos.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/metrics/histogram.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/sys_info.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "chromeos/dbus/bluetooth_adapter_client.h"
18 #include "chromeos/dbus/bluetooth_agent_manager_client.h"
19 #include "chromeos/dbus/bluetooth_agent_service_provider.h"
20 #include "chromeos/dbus/bluetooth_device_client.h"
21 #include "chromeos/dbus/bluetooth_input_client.h"
22 #include "chromeos/dbus/dbus_thread_manager.h"
23 #include "device/bluetooth/bluetooth_adapter_profile_chromeos.h"
24 #include "device/bluetooth/bluetooth_audio_sink_chromeos.h"
25 #include "device/bluetooth/bluetooth_device.h"
26 #include "device/bluetooth/bluetooth_device_chromeos.h"
27 #include "device/bluetooth/bluetooth_pairing_chromeos.h"
28 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
29 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h"
30 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
31 #include "device/bluetooth/bluetooth_socket_chromeos.h"
32 #include "device/bluetooth/bluetooth_socket_thread.h"
33 #include "device/bluetooth/bluetooth_uuid.h"
34 #include "third_party/cros_system_api/dbus/service_constants.h"
36 using device::BluetoothAdapter
;
37 using device::BluetoothAudioSink
;
38 using device::BluetoothDevice
;
39 using device::BluetoothSocket
;
40 using device::BluetoothUUID
;
44 // The agent path is relatively meaningless since BlueZ only permits one to
45 // exist per D-Bus connection, it just has to be unique within Chromium.
46 const char kAgentPath
[] = "/org/chromium/bluetooth_agent";
48 void OnUnregisterAgentError(const std::string
& error_name
,
49 const std::string
& error_message
) {
50 // It's okay if the agent didn't exist, it means we never saw an adapter.
51 if (error_name
== bluetooth_agent_manager::kErrorDoesNotExist
)
54 LOG(WARNING
) << "Failed to unregister pairing agent: "
55 << error_name
<< ": " << error_message
;
63 base::WeakPtr
<BluetoothAdapter
> BluetoothAdapter::CreateAdapter(
64 const InitCallback
& init_callback
) {
65 return chromeos::BluetoothAdapterChromeOS::CreateAdapter();
73 base::WeakPtr
<BluetoothAdapter
> BluetoothAdapterChromeOS::CreateAdapter() {
74 BluetoothAdapterChromeOS
* adapter
= new BluetoothAdapterChromeOS();
75 return adapter
->weak_ptr_factory_
.GetWeakPtr();
78 void BluetoothAdapterChromeOS::Shutdown() {
79 if (dbus_is_shutdown_
)
81 DCHECK(DBusThreadManager::IsInitialized())
82 << "Call BluetoothAdapterFactory::Shutdown() before "
83 "DBusThreadManager::Shutdown().";
86 RemoveAdapter(); // Also deletes devices_.
87 DCHECK(devices_
.empty());
88 // profiles_ should be empty because all BluetoothSockets have been signaled
89 // that this adapter is disappearing.
90 DCHECK(profiles_
.empty());
92 for (auto& it
: profile_queues_
)
94 profile_queues_
.clear();
96 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
97 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
98 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
100 VLOG(1) << "Unregistering pairing agent";
101 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->UnregisterAgent(
102 dbus::ObjectPath(kAgentPath
), base::Bind(&base::DoNothing
),
103 base::Bind(&OnUnregisterAgentError
));
106 dbus_is_shutdown_
= true;
109 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
110 : dbus_is_shutdown_(false),
111 num_discovery_sessions_(0),
112 discovery_request_pending_(false),
113 weak_ptr_factory_(this) {
114 ui_task_runner_
= base::ThreadTaskRunnerHandle::Get();
115 socket_thread_
= device::BluetoothSocketThread::Get();
117 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
118 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
119 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
121 // Register the pairing agent.
122 dbus::Bus
* system_bus
= DBusThreadManager::Get()->GetSystemBus();
123 agent_
.reset(BluetoothAgentServiceProvider::Create(
124 system_bus
, dbus::ObjectPath(kAgentPath
), this));
125 DCHECK(agent_
.get());
127 std::vector
<dbus::ObjectPath
> object_paths
=
128 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
130 if (!object_paths
.empty()) {
131 VLOG(1) << object_paths
.size() << " Bluetooth adapter(s) available.";
132 SetAdapter(object_paths
[0]);
136 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
140 void BluetoothAdapterChromeOS::DeleteOnCorrectThread() const {
141 if (ui_task_runner_
->RunsTasksOnCurrentThread() ||
142 !ui_task_runner_
->DeleteSoon(FROM_HERE
, this))
146 void BluetoothAdapterChromeOS::AddObserver(
147 BluetoothAdapter::Observer
* observer
) {
149 observers_
.AddObserver(observer
);
152 void BluetoothAdapterChromeOS::RemoveObserver(
153 BluetoothAdapter::Observer
* observer
) {
155 observers_
.RemoveObserver(observer
);
158 std::string
BluetoothAdapterChromeOS::GetAddress() const {
160 return std::string();
162 BluetoothAdapterClient::Properties
* properties
=
163 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
164 GetProperties(object_path_
);
167 return BluetoothDevice::CanonicalizeAddress(properties
->address
.value());
170 std::string
BluetoothAdapterChromeOS::GetName() const {
172 return std::string();
174 BluetoothAdapterClient::Properties
* properties
=
175 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
176 GetProperties(object_path_
);
179 return properties
->alias
.value();
182 void BluetoothAdapterChromeOS::SetName(const std::string
& name
,
183 const base::Closure
& callback
,
184 const ErrorCallback
& error_callback
) {
186 error_callback
.Run();
190 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
191 GetProperties(object_path_
)->alias
.Set(
193 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted
,
194 weak_ptr_factory_
.GetWeakPtr(),
199 bool BluetoothAdapterChromeOS::IsInitialized() const {
203 bool BluetoothAdapterChromeOS::IsPresent() const {
204 return !dbus_is_shutdown_
&& !object_path_
.value().empty();
207 bool BluetoothAdapterChromeOS::IsPowered() const {
211 BluetoothAdapterClient::Properties
* properties
=
212 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
213 GetProperties(object_path_
);
215 return properties
->powered
.value();
218 void BluetoothAdapterChromeOS::SetPowered(
220 const base::Closure
& callback
,
221 const ErrorCallback
& error_callback
) {
223 error_callback
.Run();
227 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
228 GetProperties(object_path_
)->powered
.Set(
230 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted
,
231 weak_ptr_factory_
.GetWeakPtr(),
236 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
240 BluetoothAdapterClient::Properties
* properties
=
241 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
242 GetProperties(object_path_
);
244 return properties
->discoverable
.value();
247 void BluetoothAdapterChromeOS::SetDiscoverable(
249 const base::Closure
& callback
,
250 const ErrorCallback
& error_callback
) {
252 error_callback
.Run();
256 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
257 GetProperties(object_path_
)->discoverable
.Set(
259 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable
,
260 weak_ptr_factory_
.GetWeakPtr(),
265 bool BluetoothAdapterChromeOS::IsDiscovering() const {
269 BluetoothAdapterClient::Properties
* properties
=
270 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
271 GetProperties(object_path_
);
273 return properties
->discovering
.value();
276 void BluetoothAdapterChromeOS::CreateRfcommService(
277 const BluetoothUUID
& uuid
,
278 const ServiceOptions
& options
,
279 const CreateServiceCallback
& callback
,
280 const CreateServiceErrorCallback
& error_callback
) {
281 DCHECK(!dbus_is_shutdown_
);
282 VLOG(1) << object_path_
.value() << ": Creating RFCOMM service: "
283 << uuid
.canonical_value();
284 scoped_refptr
<BluetoothSocketChromeOS
> socket
=
285 BluetoothSocketChromeOS::CreateBluetoothSocket(
286 ui_task_runner_
, socket_thread_
);
288 BluetoothSocketChromeOS::kRfcomm
,
291 base::Bind(callback
, socket
),
295 void BluetoothAdapterChromeOS::CreateL2capService(
296 const BluetoothUUID
& uuid
,
297 const ServiceOptions
& options
,
298 const CreateServiceCallback
& callback
,
299 const CreateServiceErrorCallback
& error_callback
) {
300 DCHECK(!dbus_is_shutdown_
);
301 VLOG(1) << object_path_
.value() << ": Creating L2CAP service: "
302 << uuid
.canonical_value();
303 scoped_refptr
<BluetoothSocketChromeOS
> socket
=
304 BluetoothSocketChromeOS::CreateBluetoothSocket(
305 ui_task_runner_
, socket_thread_
);
307 BluetoothSocketChromeOS::kL2cap
,
310 base::Bind(callback
, socket
),
314 void BluetoothAdapterChromeOS::RegisterAudioSink(
315 const BluetoothAudioSink::Options
& options
,
316 const device::BluetoothAdapter::AcquiredCallback
& callback
,
317 const BluetoothAudioSink::ErrorCallback
& error_callback
) {
318 VLOG(1) << "Registering audio sink";
319 if (!this->IsPresent()) {
320 error_callback
.Run(BluetoothAudioSink::ERROR_INVALID_ADAPTER
);
323 scoped_refptr
<BluetoothAudioSinkChromeOS
> audio_sink(
324 new BluetoothAudioSinkChromeOS(this));
325 audio_sink
->Register(
326 options
, base::Bind(&BluetoothAdapterChromeOS::OnRegisterAudioSink
,
327 weak_ptr_factory_
.GetWeakPtr(), callback
,
328 error_callback
, audio_sink
),
332 void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
333 BluetoothDevice::PairingDelegate
* pairing_delegate
) {
334 // Before removing a pairing delegate make sure that there aren't any devices
335 // currently using it; if there are, clear the pairing context which will
336 // make any responses no-ops.
337 for (DevicesMap::iterator iter
= devices_
.begin();
338 iter
!= devices_
.end(); ++iter
) {
339 BluetoothDeviceChromeOS
* device_chromeos
=
340 static_cast<BluetoothDeviceChromeOS
*>(iter
->second
);
342 BluetoothPairingChromeOS
* pairing
= device_chromeos
->GetPairing();
343 if (pairing
&& pairing
->GetPairingDelegate() == pairing_delegate
)
344 device_chromeos
->EndPairing();
348 void BluetoothAdapterChromeOS::AdapterAdded(
349 const dbus::ObjectPath
& object_path
) {
350 // Set the adapter to the newly added adapter only if no adapter is present.
352 SetAdapter(object_path
);
355 void BluetoothAdapterChromeOS::AdapterRemoved(
356 const dbus::ObjectPath
& object_path
) {
357 if (object_path
== object_path_
)
361 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
362 const dbus::ObjectPath
& object_path
,
363 const std::string
& property_name
) {
364 if (object_path
!= object_path_
)
368 BluetoothAdapterClient::Properties
* properties
=
369 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
370 GetProperties(object_path_
);
372 if (property_name
== properties
->powered
.name())
373 PoweredChanged(properties
->powered
.value());
374 else if (property_name
== properties
->discoverable
.name())
375 DiscoverableChanged(properties
->discoverable
.value());
376 else if (property_name
== properties
->discovering
.name())
377 DiscoveringChanged(properties
->discovering
.value());
380 void BluetoothAdapterChromeOS::DeviceAdded(
381 const dbus::ObjectPath
& object_path
) {
382 DCHECK(DBusThreadManager::Get());
383 BluetoothDeviceClient::Properties
* properties
=
384 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
385 GetProperties(object_path
);
386 if (!properties
|| properties
->adapter
.value() != object_path_
)
390 BluetoothDeviceChromeOS
* device_chromeos
=
391 new BluetoothDeviceChromeOS(this,
395 DCHECK(devices_
.find(device_chromeos
->GetAddress()) == devices_
.end());
397 devices_
[device_chromeos
->GetAddress()] = device_chromeos
;
399 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
400 DeviceAdded(this, device_chromeos
));
403 void BluetoothAdapterChromeOS::DeviceRemoved(
404 const dbus::ObjectPath
& object_path
) {
405 for (DevicesMap::iterator iter
= devices_
.begin();
406 iter
!= devices_
.end(); ++iter
) {
407 BluetoothDeviceChromeOS
* device_chromeos
=
408 static_cast<BluetoothDeviceChromeOS
*>(iter
->second
);
409 if (device_chromeos
->object_path() == object_path
) {
410 devices_
.erase(iter
);
412 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
413 DeviceRemoved(this, device_chromeos
));
414 delete device_chromeos
;
420 void BluetoothAdapterChromeOS::DevicePropertyChanged(
421 const dbus::ObjectPath
& object_path
,
422 const std::string
& property_name
) {
423 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(object_path
);
424 if (!device_chromeos
)
427 BluetoothDeviceClient::Properties
* properties
=
428 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
429 GetProperties(object_path
);
431 if (property_name
== properties
->bluetooth_class
.name() ||
432 property_name
== properties
->address
.name() ||
433 property_name
== properties
->alias
.name() ||
434 property_name
== properties
->paired
.name() ||
435 property_name
== properties
->trusted
.name() ||
436 property_name
== properties
->connected
.name() ||
437 property_name
== properties
->uuids
.name() ||
438 property_name
== properties
->rssi
.name())
439 NotifyDeviceChanged(device_chromeos
);
441 // When a device becomes paired, mark it as trusted so that the user does
442 // not need to approve every incoming connection
443 if (property_name
== properties
->paired
.name() &&
444 properties
->paired
.value() && !properties
->trusted
.value())
445 device_chromeos
->SetTrusted();
447 // UMA connection counting
448 if (property_name
== properties
->connected
.name()) {
449 // PlayStation joystick tries to reconnect after disconnection from USB.
450 // If it is still not trusted, set it, so it becomes available on the
451 // list of known devices.
452 if (properties
->connected
.value() && device_chromeos
->IsTrustable() &&
453 !properties
->trusted
.value())
454 device_chromeos
->SetTrusted();
458 for (DevicesMap::iterator iter
= devices_
.begin();
459 iter
!= devices_
.end(); ++iter
) {
460 if (iter
->second
->IsPaired() && iter
->second
->IsConnected())
464 UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count
);
468 void BluetoothAdapterChromeOS::InputPropertyChanged(
469 const dbus::ObjectPath
& object_path
,
470 const std::string
& property_name
) {
471 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(object_path
);
472 if (!device_chromeos
)
475 BluetoothInputClient::Properties
* properties
=
476 DBusThreadManager::Get()->GetBluetoothInputClient()->
477 GetProperties(object_path
);
479 // Properties structure can be removed, which triggers a change in the
480 // BluetoothDevice::IsConnectable() property, as does a change in the
481 // actual reconnect_mode property.
483 property_name
== properties
->reconnect_mode
.name())
484 NotifyDeviceChanged(device_chromeos
);
487 void BluetoothAdapterChromeOS::Released() {
488 VLOG(1) << "Release";
491 DCHECK(agent_
.get());
493 // Called after we unregister the pairing agent, e.g. when changing I/O
494 // capabilities. Nothing much to be done right now.
497 void BluetoothAdapterChromeOS::RequestPinCode(
498 const dbus::ObjectPath
& device_path
,
499 const PinCodeCallback
& callback
) {
501 DCHECK(agent_
.get());
502 VLOG(1) << device_path
.value() << ": RequestPinCode";
504 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
506 callback
.Run(REJECTED
, "");
510 pairing
->RequestPinCode(callback
);
513 void BluetoothAdapterChromeOS::DisplayPinCode(
514 const dbus::ObjectPath
& device_path
,
515 const std::string
& pincode
) {
517 DCHECK(agent_
.get());
518 VLOG(1) << device_path
.value() << ": DisplayPinCode: " << pincode
;
520 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
524 pairing
->DisplayPinCode(pincode
);
527 void BluetoothAdapterChromeOS::RequestPasskey(
528 const dbus::ObjectPath
& device_path
,
529 const PasskeyCallback
& callback
) {
531 DCHECK(agent_
.get());
532 VLOG(1) << device_path
.value() << ": RequestPasskey";
534 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
536 callback
.Run(REJECTED
, 0);
540 pairing
->RequestPasskey(callback
);
543 void BluetoothAdapterChromeOS::DisplayPasskey(
544 const dbus::ObjectPath
& device_path
,
548 DCHECK(agent_
.get());
549 VLOG(1) << device_path
.value() << ": DisplayPasskey: " << passkey
550 << " (" << entered
<< " entered)";
552 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
557 pairing
->DisplayPasskey(passkey
);
559 pairing
->KeysEntered(entered
);
562 void BluetoothAdapterChromeOS::RequestConfirmation(
563 const dbus::ObjectPath
& device_path
,
565 const ConfirmationCallback
& callback
) {
567 DCHECK(agent_
.get());
568 VLOG(1) << device_path
.value() << ": RequestConfirmation: " << passkey
;
570 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
572 callback
.Run(REJECTED
);
576 pairing
->RequestConfirmation(passkey
, callback
);
579 void BluetoothAdapterChromeOS::RequestAuthorization(
580 const dbus::ObjectPath
& device_path
,
581 const ConfirmationCallback
& callback
) {
583 DCHECK(agent_
.get());
584 VLOG(1) << device_path
.value() << ": RequestAuthorization";
586 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
588 callback
.Run(REJECTED
);
592 pairing
->RequestAuthorization(callback
);
595 void BluetoothAdapterChromeOS::AuthorizeService(
596 const dbus::ObjectPath
& device_path
,
597 const std::string
& uuid
,
598 const ConfirmationCallback
& callback
) {
600 DCHECK(agent_
.get());
601 VLOG(1) << device_path
.value() << ": AuthorizeService: " << uuid
;
603 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(device_path
);
604 if (!device_chromeos
) {
605 callback
.Run(CANCELLED
);
609 // We always set paired devices to Trusted, so the only reason that this
610 // method call would ever be called is in the case of a race condition where
611 // our "Set('Trusted', true)" method call is still pending in the Bluetooth
612 // daemon because it's busy handling the incoming connection.
613 if (device_chromeos
->IsPaired()) {
614 callback
.Run(SUCCESS
);
618 // TODO(keybuk): reject service authorizations when not paired, determine
619 // whether this is acceptable long-term.
620 LOG(WARNING
) << "Rejecting service connection from unpaired device "
621 << device_chromeos
->GetAddress() << " for UUID " << uuid
;
622 callback
.Run(REJECTED
);
625 void BluetoothAdapterChromeOS::Cancel() {
627 DCHECK(agent_
.get());
631 void BluetoothAdapterChromeOS::OnRegisterAgent() {
632 VLOG(1) << "Pairing agent registered, requesting to be made default";
634 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
636 dbus::ObjectPath(kAgentPath
),
637 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent
,
638 weak_ptr_factory_
.GetWeakPtr()),
639 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError
,
640 weak_ptr_factory_
.GetWeakPtr()));
643 void BluetoothAdapterChromeOS::OnRegisterAgentError(
644 const std::string
& error_name
,
645 const std::string
& error_message
) {
646 // Our agent being already registered isn't an error.
647 if (error_name
== bluetooth_agent_manager::kErrorAlreadyExists
)
650 LOG(WARNING
) << ": Failed to register pairing agent: "
651 << error_name
<< ": " << error_message
;
654 void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
655 VLOG(1) << "Pairing agent now default";
658 void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
659 const std::string
& error_name
,
660 const std::string
& error_message
) {
661 LOG(WARNING
) << ": Failed to make pairing agent default: "
662 << error_name
<< ": " << error_message
;
665 void BluetoothAdapterChromeOS::OnRegisterAudioSink(
666 const device::BluetoothAdapter::AcquiredCallback
& callback
,
667 const device::BluetoothAudioSink::ErrorCallback
& error_callback
,
668 scoped_refptr
<BluetoothAudioSink
> audio_sink
) {
670 VLOG(1) << "Failed to register audio sink, adapter not present";
671 error_callback
.Run(BluetoothAudioSink::ERROR_INVALID_ADAPTER
);
674 DCHECK(audio_sink
.get());
675 callback
.Run(audio_sink
);
678 BluetoothDeviceChromeOS
*
679 BluetoothAdapterChromeOS::GetDeviceWithPath(
680 const dbus::ObjectPath
& object_path
) {
684 for (DevicesMap::iterator iter
= devices_
.begin(); iter
!= devices_
.end();
686 BluetoothDeviceChromeOS
* device_chromeos
=
687 static_cast<BluetoothDeviceChromeOS
*>(iter
->second
);
688 if (device_chromeos
->object_path() == object_path
)
689 return device_chromeos
;
695 BluetoothPairingChromeOS
* BluetoothAdapterChromeOS::GetPairing(
696 const dbus::ObjectPath
& object_path
) {
698 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(object_path
);
699 if (!device_chromeos
) {
700 LOG(WARNING
) << "Pairing Agent request for unknown device: "
701 << object_path
.value();
705 BluetoothPairingChromeOS
* pairing
= device_chromeos
->GetPairing();
709 // The device doesn't have its own pairing context, so this is an incoming
710 // pairing request that should use our best default delegate (if we have one).
711 BluetoothDevice::PairingDelegate
* pairing_delegate
= DefaultPairingDelegate();
712 if (!pairing_delegate
)
715 return device_chromeos
->BeginPairing(pairing_delegate
);
718 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath
& object_path
) {
719 DCHECK(!IsPresent());
720 DCHECK(!dbus_is_shutdown_
);
721 object_path_
= object_path
;
723 VLOG(1) << object_path_
.value() << ": using adapter.";
725 VLOG(1) << "Registering pairing agent";
726 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
728 dbus::ObjectPath(kAgentPath
),
729 bluetooth_agent_manager::kKeyboardDisplayCapability
,
730 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent
,
731 weak_ptr_factory_
.GetWeakPtr()),
732 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError
,
733 weak_ptr_factory_
.GetWeakPtr()));
735 SetDefaultAdapterName();
737 BluetoothAdapterClient::Properties
* properties
=
738 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
739 GetProperties(object_path_
);
741 PresentChanged(true);
743 if (properties
->powered
.value())
744 PoweredChanged(true);
745 if (properties
->discoverable
.value())
746 DiscoverableChanged(true);
747 if (properties
->discovering
.value())
748 DiscoveringChanged(true);
750 std::vector
<dbus::ObjectPath
> device_paths
=
751 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
752 GetDevicesForAdapter(object_path_
);
754 for (std::vector
<dbus::ObjectPath
>::iterator iter
= device_paths
.begin();
755 iter
!= device_paths
.end(); ++iter
) {
760 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
762 std::string board
= base::SysInfo::GetLsbReleaseBoard();
764 if (board
.substr(0, 6) == "stumpy") {
766 } else if (board
.substr(0, 4) == "link") {
767 alias
= "Chromebook Pixel";
769 alias
= "Chromebook";
772 SetName(alias
, base::Bind(&base::DoNothing
), base::Bind(&base::DoNothing
));
775 void BluetoothAdapterChromeOS::RemoveAdapter() {
777 VLOG(1) << object_path_
.value() << ": adapter removed.";
779 BluetoothAdapterClient::Properties
* properties
=
780 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
781 GetProperties(object_path_
);
783 object_path_
= dbus::ObjectPath("");
785 if (properties
->powered
.value())
786 PoweredChanged(false);
787 if (properties
->discoverable
.value())
788 DiscoverableChanged(false);
789 if (properties
->discovering
.value())
790 DiscoveringChanged(false);
792 // Copy the devices list here and clear the original so that when we
793 // send DeviceRemoved(), GetDevices() returns no devices.
794 DevicesMap devices
= devices_
;
797 for (DevicesMap::iterator iter
= devices
.begin();
798 iter
!= devices
.end(); ++iter
) {
799 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
800 DeviceRemoved(this, iter
->second
));
804 PresentChanged(false);
807 void BluetoothAdapterChromeOS::PoweredChanged(bool powered
) {
808 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
809 AdapterPoweredChanged(this, powered
));
812 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable
) {
813 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
814 AdapterDiscoverableChanged(this, discoverable
));
817 void BluetoothAdapterChromeOS::DiscoveringChanged(
819 // If the adapter stopped discovery due to a reason other than a request by
820 // us, reset the count to 0.
821 VLOG(1) << "Discovering changed: " << discovering
;
822 if (!discovering
&& !discovery_request_pending_
823 && num_discovery_sessions_
> 0) {
824 VLOG(1) << "Marking sessions as inactive.";
825 num_discovery_sessions_
= 0;
826 MarkDiscoverySessionsAsInactive();
828 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
829 AdapterDiscoveringChanged(this, discovering
));
832 void BluetoothAdapterChromeOS::PresentChanged(bool present
) {
833 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
834 AdapterPresentChanged(this, present
));
837 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
838 BluetoothDeviceChromeOS
* device
) {
839 DCHECK(device
->adapter_
== this);
841 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
842 DeviceChanged(this, device
));
845 void BluetoothAdapterChromeOS::NotifyGattServiceAdded(
846 BluetoothRemoteGattServiceChromeOS
* service
) {
847 DCHECK_EQ(service
->GetAdapter(), this);
849 static_cast<BluetoothDeviceChromeOS
*>(service
->GetDevice())->adapter_
,
852 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
854 GattServiceAdded(this, service
->GetDevice(), service
));
857 void BluetoothAdapterChromeOS::NotifyGattServiceRemoved(
858 BluetoothRemoteGattServiceChromeOS
* service
) {
859 DCHECK_EQ(service
->GetAdapter(), this);
861 static_cast<BluetoothDeviceChromeOS
*>(service
->GetDevice())->adapter_
,
864 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
866 GattServiceRemoved(this, service
->GetDevice(), service
));
869 void BluetoothAdapterChromeOS::NotifyGattServiceChanged(
870 BluetoothRemoteGattServiceChromeOS
* service
) {
871 DCHECK_EQ(service
->GetAdapter(), this);
873 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
875 GattServiceChanged(this, service
));
878 void BluetoothAdapterChromeOS::NotifyGattDiscoveryComplete(
879 BluetoothRemoteGattServiceChromeOS
* service
) {
880 DCHECK_EQ(service
->GetAdapter(), this);
882 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
884 GattDiscoveryCompleteForService(this, service
));
887 void BluetoothAdapterChromeOS::NotifyGattCharacteristicAdded(
888 BluetoothRemoteGattCharacteristicChromeOS
* characteristic
) {
889 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS
*>(
890 characteristic
->GetService())->GetAdapter(),
893 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
895 GattCharacteristicAdded(this, characteristic
));
898 void BluetoothAdapterChromeOS::NotifyGattCharacteristicRemoved(
899 BluetoothRemoteGattCharacteristicChromeOS
* characteristic
) {
900 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS
*>(
901 characteristic
->GetService())->GetAdapter(),
904 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
906 GattCharacteristicRemoved(this, characteristic
));
909 void BluetoothAdapterChromeOS::NotifyGattDescriptorAdded(
910 BluetoothRemoteGattDescriptorChromeOS
* descriptor
) {
911 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS
*>(
912 descriptor
->GetCharacteristic()->GetService())->GetAdapter(),
915 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
917 GattDescriptorAdded(this, descriptor
));
920 void BluetoothAdapterChromeOS::NotifyGattDescriptorRemoved(
921 BluetoothRemoteGattDescriptorChromeOS
* descriptor
) {
922 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS
*>(
923 descriptor
->GetCharacteristic()->GetService())->GetAdapter(),
926 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
928 GattDescriptorRemoved(this, descriptor
));
931 void BluetoothAdapterChromeOS::NotifyGattCharacteristicValueChanged(
932 BluetoothRemoteGattCharacteristicChromeOS
* characteristic
,
933 const std::vector
<uint8
>& value
) {
934 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS
*>(
935 characteristic
->GetService())->GetAdapter(),
939 BluetoothAdapter::Observer
,
941 GattCharacteristicValueChanged(this, characteristic
, value
));
944 void BluetoothAdapterChromeOS::NotifyGattDescriptorValueChanged(
945 BluetoothRemoteGattDescriptorChromeOS
* descriptor
,
946 const std::vector
<uint8
>& value
) {
947 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS
*>(
948 descriptor
->GetCharacteristic()->GetService())->GetAdapter(),
951 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
953 GattDescriptorValueChanged(this, descriptor
, value
));
956 void BluetoothAdapterChromeOS::UseProfile(
957 const BluetoothUUID
& uuid
,
958 const dbus::ObjectPath
& device_path
,
959 const BluetoothProfileManagerClient::Options
& options
,
960 BluetoothProfileServiceProvider::Delegate
* delegate
,
961 const ProfileRegisteredCallback
& success_callback
,
962 const ErrorCompletionCallback
& error_callback
) {
966 VLOG(2) << "Adapter not present, erroring out";
967 error_callback
.Run("Adapter not present");
971 if (profiles_
.find(uuid
) != profiles_
.end()) {
972 // TODO(jamuraa) check that the options are the same and error when they are
974 SetProfileDelegate(uuid
, device_path
, delegate
, success_callback
,
979 if (profile_queues_
.find(uuid
) == profile_queues_
.end()) {
980 BluetoothAdapterProfileChromeOS::Register(
982 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfile
, this, uuid
),
983 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfileError
, this,
986 profile_queues_
[uuid
] = new std::vector
<RegisterProfileCompletionPair
>();
989 profile_queues_
[uuid
]->push_back(std::make_pair(
990 base::Bind(&BluetoothAdapterChromeOS::SetProfileDelegate
, this, uuid
,
991 device_path
, delegate
, success_callback
, error_callback
),
995 void BluetoothAdapterChromeOS::ReleaseProfile(
996 const dbus::ObjectPath
& device_path
,
997 BluetoothAdapterProfileChromeOS
* profile
) {
998 VLOG(2) << "Releasing Profile: " << profile
->uuid().canonical_value()
999 << " from " << device_path
.value();
1000 profile
->RemoveDelegate(
1001 device_path
, base::Bind(&BluetoothAdapterChromeOS::RemoveProfile
,
1002 weak_ptr_factory_
.GetWeakPtr(), profile
->uuid()));
1005 void BluetoothAdapterChromeOS::RemoveProfile(const BluetoothUUID
& uuid
) {
1006 VLOG(2) << "Remove Profile: " << uuid
.canonical_value();
1008 if (profiles_
.find(uuid
) != profiles_
.end()) {
1009 delete profiles_
[uuid
];
1010 profiles_
.erase(uuid
);
1014 void BluetoothAdapterChromeOS::OnRegisterProfile(
1015 const BluetoothUUID
& uuid
,
1016 scoped_ptr
<BluetoothAdapterProfileChromeOS
> profile
) {
1017 profiles_
[uuid
] = profile
.release();
1019 if (profile_queues_
.find(uuid
) == profile_queues_
.end())
1022 for (auto& it
: *profile_queues_
[uuid
])
1024 delete profile_queues_
[uuid
];
1025 profile_queues_
.erase(uuid
);
1028 void BluetoothAdapterChromeOS::SetProfileDelegate(
1029 const BluetoothUUID
& uuid
,
1030 const dbus::ObjectPath
& device_path
,
1031 BluetoothProfileServiceProvider::Delegate
* delegate
,
1032 const ProfileRegisteredCallback
& success_callback
,
1033 const ErrorCompletionCallback
& error_callback
) {
1034 if (profiles_
.find(uuid
) == profiles_
.end()) {
1035 error_callback
.Run("Cannot find profile!");
1039 if (profiles_
[uuid
]->SetDelegate(device_path
, delegate
)) {
1040 success_callback
.Run(profiles_
[uuid
]);
1044 error_callback
.Run(bluetooth_agent_manager::kErrorAlreadyExists
);
1047 void BluetoothAdapterChromeOS::OnRegisterProfileError(
1048 const BluetoothUUID
& uuid
,
1049 const std::string
& error_name
,
1050 const std::string
& error_message
) {
1051 VLOG(2) << object_path_
.value() << ": Failed to register profile: "
1052 << error_name
<< ": " << error_message
;
1053 if (profile_queues_
.find(uuid
) == profile_queues_
.end())
1056 for (auto& it
: *profile_queues_
[uuid
])
1057 it
.second
.Run(error_message
);
1059 delete profile_queues_
[uuid
];
1060 profile_queues_
.erase(uuid
);
1063 void BluetoothAdapterChromeOS::OnSetDiscoverable(
1064 const base::Closure
& callback
,
1065 const ErrorCallback
& error_callback
,
1068 error_callback
.Run();
1072 // Set the discoverable_timeout property to zero so the adapter remains
1073 // discoverable forever.
1074 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1075 GetProperties(object_path_
)->discoverable_timeout
.Set(
1077 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted
,
1078 weak_ptr_factory_
.GetWeakPtr(),
1083 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
1084 const base::Closure
& callback
,
1085 const ErrorCallback
& error_callback
,
1087 if (IsPresent() && success
)
1090 error_callback
.Run();
1093 void BluetoothAdapterChromeOS::AddDiscoverySession(
1094 const base::Closure
& callback
,
1095 const ErrorCallback
& error_callback
) {
1097 error_callback
.Run();
1100 VLOG(1) << __func__
;
1101 if (discovery_request_pending_
) {
1102 // The pending request is either to stop a previous session or to start a
1103 // new one. Either way, queue this one.
1104 DCHECK(num_discovery_sessions_
== 1 || num_discovery_sessions_
== 0);
1105 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
1106 << "request to start a new discovery session.";
1107 discovery_request_queue_
.push(std::make_pair(callback
, error_callback
));
1111 // The adapter is already discovering.
1112 if (num_discovery_sessions_
> 0) {
1113 DCHECK(IsDiscovering());
1114 DCHECK(!discovery_request_pending_
);
1115 num_discovery_sessions_
++;
1120 // There are no active discovery sessions.
1121 DCHECK_EQ(num_discovery_sessions_
, 0);
1123 // This is the first request to start device discovery.
1124 discovery_request_pending_
= true;
1125 DBusThreadManager::Get()->GetBluetoothAdapterClient()->StartDiscovery(
1127 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery
,
1128 weak_ptr_factory_
.GetWeakPtr(), callback
, error_callback
),
1129 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError
,
1130 weak_ptr_factory_
.GetWeakPtr(), callback
, error_callback
));
1133 void BluetoothAdapterChromeOS::RemoveDiscoverySession(
1134 const base::Closure
& callback
,
1135 const ErrorCallback
& error_callback
) {
1137 error_callback
.Run();
1141 VLOG(1) << __func__
;
1142 // There are active sessions other than the one currently being removed.
1143 if (num_discovery_sessions_
> 1) {
1144 DCHECK(IsDiscovering());
1145 DCHECK(!discovery_request_pending_
);
1146 num_discovery_sessions_
--;
1151 // If there is a pending request to BlueZ, then queue this request.
1152 if (discovery_request_pending_
) {
1153 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
1154 << "request to stop discovery session.";
1155 error_callback
.Run();
1159 // There are no active sessions. Return error.
1160 if (num_discovery_sessions_
== 0) {
1161 // TODO(armansito): This should never happen once we have the
1162 // DiscoverySession API. Replace this case with an assert once it's
1163 // the deprecated methods have been removed. (See crbug.com/3445008).
1164 VLOG(1) << "No active discovery sessions. Returning error.";
1165 error_callback
.Run();
1169 // There is exactly one active discovery session. Request BlueZ to stop
1171 DCHECK_EQ(num_discovery_sessions_
, 1);
1172 discovery_request_pending_
= true;
1173 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1176 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery
,
1177 weak_ptr_factory_
.GetWeakPtr(),
1179 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError
,
1180 weak_ptr_factory_
.GetWeakPtr(),
1184 void BluetoothAdapterChromeOS::OnStartDiscovery(
1185 const base::Closure
& callback
,
1186 const ErrorCallback
& error_callback
) {
1187 // Report success on the original request and increment the count.
1188 VLOG(1) << __func__
;
1189 DCHECK(discovery_request_pending_
);
1190 DCHECK_EQ(num_discovery_sessions_
, 0);
1191 discovery_request_pending_
= false;
1192 num_discovery_sessions_
++;
1196 error_callback
.Run();
1198 // Try to add a new discovery session for each queued request.
1199 ProcessQueuedDiscoveryRequests();
1202 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
1203 const base::Closure
& callback
,
1204 const ErrorCallback
& error_callback
,
1205 const std::string
& error_name
,
1206 const std::string
& error_message
) {
1207 LOG(WARNING
) << object_path_
.value() << ": Failed to start discovery: "
1208 << error_name
<< ": " << error_message
;
1210 // Failed to start discovery. This can only happen if the count is at 0.
1211 DCHECK_EQ(num_discovery_sessions_
, 0);
1212 DCHECK(discovery_request_pending_
);
1213 discovery_request_pending_
= false;
1215 // Discovery request may fail if discovery was previously initiated by Chrome,
1216 // but the session were invalidated due to the discovery state unexpectedly
1217 // changing to false and then back to true. In this case, report success.
1218 if (IsPresent() && error_name
== bluetooth_device::kErrorInProgress
&&
1220 VLOG(1) << "Discovery previously initiated. Reporting success.";
1221 num_discovery_sessions_
++;
1224 error_callback
.Run();
1227 // Try to add a new discovery session for each queued request.
1228 ProcessQueuedDiscoveryRequests();
1231 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure
& callback
) {
1232 // Report success on the original request and decrement the count.
1233 VLOG(1) << __func__
;
1234 DCHECK(discovery_request_pending_
);
1235 DCHECK_EQ(num_discovery_sessions_
, 1);
1236 discovery_request_pending_
= false;
1237 num_discovery_sessions_
--;
1240 // Try to add a new discovery session for each queued request.
1241 ProcessQueuedDiscoveryRequests();
1244 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
1245 const ErrorCallback
& error_callback
,
1246 const std::string
& error_name
,
1247 const std::string
& error_message
) {
1248 LOG(WARNING
) << object_path_
.value() << ": Failed to stop discovery: "
1249 << error_name
<< ": " << error_message
;
1251 // Failed to stop discovery. This can only happen if the count is at 1.
1252 DCHECK(discovery_request_pending_
);
1253 DCHECK_EQ(num_discovery_sessions_
, 1);
1254 discovery_request_pending_
= false;
1255 error_callback
.Run();
1257 // Try to add a new discovery session for each queued request.
1258 ProcessQueuedDiscoveryRequests();
1261 void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
1262 while (!discovery_request_queue_
.empty()) {
1263 VLOG(1) << "Process queued discovery request.";
1264 DiscoveryCallbackPair callbacks
= discovery_request_queue_
.front();
1265 discovery_request_queue_
.pop();
1266 AddDiscoverySession(callbacks
.first
, callbacks
.second
);
1268 // If the queued request resulted in a pending call, then let it
1269 // asynchonously process the remaining queued requests once the pending
1271 if (discovery_request_pending_
)
1276 } // namespace chromeos