1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "device/bluetooth/bluez/bluetooth_device_bluez.h"
6
7 #include <stdio.h>
8
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/callback_helpers.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/metrics/histogram_macros.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_util.h"
20 #include "components/device_event_log/device_event_log.h"
21 #include "dbus/bus.h"
22 #include "device/bluetooth/bluetooth_socket.h"
23 #include "device/bluetooth/bluetooth_socket_thread.h"
24 #include "device/bluetooth/bluez/bluetooth_adapter_bluez.h"
25 #include "device/bluetooth/bluez/bluetooth_gatt_connection_bluez.h"
26 #include "device/bluetooth/bluez/bluetooth_pairing_bluez.h"
27 #include "device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.h"
28 #include "device/bluetooth/bluez/bluetooth_service_record_bluez.h"
29 #include "device/bluetooth/bluez/bluetooth_socket_bluez.h"
30 #include "device/bluetooth/dbus/bluetooth_adapter_client.h"
31 #include "device/bluetooth/dbus/bluetooth_device_client.h"
32 #include "device/bluetooth/dbus/bluetooth_gatt_service_client.h"
33 #include "device/bluetooth/dbus/bluetooth_input_client.h"
34 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
35 #include "device/bluetooth/public/cpp/bluetooth_uuid.h"
36 #include "third_party/cros_system_api/dbus/service_constants.h"
37
38 using device::BluetoothDevice;
39 using device::BluetoothRemoteGattService;
40 using device::BluetoothSocket;
41 using device::BluetoothUUID;
42
43 namespace {
44
45 // The unit for connection interval values are in multiples of 1.25ms.
46 const uint16_t MIN_CONNECTION_INTERVAL_LOW = 6;
47 const uint16_t MAX_CONNECTION_INTERVAL_LOW = 6;
48 const uint16_t MIN_CONNECTION_INTERVAL_MEDIUM = 40;
49 const uint16_t MAX_CONNECTION_INTERVAL_MEDIUM = 56;
50 const uint16_t MIN_CONNECTION_INTERVAL_HIGH = 80;
51 const uint16_t MAX_CONNECTION_INTERVAL_HIGH = 100;
52
53 // Histogram enumerations for pairing results.
54 enum UMAPairingResult {
55 UMA_PAIRING_RESULT_SUCCESS,
56 UMA_PAIRING_RESULT_INPROGRESS,
57 UMA_PAIRING_RESULT_FAILED,
58 UMA_PAIRING_RESULT_AUTH_FAILED,
59 UMA_PAIRING_RESULT_AUTH_CANCELED,
60 UMA_PAIRING_RESULT_AUTH_REJECTED,
61 UMA_PAIRING_RESULT_AUTH_TIMEOUT,
62 UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE,
63 UMA_PAIRING_RESULT_UNKNOWN_ERROR,
64 // NOTE: Add new pairing results immediately above this line. Make sure to
65 // update the enum list in tools/histogram/histograms.xml accordinly.
66 UMA_PAIRING_RESULT_COUNT
67 };
68
ParseModalias(const dbus::ObjectPath & object_path,BluetoothDevice::VendorIDSource * vendor_id_source,uint16_t * vendor_id,uint16_t * product_id,uint16_t * device_id)69 void ParseModalias(const dbus::ObjectPath& object_path,
70 BluetoothDevice::VendorIDSource* vendor_id_source,
71 uint16_t* vendor_id,
72 uint16_t* product_id,
73 uint16_t* device_id) {
74 bluez::BluetoothDeviceClient::Properties* properties =
75 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
76 object_path);
77 DCHECK(properties);
78
79 std::string modalias = properties->modalias.value();
80 BluetoothDevice::VendorIDSource source_value;
81 int vendor_value, product_value, device_value;
82
83 if (sscanf(modalias.c_str(), "bluetooth:v%04xp%04xd%04x", &vendor_value,
84 &product_value, &device_value) == 3) {
85 source_value = BluetoothDevice::VENDOR_ID_BLUETOOTH;
86 } else if (sscanf(modalias.c_str(), "usb:v%04xp%04xd%04x", &vendor_value,
87 &product_value, &device_value) == 3) {
88 source_value = BluetoothDevice::VENDOR_ID_USB;
89 } else {
90 return;
91 }
92
93 if (vendor_id_source != nullptr)
94 *vendor_id_source = source_value;
95 if (vendor_id != nullptr)
96 *vendor_id = vendor_value;
97 if (product_id != nullptr)
98 *product_id = product_value;
99 if (device_id != nullptr)
100 *device_id = device_value;
101 }
102
RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code)103 void RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code) {
104 UMAPairingResult pairing_result;
105 switch (error_code) {
106 case BluetoothDevice::ERROR_INPROGRESS:
107 pairing_result = UMA_PAIRING_RESULT_INPROGRESS;
108 break;
109 case BluetoothDevice::ERROR_FAILED:
110 pairing_result = UMA_PAIRING_RESULT_FAILED;
111 break;
112 case BluetoothDevice::ERROR_AUTH_FAILED:
113 pairing_result = UMA_PAIRING_RESULT_AUTH_FAILED;
114 break;
115 case BluetoothDevice::ERROR_AUTH_CANCELED:
116 pairing_result = UMA_PAIRING_RESULT_AUTH_CANCELED;
117 break;
118 case BluetoothDevice::ERROR_AUTH_REJECTED:
119 pairing_result = UMA_PAIRING_RESULT_AUTH_REJECTED;
120 break;
121 case BluetoothDevice::ERROR_AUTH_TIMEOUT:
122 pairing_result = UMA_PAIRING_RESULT_AUTH_TIMEOUT;
123 break;
124 case BluetoothDevice::ERROR_UNSUPPORTED_DEVICE:
125 pairing_result = UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE;
126 break;
127 default:
128 pairing_result = UMA_PAIRING_RESULT_UNKNOWN_ERROR;
129 }
130
131 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult", pairing_result,
132 UMA_PAIRING_RESULT_COUNT);
133 }
134
DBusErrorToConnectError(const std::string & error_name)135 BluetoothDevice::ConnectErrorCode DBusErrorToConnectError(
136 const std::string& error_name) {
137 BluetoothDevice::ConnectErrorCode error_code = BluetoothDevice::ERROR_UNKNOWN;
138 if (error_name == bluetooth_device::kErrorConnectionAttemptFailed) {
139 error_code = BluetoothDevice::ERROR_FAILED;
140 } else if (error_name == bluetooth_device::kErrorFailed) {
141 error_code = BluetoothDevice::ERROR_FAILED;
142 } else if (error_name == bluetooth_device::kErrorAuthenticationFailed) {
143 error_code = BluetoothDevice::ERROR_AUTH_FAILED;
144 } else if (error_name == bluetooth_device::kErrorAuthenticationCanceled) {
145 error_code = BluetoothDevice::ERROR_AUTH_CANCELED;
146 } else if (error_name == bluetooth_device::kErrorAuthenticationRejected) {
147 error_code = BluetoothDevice::ERROR_AUTH_REJECTED;
148 } else if (error_name == bluetooth_device::kErrorAuthenticationTimeout) {
149 error_code = BluetoothDevice::ERROR_AUTH_TIMEOUT;
150 }
151 return error_code;
152 }
153
154 } // namespace
155
156 namespace bluez {
157
BluetoothDeviceBlueZ(BluetoothAdapterBlueZ * adapter,const dbus::ObjectPath & object_path,scoped_refptr<base::SequencedTaskRunner> ui_task_runner,scoped_refptr<device::BluetoothSocketThread> socket_thread)158 BluetoothDeviceBlueZ::BluetoothDeviceBlueZ(
159 BluetoothAdapterBlueZ* adapter,
160 const dbus::ObjectPath& object_path,
161 scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
162 scoped_refptr<device::BluetoothSocketThread> socket_thread)
163 : BluetoothDevice(adapter),
164 object_path_(object_path),
165 num_connecting_calls_(0),
166 ui_task_runner_(ui_task_runner),
167 socket_thread_(socket_thread) {
168 bluez::BluezDBusManager::Get()->GetBluetoothGattServiceClient()->AddObserver(
169 this);
170
171 // If GATT Services have already been discovered update the list of Gatt
172 // Services.
173 if (IsGattServicesDiscoveryComplete()) {
174 UpdateGattServices(object_path_);
175 } else {
176 BLUETOOTH_LOG(DEBUG)
177 << "Gatt services have not been fully resolved for device "
178 << object_path_.value();
179 }
180
181 // Update all the data that we cache within Chrome and do not pull from
182 // properties every time. TODO(xiaoyinh): Add a test for this. See
183 // http://crbug.com/688566.
184 UpdateServiceData();
185 UpdateManufacturerData();
186 UpdateAdvertisingDataFlags();
187 }
188
~BluetoothDeviceBlueZ()189 BluetoothDeviceBlueZ::~BluetoothDeviceBlueZ() {
190 bluez::BluezDBusManager::Get()
191 ->GetBluetoothGattServiceClient()
192 ->RemoveObserver(this);
193
194 // Copy the GATT services list here and clear the original so that when we
195 // send GattServiceRemoved(), GetGattServices() returns no services.
196 GattServiceMap gatt_services_swapped;
197 gatt_services_swapped.swap(gatt_services_);
198 for (const auto& iter : gatt_services_swapped) {
199 DCHECK(adapter());
200 adapter()->NotifyGattServiceRemoved(
201 static_cast<BluetoothRemoteGattServiceBlueZ*>(iter.second.get()));
202 }
203
204 // We pause discovery when trying to connect. Ensure discovery is unpaused if
205 // we get destroyed during a pending connection.
206 if (IsConnecting()) {
207 BLUETOOTH_LOG(EVENT) << object_path_.value()
208 << ": Unpausing discovery. Device removed.";
209 UnpauseDiscovery();
210 }
211 }
212
GetBluetoothClass() const213 uint32_t BluetoothDeviceBlueZ::GetBluetoothClass() const {
214 bluez::BluetoothDeviceClient::Properties* properties =
215 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
216 object_path_);
217 DCHECK(properties);
218
219 return properties->bluetooth_class.value();
220 }
221
GetType() const222 device::BluetoothTransport BluetoothDeviceBlueZ::GetType() const {
223 bluez::BluetoothDeviceClient::Properties* properties =
224 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
225 object_path_);
226 DCHECK(properties);
227
228 if (!properties->type.is_valid())
229 return device::BLUETOOTH_TRANSPORT_INVALID;
230
231 std::string type = properties->type.value();
232 if (type == bluez::BluetoothDeviceClient::kTypeBredr) {
233 return device::BLUETOOTH_TRANSPORT_CLASSIC;
234 } else if (type == bluez::BluetoothDeviceClient::kTypeLe) {
235 return device::BLUETOOTH_TRANSPORT_LE;
236 } else if (type == bluez::BluetoothDeviceClient::kTypeDual) {
237 return device::BLUETOOTH_TRANSPORT_DUAL;
238 }
239
240 NOTREACHED();
241 return device::BLUETOOTH_TRANSPORT_INVALID;
242 }
243
CreateGattConnectionImpl(base::Optional<BluetoothUUID> service_uuid)244 void BluetoothDeviceBlueZ::CreateGattConnectionImpl(
245 base::Optional<BluetoothUUID> service_uuid) {
246 // TODO(crbug.com/630586): Until there is a way to create a reference counted
247 // GATT connection in bluetoothd, simply do a regular connect.
248 Connect(nullptr,
249 base::BindOnce(&BluetoothDeviceBlueZ::DidConnectGatt,
250 weak_ptr_factory_.GetWeakPtr()),
251 base::BindOnce(&BluetoothDeviceBlueZ::DidFailToConnectGatt,
252 weak_ptr_factory_.GetWeakPtr()));
253 }
254
SetGattServicesDiscoveryComplete(bool complete)255 void BluetoothDeviceBlueZ::SetGattServicesDiscoveryComplete(bool complete) {
256 // BlueZ implementation already tracks service discovery state.
257 NOTIMPLEMENTED();
258 }
259
IsGattServicesDiscoveryComplete() const260 bool BluetoothDeviceBlueZ::IsGattServicesDiscoveryComplete() const {
261 bluez::BluetoothDeviceClient::Properties* properties =
262 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
263 object_path_);
264 DCHECK(properties);
265
266 return properties->services_resolved.value();
267 }
268
DisconnectGatt()269 void BluetoothDeviceBlueZ::DisconnectGatt() {
270 // There isn't currently a good way to manage the ownership of a connection
271 // between Chrome and bluetoothd plugins/profiles. Until a proper reference
272 // count is kept in bluetoothd, we might unwittingly kill a connection to a
273 // device the user is still interested in, e.g. a mouse. A device's paired
274 // status is usually a good indication that the device is being used by other
275 // parts of the system and therefore we leak these connections.
276 // TODO(crbug.com/630586): Call disconnect for all devices.
277
278 // IsPaired() returns true if we've connected to the device before. So we
279 // check the dbus property directly.
280 // TODO(crbug.com/649651): Use IsPaired once it returns true only for paired
281 // devices.
282 bluez::BluetoothDeviceClient::Properties* properties =
283 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
284 object_path_);
285 DCHECK(properties);
286
287 if (properties->paired.value()) {
288 BLUETOOTH_LOG(ERROR) << "Leaking connection to paired device.";
289 return;
290 }
291
292 Disconnect(base::DoNothing(), base::DoNothing());
293 }
294
GetAddress() const295 std::string BluetoothDeviceBlueZ::GetAddress() const {
296 bluez::BluetoothDeviceClient::Properties* properties =
297 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
298 object_path_);
299 DCHECK(properties);
300
301 return CanonicalizeAddress(properties->address.value());
302 }
303
GetVendorIDSource() const304 BluetoothDevice::VendorIDSource BluetoothDeviceBlueZ::GetVendorIDSource()
305 const {
306 VendorIDSource vendor_id_source = VENDOR_ID_UNKNOWN;
307 ParseModalias(object_path_, &vendor_id_source, nullptr, nullptr, nullptr);
308 return vendor_id_source;
309 }
310
GetVendorID() const311 uint16_t BluetoothDeviceBlueZ::GetVendorID() const {
312 uint16_t vendor_id = 0;
313 ParseModalias(object_path_, nullptr, &vendor_id, nullptr, nullptr);
314 return vendor_id;
315 }
316
GetProductID() const317 uint16_t BluetoothDeviceBlueZ::GetProductID() const {
318 uint16_t product_id = 0;
319 ParseModalias(object_path_, nullptr, nullptr, &product_id, nullptr);
320 return product_id;
321 }
322
GetDeviceID() const323 uint16_t BluetoothDeviceBlueZ::GetDeviceID() const {
324 uint16_t device_id = 0;
325 ParseModalias(object_path_, nullptr, nullptr, nullptr, &device_id);
326 return device_id;
327 }
328
GetAppearance() const329 uint16_t BluetoothDeviceBlueZ::GetAppearance() const {
330 bluez::BluetoothDeviceClient::Properties* properties =
331 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
332 object_path_);
333 DCHECK(properties);
334
335 if (!properties->appearance.is_valid())
336 return kAppearanceNotPresent;
337
338 return properties->appearance.value();
339 }
340
GetName() const341 base::Optional<std::string> BluetoothDeviceBlueZ::GetName() const {
342 bluez::BluetoothDeviceClient::Properties* properties =
343 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
344 object_path_);
345 DCHECK(properties);
346
347 if (properties->name.is_valid())
348 return properties->name.value();
349 else
350 return base::nullopt;
351 }
352
IsPaired() const353 bool BluetoothDeviceBlueZ::IsPaired() const {
354 bluez::BluetoothDeviceClient::Properties* properties =
355 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
356 object_path_);
357 DCHECK(properties);
358
359 // The Paired property reflects the successful pairing for BR/EDR/LE. The
360 // value of the Paired property is always false for the devices that don't
361 // support pairing. Once a device is paired successfully, both Paired and
362 // Trusted properties will be set to true.
363 return properties->paired.value();
364 }
365
IsConnected() const366 bool BluetoothDeviceBlueZ::IsConnected() const {
367 bluez::BluetoothDeviceClient::Properties* properties =
368 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
369 object_path_);
370 DCHECK(properties);
371
372 return properties->connected.value();
373 }
374
IsGattConnected() const375 bool BluetoothDeviceBlueZ::IsGattConnected() const {
376 // Bluez uses the same attribute for GATT Connections and Classic BT
377 // Connections.
378 return IsConnected();
379 }
380
IsConnectable() const381 bool BluetoothDeviceBlueZ::IsConnectable() const {
382 bluez::BluetoothInputClient::Properties* input_properties =
383 bluez::BluezDBusManager::Get()->GetBluetoothInputClient()->GetProperties(
384 object_path_);
385 // GetProperties returns nullptr when the device does not implement the given
386 // interface. Non HID devices are normally connectable.
387 if (!input_properties)
388 return true;
389
390 return input_properties->reconnect_mode.value() != "device";
391 }
392
IsConnecting() const393 bool BluetoothDeviceBlueZ::IsConnecting() const {
394 return num_connecting_calls_ > 0;
395 }
396
GetUUIDs() const397 BluetoothDevice::UUIDSet BluetoothDeviceBlueZ::GetUUIDs() const {
398 bluez::BluetoothDeviceClient::Properties* properties =
399 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
400 object_path_);
401 DCHECK(properties);
402
403 UUIDSet uuids;
404 const std::vector<std::string>& dbus_uuids = properties->uuids.value();
405 for (const std::string& dbus_uuid : dbus_uuids) {
406 device::BluetoothUUID uuid(dbus_uuid);
407 DCHECK(uuid.IsValid());
408 uuids.insert(std::move(uuid));
409 }
410 return uuids;
411 }
412
GetInquiryRSSI() const413 base::Optional<int8_t> BluetoothDeviceBlueZ::GetInquiryRSSI() const {
414 bluez::BluetoothDeviceClient::Properties* properties =
415 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
416 object_path_);
417 DCHECK(properties);
418
419 if (!properties->rssi.is_valid())
420 return base::nullopt;
421
422 // BlueZ uses int16_t because there is no int8_t for DBus, so we should never
423 // get an int16_t that cannot be represented by an int8_t. But just in case
424 // clamp the value.
425 return ClampPower(properties->rssi.value());
426 }
427
GetInquiryTxPower() const428 base::Optional<int8_t> BluetoothDeviceBlueZ::GetInquiryTxPower() const {
429 bluez::BluetoothDeviceClient::Properties* properties =
430 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
431 object_path_);
432 DCHECK(properties);
433
434 if (!properties->tx_power.is_valid())
435 return base::nullopt;
436
437 // BlueZ uses int16_t because there is no int8_t for DBus, so we should never
438 // get an int16_t that cannot be represented by an int8_t. But just in case
439 // clamp the value.
440 return ClampPower(properties->tx_power.value());
441 }
442
ExpectingPinCode() const443 bool BluetoothDeviceBlueZ::ExpectingPinCode() const {
444 return pairing_.get() && pairing_->ExpectingPinCode();
445 }
446
ExpectingPasskey() const447 bool BluetoothDeviceBlueZ::ExpectingPasskey() const {
448 return pairing_.get() && pairing_->ExpectingPasskey();
449 }
450
ExpectingConfirmation() const451 bool BluetoothDeviceBlueZ::ExpectingConfirmation() const {
452 return pairing_.get() && pairing_->ExpectingConfirmation();
453 }
454
GetConnectionInfo(const ConnectionInfoCallback & callback)455 void BluetoothDeviceBlueZ::GetConnectionInfo(
456 const ConnectionInfoCallback& callback) {
457 // DBus method call should gracefully return an error if the device is not
458 // currently connected.
459 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetConnInfo(
460 object_path_,
461 base::BindOnce(&BluetoothDeviceBlueZ::OnGetConnInfo,
462 weak_ptr_factory_.GetWeakPtr(), callback),
463 base::BindOnce(&BluetoothDeviceBlueZ::OnGetConnInfoError,
464 weak_ptr_factory_.GetWeakPtr(), callback));
465 }
466
SetConnectionLatency(ConnectionLatency connection_latency,const base::Closure & callback,const ErrorCallback & error_callback)467 void BluetoothDeviceBlueZ::SetConnectionLatency(
468 ConnectionLatency connection_latency,
469 const base::Closure& callback,
470 const ErrorCallback& error_callback) {
471 uint16_t min_connection_interval = MIN_CONNECTION_INTERVAL_MEDIUM;
472 uint16_t max_connection_interval = MAX_CONNECTION_INTERVAL_MEDIUM;
473 switch (connection_latency) {
474 case ConnectionLatency::CONNECTION_LATENCY_LOW:
475 min_connection_interval = MIN_CONNECTION_INTERVAL_LOW;
476 max_connection_interval = MAX_CONNECTION_INTERVAL_LOW;
477 break;
478 case ConnectionLatency::CONNECTION_LATENCY_MEDIUM:
479 min_connection_interval = MIN_CONNECTION_INTERVAL_MEDIUM;
480 max_connection_interval = MAX_CONNECTION_INTERVAL_MEDIUM;
481 break;
482 case ConnectionLatency::CONNECTION_LATENCY_HIGH:
483 min_connection_interval = MIN_CONNECTION_INTERVAL_HIGH;
484 max_connection_interval = MAX_CONNECTION_INTERVAL_HIGH;
485 break;
486 default:
487 NOTREACHED();
488 break;
489 }
490
491 BLUETOOTH_LOG(EVENT) << "Setting LE connection parameters: min="
492 << min_connection_interval
493 << ", max=" << max_connection_interval;
494 bluez::BluetoothDeviceClient::ConnectionParameters connection_parameters;
495 connection_parameters.min_connection_interval = min_connection_interval;
496 connection_parameters.max_connection_interval = max_connection_interval;
497
498 bluez::BluetoothDeviceClient* client =
499 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient();
500 client->SetLEConnectionParameters(
501 object_path_, connection_parameters,
502 base::BindOnce(&BluetoothDeviceBlueZ::OnSetLEConnectionParameters,
503 weak_ptr_factory_.GetWeakPtr(), callback),
504 base::BindOnce(&BluetoothDeviceBlueZ::OnSetLEConnectionParametersError,
505 weak_ptr_factory_.GetWeakPtr(), error_callback));
506 }
507
Connect(BluetoothDevice::PairingDelegate * pairing_delegate,base::OnceClosure callback,ConnectErrorCallback error_callback)508 void BluetoothDeviceBlueZ::Connect(
509 BluetoothDevice::PairingDelegate* pairing_delegate,
510 base::OnceClosure callback,
511 ConnectErrorCallback error_callback) {
512 if (num_connecting_calls_++ == 0)
513 adapter()->NotifyDeviceChanged(this);
514
515 BLUETOOTH_LOG(EVENT) << object_path_.value() << ": Connecting, "
516 << num_connecting_calls_ << " in progress";
517
518 // These callbacks are only called once, but are passed to two different
519 // places.
520 base::RepeatingClosure dupe_callback =
521 base::AdaptCallbackForRepeating(std::move(callback));
522 base::RepeatingCallback<ConnectErrorCallback::RunType> dupe_error_callback =
523 base::AdaptCallbackForRepeating(std::move(error_callback));
524
525 if (IsPaired() || !pairing_delegate) {
526 BLUETOOTH_LOG(EVENT) << object_path_.value() << ": Pausing discovery";
527 // No need to pair, or unable to, skip straight to connection.
528 bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->PauseDiscovery(
529 adapter()->object_path(),
530 base::BindOnce(
531 [](base::WeakPtr<BluetoothDeviceBlueZ> weak_ptr,
532 base::OnceClosure callback,
533 ConnectErrorCallback error_callback) {
534 BLUETOOTH_LOG(EVENT) << "Successfully paused discovery";
535 if (weak_ptr)
536 weak_ptr->ConnectInternal(false /* after_pairing */,
537 std::move(callback),
538 std::move(error_callback));
539 },
540 weak_ptr_factory_.GetWeakPtr(), dupe_callback, dupe_error_callback),
541 base::BindOnce(
542 [](base::WeakPtr<BluetoothDeviceBlueZ> weak_ptr,
543 base::OnceClosure callback, ConnectErrorCallback error_callback,
544 const std::string& error_name,
545 const std::string& error_message) {
546 BLUETOOTH_LOG(EVENT) << "Failed to pause discovery";
547 if (weak_ptr)
548 weak_ptr->ConnectInternal(false, std::move(callback),
549 std::move(error_callback));
550 },
551 weak_ptr_factory_.GetWeakPtr(), dupe_callback,
552 dupe_error_callback));
553 } else {
554 // Initiate high-security connection with pairing.
555 BeginPairing(pairing_delegate);
556
557 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Pair(
558 object_path_,
559 base::BindOnce(&BluetoothDeviceBlueZ::OnPairDuringConnect,
560 weak_ptr_factory_.GetWeakPtr(), dupe_callback,
561 dupe_error_callback),
562 base::BindOnce(&BluetoothDeviceBlueZ::OnPairDuringConnectError,
563 weak_ptr_factory_.GetWeakPtr(), dupe_error_callback));
564 }
565 }
566
Pair(BluetoothDevice::PairingDelegate * pairing_delegate,base::OnceClosure callback,ConnectErrorCallback error_callback)567 void BluetoothDeviceBlueZ::Pair(
568 BluetoothDevice::PairingDelegate* pairing_delegate,
569 base::OnceClosure callback,
570 ConnectErrorCallback error_callback) {
571 DCHECK(pairing_delegate);
572 BeginPairing(pairing_delegate);
573
574 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Pair(
575 object_path_,
576 base::BindOnce(&BluetoothDeviceBlueZ::OnPair,
577 weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
578 base::BindOnce(&BluetoothDeviceBlueZ::OnPairError,
579 weak_ptr_factory_.GetWeakPtr(),
580 std::move(error_callback)));
581 }
582
SetPinCode(const std::string & pincode)583 void BluetoothDeviceBlueZ::SetPinCode(const std::string& pincode) {
584 if (!pairing_.get())
585 return;
586
587 pairing_->SetPinCode(pincode);
588 }
589
SetPasskey(uint32_t passkey)590 void BluetoothDeviceBlueZ::SetPasskey(uint32_t passkey) {
591 if (!pairing_.get())
592 return;
593
594 pairing_->SetPasskey(passkey);
595 }
596
ConfirmPairing()597 void BluetoothDeviceBlueZ::ConfirmPairing() {
598 if (!pairing_.get())
599 return;
600
601 pairing_->ConfirmPairing();
602 }
603
RejectPairing()604 void BluetoothDeviceBlueZ::RejectPairing() {
605 if (!pairing_.get())
606 return;
607
608 pairing_->RejectPairing();
609 }
610
CancelPairing()611 void BluetoothDeviceBlueZ::CancelPairing() {
612 bool canceled = false;
613
614 BLUETOOTH_LOG(EVENT) << object_path_.value() << ": CancelPairing";
615
616 // If there is a callback in progress that we can reply to then use that
617 // to cancel the current pairing request.
618 if (pairing_.get() && pairing_->CancelPairing())
619 canceled = true;
620
621 // If not we have to send an explicit CancelPairing() to the device instead.
622 if (!canceled) {
623 BLUETOOTH_LOG(DEBUG) << object_path_.value()
624 << ": No pairing context or callback. "
625 << "Sending explicit cancel";
626 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->CancelPairing(
627 object_path_, base::DoNothing(),
628 base::BindOnce(&BluetoothDeviceBlueZ::OnCancelPairingError,
629 weak_ptr_factory_.GetWeakPtr()));
630 }
631
632 // Since there is no callback to this method it's possible that the pairing
633 // delegate is going to be freed before things complete (indeed it's
634 // documented that this is the method you should call while freeing the
635 // pairing delegate), so clear our the context holding on to it.
636 EndPairing();
637 }
638
Disconnect(const base::Closure & callback,const ErrorCallback & error_callback)639 void BluetoothDeviceBlueZ::Disconnect(const base::Closure& callback,
640 const ErrorCallback& error_callback) {
641 BLUETOOTH_LOG(EVENT) << object_path_.value() << ": Disconnecting";
642 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Disconnect(
643 object_path_,
644 base::BindOnce(&BluetoothDeviceBlueZ::OnDisconnect,
645 weak_ptr_factory_.GetWeakPtr(), callback),
646 base::BindOnce(&BluetoothDeviceBlueZ::OnDisconnectError,
647 weak_ptr_factory_.GetWeakPtr(), error_callback));
648 }
649
Forget(const base::Closure & callback,const ErrorCallback & error_callback)650 void BluetoothDeviceBlueZ::Forget(const base::Closure& callback,
651 const ErrorCallback& error_callback) {
652 BLUETOOTH_LOG(EVENT) << object_path_.value() << ": Removing device";
653 bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->RemoveDevice(
654 adapter()->object_path(), object_path_, callback,
655 base::BindOnce(&BluetoothDeviceBlueZ::OnForgetError,
656 weak_ptr_factory_.GetWeakPtr(), error_callback));
657 }
658
ConnectToService(const BluetoothUUID & uuid,const ConnectToServiceCallback & callback,const ConnectToServiceErrorCallback & error_callback)659 void BluetoothDeviceBlueZ::ConnectToService(
660 const BluetoothUUID& uuid,
661 const ConnectToServiceCallback& callback,
662 const ConnectToServiceErrorCallback& error_callback) {
663 BLUETOOTH_LOG(EVENT) << object_path_.value()
664 << ": Connecting to service: " << uuid.canonical_value();
665 scoped_refptr<BluetoothSocketBlueZ> socket =
666 BluetoothSocketBlueZ::CreateBluetoothSocket(ui_task_runner_,
667 socket_thread_);
668 socket->Connect(this, uuid, BluetoothSocketBlueZ::SECURITY_LEVEL_MEDIUM,
669 base::Bind(callback, socket), error_callback);
670 }
671
ConnectToServiceInsecurely(const BluetoothUUID & uuid,const ConnectToServiceCallback & callback,const ConnectToServiceErrorCallback & error_callback)672 void BluetoothDeviceBlueZ::ConnectToServiceInsecurely(
673 const BluetoothUUID& uuid,
674 const ConnectToServiceCallback& callback,
675 const ConnectToServiceErrorCallback& error_callback) {
676 BLUETOOTH_LOG(EVENT) << object_path_.value()
677 << ": Connecting insecurely to service: "
678 << uuid.canonical_value();
679 scoped_refptr<BluetoothSocketBlueZ> socket =
680 BluetoothSocketBlueZ::CreateBluetoothSocket(ui_task_runner_,
681 socket_thread_);
682 socket->Connect(this, uuid, BluetoothSocketBlueZ::SECURITY_LEVEL_LOW,
683 base::Bind(callback, socket), error_callback);
684 }
685
686 std::unique_ptr<device::BluetoothGattConnection>
CreateBluetoothGattConnectionObject()687 BluetoothDeviceBlueZ::CreateBluetoothGattConnectionObject() {
688 return std::unique_ptr<device::BluetoothGattConnection>(
689 new BluetoothGattConnectionBlueZ(adapter_, GetAddress(), object_path_));
690 }
691
GetServiceRecords(const GetServiceRecordsCallback & callback,const GetServiceRecordsErrorCallback & error_callback)692 void BluetoothDeviceBlueZ::GetServiceRecords(
693 const GetServiceRecordsCallback& callback,
694 const GetServiceRecordsErrorCallback& error_callback) {
695 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetServiceRecords(
696 object_path_, callback,
697 base::BindOnce(&BluetoothDeviceBlueZ::OnGetServiceRecordsError,
698 weak_ptr_factory_.GetWeakPtr(), error_callback));
699 }
700
701 #if defined(OS_CHROMEOS)
ExecuteWrite(const base::Closure & callback,const ExecuteWriteErrorCallback & error_callback)702 void BluetoothDeviceBlueZ::ExecuteWrite(
703 const base::Closure& callback,
704 const ExecuteWriteErrorCallback& error_callback) {
705 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->ExecuteWrite(
706 object_path_, callback,
707 base::BindOnce(&BluetoothDeviceBlueZ::OnExecuteWriteError,
708 weak_ptr_factory_.GetWeakPtr(), error_callback));
709 }
710
AbortWrite(const base::Closure & callback,const AbortWriteErrorCallback & error_callback)711 void BluetoothDeviceBlueZ::AbortWrite(
712 const base::Closure& callback,
713 const AbortWriteErrorCallback& error_callback) {
714 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->AbortWrite(
715 object_path_, callback,
716 base::BindOnce(&BluetoothDeviceBlueZ::OnAbortWriteError,
717 weak_ptr_factory_.GetWeakPtr(), error_callback));
718 }
719 #endif
720
UpdateServiceData()721 void BluetoothDeviceBlueZ::UpdateServiceData() {
722 bluez::BluetoothDeviceClient::Properties* properties =
723 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
724 object_path_);
725 if (!properties || !properties->service_data.is_valid())
726 return;
727
728 service_data_.clear();
729 for (const auto& pair : properties->service_data.value())
730 service_data_[BluetoothUUID(pair.first)] = pair.second;
731 }
732
UpdateManufacturerData()733 void BluetoothDeviceBlueZ::UpdateManufacturerData() {
734 bluez::BluetoothDeviceClient::Properties* properties =
735 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
736 object_path_);
737 if (!properties || !properties->manufacturer_data.is_valid())
738 return;
739 manufacturer_data_.clear();
740
741 if (properties->manufacturer_data.is_valid()) {
742 for (const auto& pair : properties->manufacturer_data.value())
743 manufacturer_data_[pair.first] = pair.second;
744 }
745 }
746
UpdateAdvertisingDataFlags()747 void BluetoothDeviceBlueZ::UpdateAdvertisingDataFlags() {
748 bluez::BluetoothDeviceClient::Properties* properties =
749 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
750 object_path_);
751 if (!properties || !properties->advertising_data_flags.is_valid())
752 return;
753 // The advertising data flags property is a vector<uint8> because the
754 // Supplement to Bluetooth Core Specification Version 6 page 13 said that
755 // "The Flags field may be zero or more octets long." However, only the first
756 // byte of that is needed because there is only 5 bits of data defined there.
757 advertising_data_flags_ = properties->advertising_data_flags.value()[0];
758 }
759
BeginPairing(BluetoothDevice::PairingDelegate * pairing_delegate)760 BluetoothPairingBlueZ* BluetoothDeviceBlueZ::BeginPairing(
761 BluetoothDevice::PairingDelegate* pairing_delegate) {
762 pairing_.reset(new BluetoothPairingBlueZ(this, pairing_delegate));
763 return pairing_.get();
764 }
765
EndPairing()766 void BluetoothDeviceBlueZ::EndPairing() {
767 pairing_.reset();
768 }
769
GetPairing() const770 BluetoothPairingBlueZ* BluetoothDeviceBlueZ::GetPairing() const {
771 return pairing_.get();
772 }
773
adapter() const774 BluetoothAdapterBlueZ* BluetoothDeviceBlueZ::adapter() const {
775 return static_cast<BluetoothAdapterBlueZ*>(adapter_);
776 }
777
GattServiceAdded(const dbus::ObjectPath & object_path)778 void BluetoothDeviceBlueZ::GattServiceAdded(
779 const dbus::ObjectPath& object_path) {
780 if (GetGattService(object_path.value())) {
781 BLUETOOTH_LOG(DEBUG) << "Remote GATT service already exists: "
782 << object_path.value();
783 return;
784 }
785
786 bluez::BluetoothGattServiceClient::Properties* properties =
787 bluez::BluezDBusManager::Get()
788 ->GetBluetoothGattServiceClient()
789 ->GetProperties(object_path);
790 DCHECK(properties);
791 if (properties->device.value() != object_path_) {
792 BLUETOOTH_LOG(DEBUG)
793 << "Remote GATT service does not belong to this device.";
794 return;
795 }
796
797 BLUETOOTH_LOG(EVENT) << "Adding new remote GATT service for device: "
798 << GetAddress();
799
800 BluetoothRemoteGattServiceBlueZ* service =
801 new BluetoothRemoteGattServiceBlueZ(adapter(), this, object_path);
802
803 gatt_services_[service->GetIdentifier()] = base::WrapUnique(service);
804 DCHECK(service->object_path() == object_path);
805 DCHECK(service->GetUUID().IsValid());
806
807 DCHECK(adapter());
808 adapter()->NotifyGattServiceAdded(service);
809 }
810
GattServiceRemoved(const dbus::ObjectPath & object_path)811 void BluetoothDeviceBlueZ::GattServiceRemoved(
812 const dbus::ObjectPath& object_path) {
813 auto iter = gatt_services_.find(object_path.value());
814 if (iter == gatt_services_.end()) {
815 DVLOG(3) << "Unknown GATT service removed: " << object_path.value();
816 return;
817 }
818
819 BluetoothRemoteGattServiceBlueZ* service =
820 static_cast<BluetoothRemoteGattServiceBlueZ*>(iter->second.get());
821
822 BLUETOOTH_LOG(EVENT) << "Removing remote GATT service with UUID: '"
823 << service->GetUUID().canonical_value()
824 << "' from device: " << GetAddress();
825
826 DCHECK(service->object_path() == object_path);
827 std::unique_ptr<BluetoothRemoteGattService> scoped_service =
828 std::move(gatt_services_[object_path.value()]);
829 gatt_services_.erase(iter);
830
831 DCHECK(adapter());
832 discovery_complete_notified_.erase(service);
833 adapter()->NotifyGattServiceRemoved(service);
834 }
835
UpdateGattServices(const dbus::ObjectPath & object_path)836 void BluetoothDeviceBlueZ::UpdateGattServices(
837 const dbus::ObjectPath& object_path) {
838 if (object_path != object_path_) {
839 // No need to update map if update is for a different device.
840 return;
841 }
842
843 DCHECK(IsGattServicesDiscoveryComplete());
844
845 DVLOG(3) << "Updating the list of GATT services associated with device "
846 << object_path_.value();
847
848 const std::vector<dbus::ObjectPath> service_paths =
849 bluez::BluezDBusManager::Get()
850 ->GetBluetoothGattServiceClient()
851 ->GetServices();
852 for (const auto& service_path : service_paths) {
853 // Add all previously unknown GATT services associated with the device.
854 GattServiceAdded(service_path);
855
856 // If the service does not belong in this device, there is nothing left to
857 // do.
858 BluetoothRemoteGattService* service = GetGattService(service_path.value());
859 if (service == nullptr) {
860 return;
861 }
862
863 // Notify of GATT discovery complete if we haven't before.
864 auto notified_pair = discovery_complete_notified_.insert(service);
865 if (notified_pair.second) {
866 adapter()->NotifyGattDiscoveryComplete(service);
867 }
868 }
869 }
870
OnGetConnInfo(const ConnectionInfoCallback & callback,int16_t rssi,int16_t transmit_power,int16_t max_transmit_power)871 void BluetoothDeviceBlueZ::OnGetConnInfo(const ConnectionInfoCallback& callback,
872 int16_t rssi,
873 int16_t transmit_power,
874 int16_t max_transmit_power) {
875 callback.Run(ConnectionInfo(rssi, transmit_power, max_transmit_power));
876 }
877
OnGetConnInfoError(const ConnectionInfoCallback & callback,const std::string & error_name,const std::string & error_message)878 void BluetoothDeviceBlueZ::OnGetConnInfoError(
879 const ConnectionInfoCallback& callback,
880 const std::string& error_name,
881 const std::string& error_message) {
882 BLUETOOTH_LOG(ERROR) << object_path_.value()
883 << ": Failed to get connection info: " << error_name
884 << ": " << error_message;
885 callback.Run(ConnectionInfo());
886 }
887
OnSetLEConnectionParameters(const base::Closure & callback)888 void BluetoothDeviceBlueZ::OnSetLEConnectionParameters(
889 const base::Closure& callback) {
890 callback.Run();
891 }
892
OnSetLEConnectionParametersError(const ErrorCallback & callback,const std::string & error_name,const std::string & error_message)893 void BluetoothDeviceBlueZ::OnSetLEConnectionParametersError(
894 const ErrorCallback& callback,
895 const std::string& error_name,
896 const std::string& error_message) {
897 BLUETOOTH_LOG(ERROR) << object_path_.value()
898 << ": Failed to set connection parameters: "
899 << error_name << ": " << error_message;
900 callback.Run();
901 }
902
OnGetServiceRecordsError(const GetServiceRecordsErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)903 void BluetoothDeviceBlueZ::OnGetServiceRecordsError(
904 const GetServiceRecordsErrorCallback& error_callback,
905 const std::string& error_name,
906 const std::string& error_message) {
907 BLUETOOTH_LOG(EVENT) << object_path_.value()
908 << ": Failed to get service records: " << error_name
909 << ": " << error_message;
910 BluetoothServiceRecordBlueZ::ErrorCode code =
911 BluetoothServiceRecordBlueZ::ErrorCode::UNKNOWN;
912 if (error_name == bluetooth_device::kErrorNotConnected) {
913 code = BluetoothServiceRecordBlueZ::ErrorCode::ERROR_DEVICE_DISCONNECTED;
914 }
915 error_callback.Run(code);
916 }
917
918 #if defined(OS_CHROMEOS)
OnExecuteWriteError(const ExecuteWriteErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)919 void BluetoothDeviceBlueZ::OnExecuteWriteError(
920 const ExecuteWriteErrorCallback& error_callback,
921 const std::string& error_name,
922 const std::string& error_message) {
923 BLUETOOTH_LOG(EVENT) << object_path_.value()
924 << ": Failed to execute write: " << error_name << ": "
925 << error_message;
926 error_callback.Run(
927 BluetoothGattServiceBlueZ::DBusErrorToServiceError(error_name));
928 }
929
OnAbortWriteError(const AbortWriteErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)930 void BluetoothDeviceBlueZ::OnAbortWriteError(
931 const AbortWriteErrorCallback& error_callback,
932 const std::string& error_name,
933 const std::string& error_message) {
934 BLUETOOTH_LOG(EVENT) << object_path_.value()
935 << ": Failed to abort write: " << error_name << ": "
936 << error_message;
937 error_callback.Run(
938 BluetoothGattServiceBlueZ::DBusErrorToServiceError(error_name));
939 }
940 #endif
941
ConnectInternal(bool after_pairing,base::OnceClosure callback,ConnectErrorCallback error_callback)942 void BluetoothDeviceBlueZ::ConnectInternal(
943 bool after_pairing,
944 base::OnceClosure callback,
945 ConnectErrorCallback error_callback) {
946 BLUETOOTH_LOG(EVENT) << object_path_.value() << ": Connecting";
947 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Connect(
948 object_path_,
949 base::BindOnce(&BluetoothDeviceBlueZ::OnConnect,
950 weak_ptr_factory_.GetWeakPtr(), after_pairing,
951 std::move(callback)),
952 base::BindOnce(&BluetoothDeviceBlueZ::OnConnectError,
953 weak_ptr_factory_.GetWeakPtr(), after_pairing,
954 std::move(error_callback)));
955 }
956
OnConnect(bool after_pairing,base::OnceClosure callback)957 void BluetoothDeviceBlueZ::OnConnect(bool after_pairing,
958 base::OnceClosure callback) {
959 BLUETOOTH_LOG(EVENT) << object_path_.value()
960 << ": Unpausing discovery after connection";
961 UnpauseDiscovery();
962 if (--num_connecting_calls_ == 0)
963 adapter()->NotifyDeviceChanged(this);
964
965 DCHECK(num_connecting_calls_ >= 0);
966 BLUETOOTH_LOG(EVENT) << object_path_.value() << ": Connected, "
967 << num_connecting_calls_ << " still in progress";
968
969 SetTrusted();
970
971 if (after_pairing)
972 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult",
973 UMA_PAIRING_RESULT_SUCCESS,
974 UMA_PAIRING_RESULT_COUNT);
975
976 std::move(callback).Run();
977 }
978
OnConnectError(bool after_pairing,ConnectErrorCallback error_callback,const std::string & error_name,const std::string & error_message)979 void BluetoothDeviceBlueZ::OnConnectError(bool after_pairing,
980 ConnectErrorCallback error_callback,
981 const std::string& error_name,
982 const std::string& error_message) {
983 BLUETOOTH_LOG(EVENT) << object_path_.value()
984 << ": Unpausing discovery after failed connection";
985 UnpauseDiscovery();
986
987 if (--num_connecting_calls_ == 0)
988 adapter()->NotifyDeviceChanged(this);
989
990 DCHECK(num_connecting_calls_ >= 0);
991 BLUETOOTH_LOG(ERROR) << object_path_.value()
992 << ": Failed to connect device: " << error_name << ": "
993 << error_message;
994 BLUETOOTH_LOG(DEBUG) << object_path_.value() << ": " << num_connecting_calls_
995 << " still in progress";
996
997 // Determine the error code from error_name.
998 ConnectErrorCode error_code = ERROR_UNKNOWN;
999 if (error_name == bluetooth_device::kErrorFailed) {
1000 error_code = ERROR_FAILED;
1001 } else if (error_name == bluetooth_device::kErrorInProgress) {
1002 error_code = ERROR_INPROGRESS;
1003 } else if (error_name == bluetooth_device::kErrorNotSupported) {
1004 error_code = ERROR_UNSUPPORTED_DEVICE;
1005 }
1006
1007 if (after_pairing)
1008 RecordPairingResult(error_code);
1009 std::move(error_callback).Run(error_code);
1010 }
1011
OnPairDuringConnect(base::OnceClosure callback,ConnectErrorCallback error_callback)1012 void BluetoothDeviceBlueZ::OnPairDuringConnect(
1013 base::OnceClosure callback,
1014 ConnectErrorCallback error_callback) {
1015 BLUETOOTH_LOG(EVENT) << object_path_.value() << ": Paired";
1016
1017 EndPairing();
1018
1019 ConnectInternal(true, std::move(callback), std::move(error_callback));
1020 }
1021
OnPairDuringConnectError(ConnectErrorCallback error_callback,const std::string & error_name,const std::string & error_message)1022 void BluetoothDeviceBlueZ::OnPairDuringConnectError(
1023 ConnectErrorCallback error_callback,
1024 const std::string& error_name,
1025 const std::string& error_message) {
1026 if (--num_connecting_calls_ == 0)
1027 adapter()->NotifyDeviceChanged(this);
1028
1029 DCHECK(num_connecting_calls_ >= 0);
1030 BLUETOOTH_LOG(ERROR) << object_path_.value()
1031 << ": Failed to pair device: " << error_name << ": "
1032 << error_message;
1033 BLUETOOTH_LOG(DEBUG) << object_path_.value() << ": " << num_connecting_calls_
1034 << " still in progress";
1035
1036 EndPairing();
1037
1038 // Determine the error code from error_name.
1039 ConnectErrorCode error_code = DBusErrorToConnectError(error_name);
1040
1041 RecordPairingResult(error_code);
1042 std::move(error_callback).Run(error_code);
1043 }
1044
OnPair(base::OnceClosure callback)1045 void BluetoothDeviceBlueZ::OnPair(base::OnceClosure callback) {
1046 BLUETOOTH_LOG(EVENT) << object_path_.value() << ": Paired";
1047 EndPairing();
1048 std::move(callback).Run();
1049 }
1050
OnPairError(ConnectErrorCallback error_callback,const std::string & error_name,const std::string & error_message)1051 void BluetoothDeviceBlueZ::OnPairError(ConnectErrorCallback error_callback,
1052 const std::string& error_name,
1053 const std::string& error_message) {
1054 BLUETOOTH_LOG(ERROR) << object_path_.value()
1055 << ": Failed to pair device: " << error_name << ": "
1056 << error_message;
1057 EndPairing();
1058 ConnectErrorCode error_code = DBusErrorToConnectError(error_name);
1059 RecordPairingResult(error_code);
1060 std::move(error_callback).Run(error_code);
1061 }
1062
OnCancelPairingError(const std::string & error_name,const std::string & error_message)1063 void BluetoothDeviceBlueZ::OnCancelPairingError(
1064 const std::string& error_name,
1065 const std::string& error_message) {
1066 BLUETOOTH_LOG(ERROR) << object_path_.value()
1067 << ": Failed to cancel pairing: " << error_name << ": "
1068 << error_message;
1069 }
1070
SetTrusted()1071 void BluetoothDeviceBlueZ::SetTrusted() {
1072 // Unconditionally send the property change, rather than checking the value
1073 // first; there's no harm in doing this and it solves any race conditions
1074 // with the property becoming true or false and this call happening before
1075 // we get the D-Bus signal about the earlier change.
1076 bluez::BluezDBusManager::Get()
1077 ->GetBluetoothDeviceClient()
1078 ->GetProperties(object_path_)
1079 ->trusted.Set(true, base::BindOnce(&BluetoothDeviceBlueZ::OnSetTrusted,
1080 weak_ptr_factory_.GetWeakPtr()));
1081 }
1082
OnSetTrusted(bool success)1083 void BluetoothDeviceBlueZ::OnSetTrusted(bool success) {
1084 device_event_log::LogLevel log_level =
1085 success ? device_event_log::LOG_LEVEL_DEBUG
1086 : device_event_log::LOG_LEVEL_ERROR;
1087 DEVICE_LOG(device_event_log::LOG_TYPE_BLUETOOTH, log_level)
1088 << object_path_.value() << ": OnSetTrusted: " << success;
1089 }
1090
OnDisconnect(const base::Closure & callback)1091 void BluetoothDeviceBlueZ::OnDisconnect(const base::Closure& callback) {
1092 BLUETOOTH_LOG(EVENT) << object_path_.value() << ": Disconnected";
1093 callback.Run();
1094 }
1095
OnDisconnectError(const ErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)1096 void BluetoothDeviceBlueZ::OnDisconnectError(
1097 const ErrorCallback& error_callback,
1098 const std::string& error_name,
1099 const std::string& error_message) {
1100 BLUETOOTH_LOG(ERROR) << object_path_.value()
1101 << ": Failed to disconnect device: " << error_name
1102 << ": " << error_message;
1103 error_callback.Run();
1104 }
1105
OnForgetError(const ErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)1106 void BluetoothDeviceBlueZ::OnForgetError(const ErrorCallback& error_callback,
1107 const std::string& error_name,
1108 const std::string& error_message) {
1109 BLUETOOTH_LOG(ERROR) << object_path_.value()
1110 << ": Failed to remove device: " << error_name << ": "
1111 << error_message;
1112 error_callback.Run();
1113 }
1114
UnpauseDiscovery()1115 void BluetoothDeviceBlueZ::UnpauseDiscovery() {
1116 bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->UnpauseDiscovery(
1117 adapter()->object_path(), base::BindOnce([]() {
1118 BLUETOOTH_LOG(EVENT) << "Successfully un-paused discovery";
1119 }),
1120 base::BindOnce(
1121 [](const std::string& error_name, const std::string& error_message) {
1122 BLUETOOTH_LOG(EVENT) << "Failed to un-pause discovery";
1123 }));
1124 }
1125
1126 } // namespace bluez
1127