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
) {
365 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
) {
383 BluetoothDeviceClient::Properties
* properties
=
384 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
385 GetProperties(object_path
);
386 if (properties
->adapter
.value() != object_path_
)
389 BluetoothDeviceChromeOS
* device_chromeos
=
390 new BluetoothDeviceChromeOS(this,
394 DCHECK(devices_
.find(device_chromeos
->GetAddress()) == devices_
.end());
396 devices_
[device_chromeos
->GetAddress()] = device_chromeos
;
398 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
399 DeviceAdded(this, device_chromeos
));
402 void BluetoothAdapterChromeOS::DeviceRemoved(
403 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
) {
424 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(object_path
);
425 if (!device_chromeos
)
428 BluetoothDeviceClient::Properties
* properties
=
429 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
430 GetProperties(object_path
);
432 if (property_name
== properties
->bluetooth_class
.name() ||
433 property_name
== properties
->address
.name() ||
434 property_name
== properties
->alias
.name() ||
435 property_name
== properties
->paired
.name() ||
436 property_name
== properties
->trusted
.name() ||
437 property_name
== properties
->connected
.name() ||
438 property_name
== properties
->uuids
.name() ||
439 property_name
== properties
->rssi
.name())
440 NotifyDeviceChanged(device_chromeos
);
442 // When a device becomes paired, mark it as trusted so that the user does
443 // not need to approve every incoming connection
444 if (property_name
== properties
->paired
.name() &&
445 properties
->paired
.value() && !properties
->trusted
.value())
446 device_chromeos
->SetTrusted();
448 // UMA connection counting
449 if (property_name
== properties
->connected
.name()) {
450 // PlayStation joystick tries to reconnect after disconnection from USB.
451 // If it is still not trusted, set it, so it becomes available on the
452 // list of known devices.
453 if (properties
->connected
.value() && device_chromeos
->IsTrustable() &&
454 !properties
->trusted
.value())
455 device_chromeos
->SetTrusted();
459 for (DevicesMap::iterator iter
= devices_
.begin();
460 iter
!= devices_
.end(); ++iter
) {
461 if (iter
->second
->IsPaired() && iter
->second
->IsConnected())
465 UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count
);
469 void BluetoothAdapterChromeOS::InputPropertyChanged(
470 const dbus::ObjectPath
& object_path
,
471 const std::string
& property_name
) {
473 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(object_path
);
474 if (!device_chromeos
)
477 BluetoothInputClient::Properties
* properties
=
478 DBusThreadManager::Get()->GetBluetoothInputClient()->
479 GetProperties(object_path
);
481 // Properties structure can be removed, which triggers a change in the
482 // BluetoothDevice::IsConnectable() property, as does a change in the
483 // actual reconnect_mode property.
485 property_name
== properties
->reconnect_mode
.name())
486 NotifyDeviceChanged(device_chromeos
);
489 void BluetoothAdapterChromeOS::Released() {
490 VLOG(1) << "Release";
493 DCHECK(agent_
.get());
495 // Called after we unregister the pairing agent, e.g. when changing I/O
496 // capabilities. Nothing much to be done right now.
499 void BluetoothAdapterChromeOS::RequestPinCode(
500 const dbus::ObjectPath
& device_path
,
501 const PinCodeCallback
& callback
) {
503 DCHECK(agent_
.get());
504 VLOG(1) << device_path
.value() << ": RequestPinCode";
506 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
508 callback
.Run(REJECTED
, "");
512 pairing
->RequestPinCode(callback
);
515 void BluetoothAdapterChromeOS::DisplayPinCode(
516 const dbus::ObjectPath
& device_path
,
517 const std::string
& pincode
) {
519 DCHECK(agent_
.get());
520 VLOG(1) << device_path
.value() << ": DisplayPinCode: " << pincode
;
522 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
526 pairing
->DisplayPinCode(pincode
);
529 void BluetoothAdapterChromeOS::RequestPasskey(
530 const dbus::ObjectPath
& device_path
,
531 const PasskeyCallback
& callback
) {
533 DCHECK(agent_
.get());
534 VLOG(1) << device_path
.value() << ": RequestPasskey";
536 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
538 callback
.Run(REJECTED
, 0);
542 pairing
->RequestPasskey(callback
);
545 void BluetoothAdapterChromeOS::DisplayPasskey(
546 const dbus::ObjectPath
& device_path
,
550 DCHECK(agent_
.get());
551 VLOG(1) << device_path
.value() << ": DisplayPasskey: " << passkey
552 << " (" << entered
<< " entered)";
554 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
559 pairing
->DisplayPasskey(passkey
);
561 pairing
->KeysEntered(entered
);
564 void BluetoothAdapterChromeOS::RequestConfirmation(
565 const dbus::ObjectPath
& device_path
,
567 const ConfirmationCallback
& callback
) {
569 DCHECK(agent_
.get());
570 VLOG(1) << device_path
.value() << ": RequestConfirmation: " << passkey
;
572 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
574 callback
.Run(REJECTED
);
578 pairing
->RequestConfirmation(passkey
, callback
);
581 void BluetoothAdapterChromeOS::RequestAuthorization(
582 const dbus::ObjectPath
& device_path
,
583 const ConfirmationCallback
& callback
) {
585 DCHECK(agent_
.get());
586 VLOG(1) << device_path
.value() << ": RequestAuthorization";
588 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
590 callback
.Run(REJECTED
);
594 pairing
->RequestAuthorization(callback
);
597 void BluetoothAdapterChromeOS::AuthorizeService(
598 const dbus::ObjectPath
& device_path
,
599 const std::string
& uuid
,
600 const ConfirmationCallback
& callback
) {
602 DCHECK(agent_
.get());
603 VLOG(1) << device_path
.value() << ": AuthorizeService: " << uuid
;
605 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(device_path
);
606 if (!device_chromeos
) {
607 callback
.Run(CANCELLED
);
611 // We always set paired devices to Trusted, so the only reason that this
612 // method call would ever be called is in the case of a race condition where
613 // our "Set('Trusted', true)" method call is still pending in the Bluetooth
614 // daemon because it's busy handling the incoming connection.
615 if (device_chromeos
->IsPaired()) {
616 callback
.Run(SUCCESS
);
620 // TODO(keybuk): reject service authorizations when not paired, determine
621 // whether this is acceptable long-term.
622 LOG(WARNING
) << "Rejecting service connection from unpaired device "
623 << device_chromeos
->GetAddress() << " for UUID " << uuid
;
624 callback
.Run(REJECTED
);
627 void BluetoothAdapterChromeOS::Cancel() {
629 DCHECK(agent_
.get());
633 void BluetoothAdapterChromeOS::OnRegisterAgent() {
634 VLOG(1) << "Pairing agent registered, requesting to be made default";
636 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
638 dbus::ObjectPath(kAgentPath
),
639 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent
,
640 weak_ptr_factory_
.GetWeakPtr()),
641 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError
,
642 weak_ptr_factory_
.GetWeakPtr()));
645 void BluetoothAdapterChromeOS::OnRegisterAgentError(
646 const std::string
& error_name
,
647 const std::string
& error_message
) {
648 // Our agent being already registered isn't an error.
649 if (error_name
== bluetooth_agent_manager::kErrorAlreadyExists
)
652 LOG(WARNING
) << ": Failed to register pairing agent: "
653 << error_name
<< ": " << error_message
;
656 void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
657 VLOG(1) << "Pairing agent now default";
660 void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
661 const std::string
& error_name
,
662 const std::string
& error_message
) {
663 LOG(WARNING
) << ": Failed to make pairing agent default: "
664 << error_name
<< ": " << error_message
;
667 void BluetoothAdapterChromeOS::OnRegisterAudioSink(
668 const device::BluetoothAdapter::AcquiredCallback
& callback
,
669 const device::BluetoothAudioSink::ErrorCallback
& error_callback
,
670 scoped_refptr
<BluetoothAudioSink
> audio_sink
) {
672 VLOG(1) << "Failed to register audio sink, adapter not present";
673 error_callback
.Run(BluetoothAudioSink::ERROR_INVALID_ADAPTER
);
676 DCHECK(audio_sink
.get());
677 callback
.Run(audio_sink
);
680 BluetoothDeviceChromeOS
*
681 BluetoothAdapterChromeOS::GetDeviceWithPath(
682 const dbus::ObjectPath
& object_path
) {
686 for (DevicesMap::iterator iter
= devices_
.begin(); iter
!= devices_
.end();
688 BluetoothDeviceChromeOS
* device_chromeos
=
689 static_cast<BluetoothDeviceChromeOS
*>(iter
->second
);
690 if (device_chromeos
->object_path() == object_path
)
691 return device_chromeos
;
697 BluetoothPairingChromeOS
* BluetoothAdapterChromeOS::GetPairing(
698 const dbus::ObjectPath
& object_path
) {
700 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(object_path
);
701 if (!device_chromeos
) {
702 LOG(WARNING
) << "Pairing Agent request for unknown device: "
703 << object_path
.value();
707 BluetoothPairingChromeOS
* pairing
= device_chromeos
->GetPairing();
711 // The device doesn't have its own pairing context, so this is an incoming
712 // pairing request that should use our best default delegate (if we have one).
713 BluetoothDevice::PairingDelegate
* pairing_delegate
= DefaultPairingDelegate();
714 if (!pairing_delegate
)
717 return device_chromeos
->BeginPairing(pairing_delegate
);
720 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath
& object_path
) {
721 DCHECK(!IsPresent());
722 DCHECK(!dbus_is_shutdown_
);
723 object_path_
= object_path
;
725 VLOG(1) << object_path_
.value() << ": using adapter.";
727 VLOG(1) << "Registering pairing agent";
728 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
730 dbus::ObjectPath(kAgentPath
),
731 bluetooth_agent_manager::kKeyboardDisplayCapability
,
732 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent
,
733 weak_ptr_factory_
.GetWeakPtr()),
734 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError
,
735 weak_ptr_factory_
.GetWeakPtr()));
737 SetDefaultAdapterName();
739 BluetoothAdapterClient::Properties
* properties
=
740 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
741 GetProperties(object_path_
);
743 PresentChanged(true);
745 if (properties
->powered
.value())
746 PoweredChanged(true);
747 if (properties
->discoverable
.value())
748 DiscoverableChanged(true);
749 if (properties
->discovering
.value())
750 DiscoveringChanged(true);
752 std::vector
<dbus::ObjectPath
> device_paths
=
753 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
754 GetDevicesForAdapter(object_path_
);
756 for (std::vector
<dbus::ObjectPath
>::iterator iter
= device_paths
.begin();
757 iter
!= device_paths
.end(); ++iter
) {
762 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
764 std::string board
= base::SysInfo::GetLsbReleaseBoard();
766 if (board
.substr(0, 6) == "stumpy") {
768 } else if (board
.substr(0, 4) == "link") {
769 alias
= "Chromebook Pixel";
771 alias
= "Chromebook";
774 SetName(alias
, base::Bind(&base::DoNothing
), base::Bind(&base::DoNothing
));
777 void BluetoothAdapterChromeOS::RemoveAdapter() {
779 VLOG(1) << object_path_
.value() << ": adapter removed.";
781 BluetoothAdapterClient::Properties
* properties
=
782 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
783 GetProperties(object_path_
);
785 object_path_
= dbus::ObjectPath("");
787 if (properties
->powered
.value())
788 PoweredChanged(false);
789 if (properties
->discoverable
.value())
790 DiscoverableChanged(false);
791 if (properties
->discovering
.value())
792 DiscoveringChanged(false);
794 // Copy the devices list here and clear the original so that when we
795 // send DeviceRemoved(), GetDevices() returns no devices.
796 DevicesMap devices
= devices_
;
799 for (DevicesMap::iterator iter
= devices
.begin();
800 iter
!= devices
.end(); ++iter
) {
801 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
802 DeviceRemoved(this, iter
->second
));
806 PresentChanged(false);
809 void BluetoothAdapterChromeOS::PoweredChanged(bool powered
) {
810 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
811 AdapterPoweredChanged(this, powered
));
814 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable
) {
815 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
816 AdapterDiscoverableChanged(this, discoverable
));
819 void BluetoothAdapterChromeOS::DiscoveringChanged(
821 // If the adapter stopped discovery due to a reason other than a request by
822 // us, reset the count to 0.
823 VLOG(1) << "Discovering changed: " << discovering
;
824 if (!discovering
&& !discovery_request_pending_
825 && num_discovery_sessions_
> 0) {
826 VLOG(1) << "Marking sessions as inactive.";
827 num_discovery_sessions_
= 0;
828 MarkDiscoverySessionsAsInactive();
830 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
831 AdapterDiscoveringChanged(this, discovering
));
834 void BluetoothAdapterChromeOS::PresentChanged(bool present
) {
835 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
836 AdapterPresentChanged(this, present
));
839 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
840 BluetoothDeviceChromeOS
* device
) {
841 DCHECK(device
->adapter_
== this);
843 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
844 DeviceChanged(this, device
));
847 void BluetoothAdapterChromeOS::NotifyGattServiceAdded(
848 BluetoothRemoteGattServiceChromeOS
* service
) {
849 DCHECK_EQ(service
->GetAdapter(), this);
851 static_cast<BluetoothDeviceChromeOS
*>(service
->GetDevice())->adapter_
,
854 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
856 GattServiceAdded(this, service
->GetDevice(), service
));
859 void BluetoothAdapterChromeOS::NotifyGattServiceRemoved(
860 BluetoothRemoteGattServiceChromeOS
* service
) {
861 DCHECK_EQ(service
->GetAdapter(), this);
863 static_cast<BluetoothDeviceChromeOS
*>(service
->GetDevice())->adapter_
,
866 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
868 GattServiceRemoved(this, service
->GetDevice(), service
));
871 void BluetoothAdapterChromeOS::NotifyGattServiceChanged(
872 BluetoothRemoteGattServiceChromeOS
* service
) {
873 DCHECK_EQ(service
->GetAdapter(), this);
875 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
877 GattServiceChanged(this, service
));
880 void BluetoothAdapterChromeOS::NotifyGattDiscoveryComplete(
881 BluetoothRemoteGattServiceChromeOS
* service
) {
882 DCHECK_EQ(service
->GetAdapter(), this);
884 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
886 GattDiscoveryCompleteForService(this, service
));
889 void BluetoothAdapterChromeOS::NotifyGattCharacteristicAdded(
890 BluetoothRemoteGattCharacteristicChromeOS
* characteristic
) {
891 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS
*>(
892 characteristic
->GetService())->GetAdapter(),
895 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
897 GattCharacteristicAdded(this, characteristic
));
900 void BluetoothAdapterChromeOS::NotifyGattCharacteristicRemoved(
901 BluetoothRemoteGattCharacteristicChromeOS
* characteristic
) {
902 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS
*>(
903 characteristic
->GetService())->GetAdapter(),
906 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
908 GattCharacteristicRemoved(this, characteristic
));
911 void BluetoothAdapterChromeOS::NotifyGattDescriptorAdded(
912 BluetoothRemoteGattDescriptorChromeOS
* descriptor
) {
913 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS
*>(
914 descriptor
->GetCharacteristic()->GetService())->GetAdapter(),
917 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
919 GattDescriptorAdded(this, descriptor
));
922 void BluetoothAdapterChromeOS::NotifyGattDescriptorRemoved(
923 BluetoothRemoteGattDescriptorChromeOS
* descriptor
) {
924 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS
*>(
925 descriptor
->GetCharacteristic()->GetService())->GetAdapter(),
928 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
930 GattDescriptorRemoved(this, descriptor
));
933 void BluetoothAdapterChromeOS::NotifyGattCharacteristicValueChanged(
934 BluetoothRemoteGattCharacteristicChromeOS
* characteristic
,
935 const std::vector
<uint8
>& value
) {
936 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS
*>(
937 characteristic
->GetService())->GetAdapter(),
941 BluetoothAdapter::Observer
,
943 GattCharacteristicValueChanged(this, characteristic
, value
));
946 void BluetoothAdapterChromeOS::NotifyGattDescriptorValueChanged(
947 BluetoothRemoteGattDescriptorChromeOS
* descriptor
,
948 const std::vector
<uint8
>& value
) {
949 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS
*>(
950 descriptor
->GetCharacteristic()->GetService())->GetAdapter(),
953 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
,
955 GattDescriptorValueChanged(this, descriptor
, value
));
958 void BluetoothAdapterChromeOS::UseProfile(
959 const BluetoothUUID
& uuid
,
960 const dbus::ObjectPath
& device_path
,
961 const BluetoothProfileManagerClient::Options
& options
,
962 BluetoothProfileServiceProvider::Delegate
* delegate
,
963 const ProfileRegisteredCallback
& success_callback
,
964 const ErrorCompletionCallback
& error_callback
) {
968 VLOG(2) << "Adapter not present, erroring out";
969 error_callback
.Run("Adapter not present");
973 if (profiles_
.find(uuid
) != profiles_
.end()) {
974 // TODO(jamuraa) check that the options are the same and error when they are
976 SetProfileDelegate(uuid
, device_path
, delegate
, success_callback
,
981 if (profile_queues_
.find(uuid
) == profile_queues_
.end()) {
982 BluetoothAdapterProfileChromeOS::Register(
984 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfile
, this, uuid
),
985 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfileError
, this,
988 profile_queues_
[uuid
] = new std::vector
<RegisterProfileCompletionPair
>();
991 profile_queues_
[uuid
]->push_back(std::make_pair(
992 base::Bind(&BluetoothAdapterChromeOS::SetProfileDelegate
, this, uuid
,
993 device_path
, delegate
, success_callback
, error_callback
),
997 void BluetoothAdapterChromeOS::ReleaseProfile(
998 const dbus::ObjectPath
& device_path
,
999 BluetoothAdapterProfileChromeOS
* profile
) {
1000 VLOG(2) << "Releasing Profile: " << profile
->uuid().canonical_value()
1001 << " from " << device_path
.value();
1002 profile
->RemoveDelegate(
1003 device_path
, base::Bind(&BluetoothAdapterChromeOS::RemoveProfile
,
1004 weak_ptr_factory_
.GetWeakPtr(), profile
->uuid()));
1007 void BluetoothAdapterChromeOS::RemoveProfile(const BluetoothUUID
& uuid
) {
1008 VLOG(2) << "Remove Profile: " << uuid
.canonical_value();
1010 if (profiles_
.find(uuid
) != profiles_
.end()) {
1011 delete profiles_
[uuid
];
1012 profiles_
.erase(uuid
);
1016 void BluetoothAdapterChromeOS::OnRegisterProfile(
1017 const BluetoothUUID
& uuid
,
1018 BluetoothAdapterProfileChromeOS
* profile
) {
1019 profiles_
[uuid
] = profile
;
1021 if (profile_queues_
.find(uuid
) == profile_queues_
.end())
1024 for (auto& it
: *profile_queues_
[uuid
])
1026 delete profile_queues_
[uuid
];
1027 profile_queues_
.erase(uuid
);
1030 void BluetoothAdapterChromeOS::SetProfileDelegate(
1031 const BluetoothUUID
& uuid
,
1032 const dbus::ObjectPath
& device_path
,
1033 BluetoothProfileServiceProvider::Delegate
* delegate
,
1034 const ProfileRegisteredCallback
& success_callback
,
1035 const ErrorCompletionCallback
& error_callback
) {
1037 if (profiles_
.find(uuid
) == profiles_
.end()) {
1038 error_callback
.Run("Cannot find profile!");
1042 if (profiles_
[uuid
]->SetDelegate(device_path
, delegate
)) {
1043 success_callback
.Run(profiles_
[uuid
]);
1047 error_callback
.Run(bluetooth_agent_manager::kErrorAlreadyExists
);
1050 void BluetoothAdapterChromeOS::OnRegisterProfileError(
1051 const BluetoothUUID
& uuid
,
1052 const std::string
& error_name
,
1053 const std::string
& error_message
) {
1054 VLOG(2) << object_path_
.value() << ": Failed to register profile: "
1055 << error_name
<< ": " << error_message
;
1056 if (profile_queues_
.find(uuid
) == profile_queues_
.end())
1059 for (auto& it
: *profile_queues_
[uuid
])
1060 it
.second
.Run(error_message
);
1062 delete profile_queues_
[uuid
];
1063 profile_queues_
.erase(uuid
);
1066 void BluetoothAdapterChromeOS::OnSetDiscoverable(
1067 const base::Closure
& callback
,
1068 const ErrorCallback
& error_callback
,
1071 error_callback
.Run();
1075 // Set the discoverable_timeout property to zero so the adapter remains
1076 // discoverable forever.
1077 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1078 GetProperties(object_path_
)->discoverable_timeout
.Set(
1080 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted
,
1081 weak_ptr_factory_
.GetWeakPtr(),
1086 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
1087 const base::Closure
& callback
,
1088 const ErrorCallback
& error_callback
,
1090 if (IsPresent() && success
)
1093 error_callback
.Run();
1096 void BluetoothAdapterChromeOS::AddDiscoverySession(
1097 const base::Closure
& callback
,
1098 const ErrorCallback
& error_callback
) {
1100 error_callback
.Run();
1103 VLOG(1) << __func__
;
1104 if (discovery_request_pending_
) {
1105 // The pending request is either to stop a previous session or to start a
1106 // new one. Either way, queue this one.
1107 DCHECK(num_discovery_sessions_
== 1 || num_discovery_sessions_
== 0);
1108 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
1109 << "request to start a new discovery session.";
1110 discovery_request_queue_
.push(std::make_pair(callback
, error_callback
));
1114 // The adapter is already discovering.
1115 if (num_discovery_sessions_
> 0) {
1116 DCHECK(IsDiscovering());
1117 DCHECK(!discovery_request_pending_
);
1118 num_discovery_sessions_
++;
1123 // There are no active discovery sessions.
1124 DCHECK_EQ(num_discovery_sessions_
, 0);
1126 // This is the first request to start device discovery.
1127 discovery_request_pending_
= true;
1128 DBusThreadManager::Get()->GetBluetoothAdapterClient()->StartDiscovery(
1130 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery
,
1131 weak_ptr_factory_
.GetWeakPtr(), callback
, error_callback
),
1132 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError
,
1133 weak_ptr_factory_
.GetWeakPtr(), callback
, error_callback
));
1136 void BluetoothAdapterChromeOS::RemoveDiscoverySession(
1137 const base::Closure
& callback
,
1138 const ErrorCallback
& error_callback
) {
1140 error_callback
.Run();
1144 VLOG(1) << __func__
;
1145 // There are active sessions other than the one currently being removed.
1146 if (num_discovery_sessions_
> 1) {
1147 DCHECK(IsDiscovering());
1148 DCHECK(!discovery_request_pending_
);
1149 num_discovery_sessions_
--;
1154 // If there is a pending request to BlueZ, then queue this request.
1155 if (discovery_request_pending_
) {
1156 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
1157 << "request to stop discovery session.";
1158 error_callback
.Run();
1162 // There are no active sessions. Return error.
1163 if (num_discovery_sessions_
== 0) {
1164 // TODO(armansito): This should never happen once we have the
1165 // DiscoverySession API. Replace this case with an assert once it's
1166 // the deprecated methods have been removed. (See crbug.com/3445008).
1167 VLOG(1) << "No active discovery sessions. Returning error.";
1168 error_callback
.Run();
1172 // There is exactly one active discovery session. Request BlueZ to stop
1174 DCHECK_EQ(num_discovery_sessions_
, 1);
1175 discovery_request_pending_
= true;
1176 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1179 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery
,
1180 weak_ptr_factory_
.GetWeakPtr(),
1182 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError
,
1183 weak_ptr_factory_
.GetWeakPtr(),
1187 void BluetoothAdapterChromeOS::OnStartDiscovery(
1188 const base::Closure
& callback
,
1189 const ErrorCallback
& error_callback
) {
1190 // Report success on the original request and increment the count.
1191 VLOG(1) << __func__
;
1192 DCHECK(discovery_request_pending_
);
1193 DCHECK_EQ(num_discovery_sessions_
, 0);
1194 discovery_request_pending_
= false;
1195 num_discovery_sessions_
++;
1199 error_callback
.Run();
1201 // Try to add a new discovery session for each queued request.
1202 ProcessQueuedDiscoveryRequests();
1205 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
1206 const base::Closure
& callback
,
1207 const ErrorCallback
& error_callback
,
1208 const std::string
& error_name
,
1209 const std::string
& error_message
) {
1210 LOG(WARNING
) << object_path_
.value() << ": Failed to start discovery: "
1211 << error_name
<< ": " << error_message
;
1213 // Failed to start discovery. This can only happen if the count is at 0.
1214 DCHECK_EQ(num_discovery_sessions_
, 0);
1215 DCHECK(discovery_request_pending_
);
1216 discovery_request_pending_
= false;
1218 // Discovery request may fail if discovery was previously initiated by Chrome,
1219 // but the session were invalidated due to the discovery state unexpectedly
1220 // changing to false and then back to true. In this case, report success.
1221 if (IsPresent() && error_name
== bluetooth_device::kErrorInProgress
&&
1223 VLOG(1) << "Discovery previously initiated. Reporting success.";
1224 num_discovery_sessions_
++;
1227 error_callback
.Run();
1230 // Try to add a new discovery session for each queued request.
1231 ProcessQueuedDiscoveryRequests();
1234 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure
& callback
) {
1235 // Report success on the original request and decrement the count.
1236 VLOG(1) << __func__
;
1237 DCHECK(discovery_request_pending_
);
1238 DCHECK_EQ(num_discovery_sessions_
, 1);
1239 discovery_request_pending_
= false;
1240 num_discovery_sessions_
--;
1243 // Try to add a new discovery session for each queued request.
1244 ProcessQueuedDiscoveryRequests();
1247 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
1248 const ErrorCallback
& error_callback
,
1249 const std::string
& error_name
,
1250 const std::string
& error_message
) {
1251 LOG(WARNING
) << object_path_
.value() << ": Failed to stop discovery: "
1252 << error_name
<< ": " << error_message
;
1254 // Failed to stop discovery. This can only happen if the count is at 1.
1255 DCHECK(discovery_request_pending_
);
1256 DCHECK_EQ(num_discovery_sessions_
, 1);
1257 discovery_request_pending_
= false;
1258 error_callback
.Run();
1260 // Try to add a new discovery session for each queued request.
1261 ProcessQueuedDiscoveryRequests();
1264 void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
1265 while (!discovery_request_queue_
.empty()) {
1266 VLOG(1) << "Process queued discovery request.";
1267 DiscoveryCallbackPair callbacks
= discovery_request_queue_
.front();
1268 discovery_request_queue_
.pop();
1269 AddDiscoverySession(callbacks
.first
, callbacks
.second
);
1271 // If the queued request resulted in a pending call, then let it
1272 // asynchonously process the remaining queued requests once the pending
1274 if (discovery_request_pending_
)
1279 } // namespace chromeos