Revert of "Log force-alt-protocols command line flag usage".
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_chromeos.cc
blobedd0f0154fc145fa222fd07d29962de1d95d1d33
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"
7 #include <string>
9 #include "base/bind.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;
42 namespace {
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)
52 return;
54 LOG(WARNING) << "Failed to unregister pairing agent: "
55 << error_name << ": " << error_message;
58 } // namespace
60 namespace device {
62 // static
63 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
64 const InitCallback& init_callback) {
65 return chromeos::BluetoothAdapterChromeOS::CreateAdapter();
70 namespace chromeos {
72 // static
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_)
80 return;
81 DCHECK(DBusThreadManager::IsInitialized())
82 << "Call BluetoothAdapterFactory::Shutdown() before "
83 "DBusThreadManager::Shutdown().";
85 if (IsPresent())
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_)
93 delete it.second;
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));
105 agent_.reset();
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() {
137 Shutdown();
140 void BluetoothAdapterChromeOS::DeleteOnCorrectThread() const {
141 if (ui_task_runner_->RunsTasksOnCurrentThread() ||
142 !ui_task_runner_->DeleteSoon(FROM_HERE, this))
143 delete this;
146 void BluetoothAdapterChromeOS::AddObserver(
147 BluetoothAdapter::Observer* observer) {
148 DCHECK(observer);
149 observers_.AddObserver(observer);
152 void BluetoothAdapterChromeOS::RemoveObserver(
153 BluetoothAdapter::Observer* observer) {
154 DCHECK(observer);
155 observers_.RemoveObserver(observer);
158 std::string BluetoothAdapterChromeOS::GetAddress() const {
159 if (!IsPresent())
160 return std::string();
162 BluetoothAdapterClient::Properties* properties =
163 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
164 GetProperties(object_path_);
165 DCHECK(properties);
167 return BluetoothDevice::CanonicalizeAddress(properties->address.value());
170 std::string BluetoothAdapterChromeOS::GetName() const {
171 if (!IsPresent())
172 return std::string();
174 BluetoothAdapterClient::Properties* properties =
175 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
176 GetProperties(object_path_);
177 DCHECK(properties);
179 return properties->alias.value();
182 void BluetoothAdapterChromeOS::SetName(const std::string& name,
183 const base::Closure& callback,
184 const ErrorCallback& error_callback) {
185 if (!IsPresent()) {
186 error_callback.Run();
187 return;
190 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
191 GetProperties(object_path_)->alias.Set(
192 name,
193 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
194 weak_ptr_factory_.GetWeakPtr(),
195 callback,
196 error_callback));
199 bool BluetoothAdapterChromeOS::IsInitialized() const {
200 return true;
203 bool BluetoothAdapterChromeOS::IsPresent() const {
204 return !dbus_is_shutdown_ && !object_path_.value().empty();
207 bool BluetoothAdapterChromeOS::IsPowered() const {
208 if (!IsPresent())
209 return false;
211 BluetoothAdapterClient::Properties* properties =
212 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
213 GetProperties(object_path_);
215 return properties->powered.value();
218 void BluetoothAdapterChromeOS::SetPowered(
219 bool powered,
220 const base::Closure& callback,
221 const ErrorCallback& error_callback) {
222 if (!IsPresent()) {
223 error_callback.Run();
224 return;
227 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
228 GetProperties(object_path_)->powered.Set(
229 powered,
230 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
231 weak_ptr_factory_.GetWeakPtr(),
232 callback,
233 error_callback));
236 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
237 if (!IsPresent())
238 return false;
240 BluetoothAdapterClient::Properties* properties =
241 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
242 GetProperties(object_path_);
244 return properties->discoverable.value();
247 void BluetoothAdapterChromeOS::SetDiscoverable(
248 bool discoverable,
249 const base::Closure& callback,
250 const ErrorCallback& error_callback) {
251 if (!IsPresent()) {
252 error_callback.Run();
253 return;
256 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
257 GetProperties(object_path_)->discoverable.Set(
258 discoverable,
259 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable,
260 weak_ptr_factory_.GetWeakPtr(),
261 callback,
262 error_callback));
265 bool BluetoothAdapterChromeOS::IsDiscovering() const {
266 if (!IsPresent())
267 return false;
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_);
287 socket->Listen(this,
288 BluetoothSocketChromeOS::kRfcomm,
289 uuid,
290 options,
291 base::Bind(callback, socket),
292 error_callback);
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_);
306 socket->Listen(this,
307 BluetoothSocketChromeOS::kL2cap,
308 uuid,
309 options,
310 base::Bind(callback, socket),
311 error_callback);
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);
321 return;
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),
329 error_callback);
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.
351 if (!IsPresent())
352 SetAdapter(object_path);
355 void BluetoothAdapterChromeOS::AdapterRemoved(
356 const dbus::ObjectPath& object_path) {
357 if (object_path == object_path_)
358 RemoveAdapter();
361 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
362 const dbus::ObjectPath& object_path,
363 const std::string& property_name) {
364 if (object_path != object_path_)
365 return;
366 DCHECK(IsPresent());
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_)
387 return;
388 DCHECK(IsPresent());
390 BluetoothDeviceChromeOS* device_chromeos =
391 new BluetoothDeviceChromeOS(this,
392 object_path,
393 ui_task_runner_,
394 socket_thread_);
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;
415 return;
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)
425 return;
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();
456 int count = 0;
458 for (DevicesMap::iterator iter = devices_.begin();
459 iter != devices_.end(); ++iter) {
460 if (iter->second->IsPaired() && iter->second->IsConnected())
461 ++count;
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)
473 return;
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.
482 if (!properties ||
483 property_name == properties->reconnect_mode.name())
484 NotifyDeviceChanged(device_chromeos);
487 void BluetoothAdapterChromeOS::Released() {
488 VLOG(1) << "Release";
489 if (!IsPresent())
490 return;
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) {
500 DCHECK(IsPresent());
501 DCHECK(agent_.get());
502 VLOG(1) << device_path.value() << ": RequestPinCode";
504 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
505 if (!pairing) {
506 callback.Run(REJECTED, "");
507 return;
510 pairing->RequestPinCode(callback);
513 void BluetoothAdapterChromeOS::DisplayPinCode(
514 const dbus::ObjectPath& device_path,
515 const std::string& pincode) {
516 DCHECK(IsPresent());
517 DCHECK(agent_.get());
518 VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
520 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
521 if (!pairing)
522 return;
524 pairing->DisplayPinCode(pincode);
527 void BluetoothAdapterChromeOS::RequestPasskey(
528 const dbus::ObjectPath& device_path,
529 const PasskeyCallback& callback) {
530 DCHECK(IsPresent());
531 DCHECK(agent_.get());
532 VLOG(1) << device_path.value() << ": RequestPasskey";
534 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
535 if (!pairing) {
536 callback.Run(REJECTED, 0);
537 return;
540 pairing->RequestPasskey(callback);
543 void BluetoothAdapterChromeOS::DisplayPasskey(
544 const dbus::ObjectPath& device_path,
545 uint32 passkey,
546 uint16 entered) {
547 DCHECK(IsPresent());
548 DCHECK(agent_.get());
549 VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
550 << " (" << entered << " entered)";
552 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
553 if (!pairing)
554 return;
556 if (entered == 0)
557 pairing->DisplayPasskey(passkey);
559 pairing->KeysEntered(entered);
562 void BluetoothAdapterChromeOS::RequestConfirmation(
563 const dbus::ObjectPath& device_path,
564 uint32 passkey,
565 const ConfirmationCallback& callback) {
566 DCHECK(IsPresent());
567 DCHECK(agent_.get());
568 VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
570 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
571 if (!pairing) {
572 callback.Run(REJECTED);
573 return;
576 pairing->RequestConfirmation(passkey, callback);
579 void BluetoothAdapterChromeOS::RequestAuthorization(
580 const dbus::ObjectPath& device_path,
581 const ConfirmationCallback& callback) {
582 DCHECK(IsPresent());
583 DCHECK(agent_.get());
584 VLOG(1) << device_path.value() << ": RequestAuthorization";
586 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
587 if (!pairing) {
588 callback.Run(REJECTED);
589 return;
592 pairing->RequestAuthorization(callback);
595 void BluetoothAdapterChromeOS::AuthorizeService(
596 const dbus::ObjectPath& device_path,
597 const std::string& uuid,
598 const ConfirmationCallback& callback) {
599 DCHECK(IsPresent());
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);
606 return;
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);
615 return;
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() {
626 DCHECK(IsPresent());
627 DCHECK(agent_.get());
628 VLOG(1) << "Cancel";
631 void BluetoothAdapterChromeOS::OnRegisterAgent() {
632 VLOG(1) << "Pairing agent registered, requesting to be made default";
634 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
635 RequestDefaultAgent(
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)
648 return;
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) {
669 if (!IsPresent()) {
670 VLOG(1) << "Failed to register audio sink, adapter not present";
671 error_callback.Run(BluetoothAudioSink::ERROR_INVALID_ADAPTER);
672 return;
674 DCHECK(audio_sink.get());
675 callback.Run(audio_sink);
678 BluetoothDeviceChromeOS*
679 BluetoothAdapterChromeOS::GetDeviceWithPath(
680 const dbus::ObjectPath& object_path) {
681 if (!IsPresent())
682 return NULL;
684 for (DevicesMap::iterator iter = devices_.begin(); iter != devices_.end();
685 ++iter) {
686 BluetoothDeviceChromeOS* device_chromeos =
687 static_cast<BluetoothDeviceChromeOS*>(iter->second);
688 if (device_chromeos->object_path() == object_path)
689 return device_chromeos;
692 return NULL;
695 BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing(
696 const dbus::ObjectPath& object_path) {
697 DCHECK(IsPresent());
698 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
699 if (!device_chromeos) {
700 LOG(WARNING) << "Pairing Agent request for unknown device: "
701 << object_path.value();
702 return NULL;
705 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
706 if (pairing)
707 return pairing;
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)
713 return NULL;
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()->
727 RegisterAgent(
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) {
756 DeviceAdded(*iter);
760 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
761 DCHECK(IsPresent());
762 std::string board = base::SysInfo::GetLsbReleaseBoard();
763 std::string alias;
764 if (board.substr(0, 6) == "stumpy") {
765 alias = "Chromebox";
766 } else if (board.substr(0, 4) == "link") {
767 alias = "Chromebook Pixel";
768 } else {
769 alias = "Chromebook";
772 SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
775 void BluetoothAdapterChromeOS::RemoveAdapter() {
776 DCHECK(IsPresent());
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_;
795 devices_.clear();
797 for (DevicesMap::iterator iter = devices.begin();
798 iter != devices.end(); ++iter) {
799 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
800 DeviceRemoved(this, iter->second));
801 delete 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(
818 bool discovering) {
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);
848 DCHECK_EQ(
849 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
850 this);
852 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
853 observers_,
854 GattServiceAdded(this, service->GetDevice(), service));
857 void BluetoothAdapterChromeOS::NotifyGattServiceRemoved(
858 BluetoothRemoteGattServiceChromeOS* service) {
859 DCHECK_EQ(service->GetAdapter(), this);
860 DCHECK_EQ(
861 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
862 this);
864 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
865 observers_,
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,
874 observers_,
875 GattServiceChanged(this, service));
878 void BluetoothAdapterChromeOS::NotifyGattDiscoveryComplete(
879 BluetoothRemoteGattServiceChromeOS* service) {
880 DCHECK_EQ(service->GetAdapter(), this);
882 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
883 observers_,
884 GattDiscoveryCompleteForService(this, service));
887 void BluetoothAdapterChromeOS::NotifyGattCharacteristicAdded(
888 BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
889 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
890 characteristic->GetService())->GetAdapter(),
891 this);
893 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
894 observers_,
895 GattCharacteristicAdded(this, characteristic));
898 void BluetoothAdapterChromeOS::NotifyGattCharacteristicRemoved(
899 BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
900 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
901 characteristic->GetService())->GetAdapter(),
902 this);
904 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
905 observers_,
906 GattCharacteristicRemoved(this, characteristic));
909 void BluetoothAdapterChromeOS::NotifyGattDescriptorAdded(
910 BluetoothRemoteGattDescriptorChromeOS* descriptor) {
911 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
912 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
913 this);
915 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
916 observers_,
917 GattDescriptorAdded(this, descriptor));
920 void BluetoothAdapterChromeOS::NotifyGattDescriptorRemoved(
921 BluetoothRemoteGattDescriptorChromeOS* descriptor) {
922 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
923 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
924 this);
926 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
927 observers_,
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(),
936 this);
938 FOR_EACH_OBSERVER(
939 BluetoothAdapter::Observer,
940 observers_,
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(),
949 this);
951 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
952 observers_,
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) {
963 DCHECK(delegate);
965 if (!IsPresent()) {
966 VLOG(2) << "Adapter not present, erroring out";
967 error_callback.Run("Adapter not present");
968 return;
971 if (profiles_.find(uuid) != profiles_.end()) {
972 // TODO(jamuraa) check that the options are the same and error when they are
973 // not.
974 SetProfileDelegate(uuid, device_path, delegate, success_callback,
975 error_callback);
976 return;
979 if (profile_queues_.find(uuid) == profile_queues_.end()) {
980 BluetoothAdapterProfileChromeOS::Register(
981 uuid, options,
982 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfile, this, uuid),
983 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfileError, this,
984 uuid));
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),
992 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())
1020 return;
1022 for (auto& it : *profile_queues_[uuid])
1023 it.first.Run();
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!");
1036 return;
1039 if (profiles_[uuid]->SetDelegate(device_path, delegate)) {
1040 success_callback.Run(profiles_[uuid]);
1041 return;
1043 // Already set
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())
1054 return;
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,
1066 bool success) {
1067 if (!IsPresent()) {
1068 error_callback.Run();
1069 return;
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(),
1079 callback,
1080 error_callback));
1083 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
1084 const base::Closure& callback,
1085 const ErrorCallback& error_callback,
1086 bool success) {
1087 if (IsPresent() && success)
1088 callback.Run();
1089 else
1090 error_callback.Run();
1093 void BluetoothAdapterChromeOS::AddDiscoverySession(
1094 const base::Closure& callback,
1095 const ErrorCallback& error_callback) {
1096 if (!IsPresent()) {
1097 error_callback.Run();
1098 return;
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));
1108 return;
1111 // The adapter is already discovering.
1112 if (num_discovery_sessions_ > 0) {
1113 DCHECK(IsDiscovering());
1114 DCHECK(!discovery_request_pending_);
1115 num_discovery_sessions_++;
1116 callback.Run();
1117 return;
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(
1126 object_path_,
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) {
1136 if (!IsPresent()) {
1137 error_callback.Run();
1138 return;
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_--;
1147 callback.Run();
1148 return;
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();
1156 return;
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();
1166 return;
1169 // There is exactly one active discovery session. Request BlueZ to stop
1170 // discovery.
1171 DCHECK_EQ(num_discovery_sessions_, 1);
1172 discovery_request_pending_ = true;
1173 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1174 StopDiscovery(
1175 object_path_,
1176 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
1177 weak_ptr_factory_.GetWeakPtr(),
1178 callback),
1179 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
1180 weak_ptr_factory_.GetWeakPtr(),
1181 error_callback));
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_++;
1193 if (IsPresent())
1194 callback.Run();
1195 else
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 &&
1219 IsDiscovering()) {
1220 VLOG(1) << "Discovery previously initiated. Reporting success.";
1221 num_discovery_sessions_++;
1222 callback.Run();
1223 } else {
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_--;
1238 callback.Run();
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
1270 // call returns.
1271 if (discovery_request_pending_)
1272 return;
1276 } // namespace chromeos