OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "device/bluetooth/bluetooth_device_bluez.h" | |
6 | |
7 #include <stdio.h> | |
8 | |
9 #include <memory> | |
10 #include <utility> | |
11 | |
12 #include "base/bind.h" | |
13 #include "base/metrics/histogram.h" | |
14 #include "base/strings/string_number_conversions.h" | |
15 #include "base/strings/string_util.h" | |
16 #include "dbus/bus.h" | |
17 #include "device/bluetooth/bluetooth_adapter_bluez.h" | |
18 #include "device/bluetooth/bluetooth_gatt_connection_bluez.h" | |
19 #include "device/bluetooth/bluetooth_pairing_bluez.h" | |
20 #include "device/bluetooth/bluetooth_remote_gatt_service_bluez.h" | |
21 #include "device/bluetooth/bluetooth_socket.h" | |
22 #include "device/bluetooth/bluetooth_socket_bluez.h" | |
23 #include "device/bluetooth/bluetooth_socket_thread.h" | |
24 #include "device/bluetooth/bluetooth_uuid.h" | |
25 #include "device/bluetooth/dbus/bluetooth_adapter_client.h" | |
26 #include "device/bluetooth/dbus/bluetooth_device_client.h" | |
27 #include "device/bluetooth/dbus/bluetooth_gatt_service_client.h" | |
28 #include "device/bluetooth/dbus/bluetooth_input_client.h" | |
29 #include "device/bluetooth/dbus/bluez_dbus_manager.h" | |
30 #include "third_party/cros_system_api/dbus/service_constants.h" | |
31 | |
32 using device::BluetoothDevice; | |
33 using device::BluetoothGattService; | |
34 using device::BluetoothSocket; | |
35 using device::BluetoothUUID; | |
36 | |
37 namespace { | |
38 | |
39 // Histogram enumerations for pairing results. | |
40 enum UMAPairingResult { | |
41 UMA_PAIRING_RESULT_SUCCESS, | |
42 UMA_PAIRING_RESULT_INPROGRESS, | |
43 UMA_PAIRING_RESULT_FAILED, | |
44 UMA_PAIRING_RESULT_AUTH_FAILED, | |
45 UMA_PAIRING_RESULT_AUTH_CANCELED, | |
46 UMA_PAIRING_RESULT_AUTH_REJECTED, | |
47 UMA_PAIRING_RESULT_AUTH_TIMEOUT, | |
48 UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE, | |
49 UMA_PAIRING_RESULT_UNKNOWN_ERROR, | |
50 // NOTE: Add new pairing results immediately above this line. Make sure to | |
51 // update the enum list in tools/histogram/histograms.xml accordinly. | |
52 UMA_PAIRING_RESULT_COUNT | |
53 }; | |
54 | |
55 void ParseModalias(const dbus::ObjectPath& object_path, | |
56 BluetoothDevice::VendorIDSource* vendor_id_source, | |
57 uint16_t* vendor_id, | |
58 uint16_t* product_id, | |
59 uint16_t* device_id) { | |
60 bluez::BluetoothDeviceClient::Properties* properties = | |
61 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
62 object_path); | |
63 DCHECK(properties); | |
64 | |
65 std::string modalias = properties->modalias.value(); | |
66 BluetoothDevice::VendorIDSource source_value; | |
67 int vendor_value, product_value, device_value; | |
68 | |
69 if (sscanf(modalias.c_str(), "bluetooth:v%04xp%04xd%04x", &vendor_value, | |
70 &product_value, &device_value) == 3) { | |
71 source_value = BluetoothDevice::VENDOR_ID_BLUETOOTH; | |
72 } else if (sscanf(modalias.c_str(), "usb:v%04xp%04xd%04x", &vendor_value, | |
73 &product_value, &device_value) == 3) { | |
74 source_value = BluetoothDevice::VENDOR_ID_USB; | |
75 } else { | |
76 return; | |
77 } | |
78 | |
79 if (vendor_id_source != NULL) | |
80 *vendor_id_source = source_value; | |
81 if (vendor_id != NULL) | |
82 *vendor_id = vendor_value; | |
83 if (product_id != NULL) | |
84 *product_id = product_value; | |
85 if (device_id != NULL) | |
86 *device_id = device_value; | |
87 } | |
88 | |
89 void RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code) { | |
90 UMAPairingResult pairing_result; | |
91 switch (error_code) { | |
92 case BluetoothDevice::ERROR_INPROGRESS: | |
93 pairing_result = UMA_PAIRING_RESULT_INPROGRESS; | |
94 break; | |
95 case BluetoothDevice::ERROR_FAILED: | |
96 pairing_result = UMA_PAIRING_RESULT_FAILED; | |
97 break; | |
98 case BluetoothDevice::ERROR_AUTH_FAILED: | |
99 pairing_result = UMA_PAIRING_RESULT_AUTH_FAILED; | |
100 break; | |
101 case BluetoothDevice::ERROR_AUTH_CANCELED: | |
102 pairing_result = UMA_PAIRING_RESULT_AUTH_CANCELED; | |
103 break; | |
104 case BluetoothDevice::ERROR_AUTH_REJECTED: | |
105 pairing_result = UMA_PAIRING_RESULT_AUTH_REJECTED; | |
106 break; | |
107 case BluetoothDevice::ERROR_AUTH_TIMEOUT: | |
108 pairing_result = UMA_PAIRING_RESULT_AUTH_TIMEOUT; | |
109 break; | |
110 case BluetoothDevice::ERROR_UNSUPPORTED_DEVICE: | |
111 pairing_result = UMA_PAIRING_RESULT_UNSUPPORTED_DEVICE; | |
112 break; | |
113 default: | |
114 pairing_result = UMA_PAIRING_RESULT_UNKNOWN_ERROR; | |
115 } | |
116 | |
117 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult", pairing_result, | |
118 UMA_PAIRING_RESULT_COUNT); | |
119 } | |
120 | |
121 BluetoothDevice::ConnectErrorCode DBusErrorToConnectError( | |
122 const std::string& error_name) { | |
123 BluetoothDevice::ConnectErrorCode error_code = BluetoothDevice::ERROR_UNKNOWN; | |
124 if (error_name == bluetooth_device::kErrorConnectionAttemptFailed) { | |
125 error_code = BluetoothDevice::ERROR_FAILED; | |
126 } else if (error_name == bluetooth_device::kErrorFailed) { | |
127 error_code = BluetoothDevice::ERROR_FAILED; | |
128 } else if (error_name == bluetooth_device::kErrorAuthenticationFailed) { | |
129 error_code = BluetoothDevice::ERROR_AUTH_FAILED; | |
130 } else if (error_name == bluetooth_device::kErrorAuthenticationCanceled) { | |
131 error_code = BluetoothDevice::ERROR_AUTH_CANCELED; | |
132 } else if (error_name == bluetooth_device::kErrorAuthenticationRejected) { | |
133 error_code = BluetoothDevice::ERROR_AUTH_REJECTED; | |
134 } else if (error_name == bluetooth_device::kErrorAuthenticationTimeout) { | |
135 error_code = BluetoothDevice::ERROR_AUTH_TIMEOUT; | |
136 } | |
137 return error_code; | |
138 } | |
139 | |
140 } // namespace | |
141 | |
142 namespace bluez { | |
143 | |
144 BluetoothDeviceBlueZ::BluetoothDeviceBlueZ( | |
145 BluetoothAdapterBlueZ* adapter, | |
146 const dbus::ObjectPath& object_path, | |
147 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, | |
148 scoped_refptr<device::BluetoothSocketThread> socket_thread) | |
149 : BluetoothDevice(adapter), | |
150 object_path_(object_path), | |
151 num_connecting_calls_(0), | |
152 connection_monitor_started_(false), | |
153 ui_task_runner_(ui_task_runner), | |
154 socket_thread_(socket_thread), | |
155 weak_ptr_factory_(this) { | |
156 bluez::BluezDBusManager::Get()->GetBluetoothGattServiceClient()->AddObserver( | |
157 this); | |
158 | |
159 // Add all known GATT services. | |
160 const std::vector<dbus::ObjectPath> gatt_services = | |
161 bluez::BluezDBusManager::Get() | |
162 ->GetBluetoothGattServiceClient() | |
163 ->GetServices(); | |
164 for (std::vector<dbus::ObjectPath>::const_iterator it = gatt_services.begin(); | |
165 it != gatt_services.end(); ++it) { | |
166 GattServiceAdded(*it); | |
167 } | |
168 } | |
169 | |
170 BluetoothDeviceBlueZ::~BluetoothDeviceBlueZ() { | |
171 bluez::BluezDBusManager::Get() | |
172 ->GetBluetoothGattServiceClient() | |
173 ->RemoveObserver(this); | |
174 | |
175 // Copy the GATT services list here and clear the original so that when we | |
176 // send GattServiceRemoved(), GetGattServices() returns no services. | |
177 GattServiceMap gatt_services_swapped; | |
178 gatt_services_swapped.swap(gatt_services_); | |
179 for (const auto& iter : gatt_services_swapped) { | |
180 DCHECK(adapter_); | |
181 adapter()->NotifyGattServiceRemoved( | |
182 static_cast<BluetoothRemoteGattServiceBlueZ*>(iter.second)); | |
183 } | |
184 } | |
185 | |
186 uint32_t BluetoothDeviceBlueZ::GetBluetoothClass() const { | |
187 bluez::BluetoothDeviceClient::Properties* properties = | |
188 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
189 object_path_); | |
190 DCHECK(properties); | |
191 | |
192 return properties->bluetooth_class.value(); | |
193 } | |
194 | |
195 std::string BluetoothDeviceBlueZ::GetDeviceName() const { | |
196 bluez::BluetoothDeviceClient::Properties* properties = | |
197 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
198 object_path_); | |
199 DCHECK(properties); | |
200 | |
201 return properties->alias.value(); | |
202 } | |
203 | |
204 void BluetoothDeviceBlueZ::CreateGattConnectionImpl() { | |
205 // BlueZ implementation does not use the default CreateGattConnection | |
206 // implementation. | |
207 NOTIMPLEMENTED(); | |
208 } | |
209 | |
210 void BluetoothDeviceBlueZ::DisconnectGatt() { | |
211 Disconnect(base::Bind(&base::DoNothing), base::Bind(&base::DoNothing)); | |
212 } | |
213 | |
214 std::string BluetoothDeviceBlueZ::GetAddress() const { | |
215 bluez::BluetoothDeviceClient::Properties* properties = | |
216 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
217 object_path_); | |
218 DCHECK(properties); | |
219 | |
220 return CanonicalizeAddress(properties->address.value()); | |
221 } | |
222 | |
223 BluetoothDevice::VendorIDSource BluetoothDeviceBlueZ::GetVendorIDSource() | |
224 const { | |
225 VendorIDSource vendor_id_source = VENDOR_ID_UNKNOWN; | |
226 ParseModalias(object_path_, &vendor_id_source, NULL, NULL, NULL); | |
227 return vendor_id_source; | |
228 } | |
229 | |
230 uint16_t BluetoothDeviceBlueZ::GetVendorID() const { | |
231 uint16_t vendor_id = 0; | |
232 ParseModalias(object_path_, NULL, &vendor_id, NULL, NULL); | |
233 return vendor_id; | |
234 } | |
235 | |
236 uint16_t BluetoothDeviceBlueZ::GetProductID() const { | |
237 uint16_t product_id = 0; | |
238 ParseModalias(object_path_, NULL, NULL, &product_id, NULL); | |
239 return product_id; | |
240 } | |
241 | |
242 uint16_t BluetoothDeviceBlueZ::GetDeviceID() const { | |
243 uint16_t device_id = 0; | |
244 ParseModalias(object_path_, NULL, NULL, NULL, &device_id); | |
245 return device_id; | |
246 } | |
247 | |
248 uint16_t BluetoothDeviceBlueZ::GetAppearance() const { | |
249 bluez::BluetoothDeviceClient::Properties* properties = | |
250 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
251 object_path_); | |
252 DCHECK(properties); | |
253 | |
254 if (!properties->appearance.is_valid()) | |
255 return kAppearanceNotPresent; | |
256 | |
257 return properties->appearance.value(); | |
258 } | |
259 | |
260 bool BluetoothDeviceBlueZ::IsPaired() const { | |
261 bluez::BluetoothDeviceClient::Properties* properties = | |
262 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
263 object_path_); | |
264 DCHECK(properties); | |
265 | |
266 // Trusted devices are devices that don't support pairing but that the | |
267 // user has explicitly connected; it makes no sense for UI purposes to | |
268 // treat them differently from each other. | |
269 return properties->paired.value() || properties->trusted.value(); | |
270 } | |
271 | |
272 bool BluetoothDeviceBlueZ::IsConnected() const { | |
273 bluez::BluetoothDeviceClient::Properties* properties = | |
274 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
275 object_path_); | |
276 DCHECK(properties); | |
277 | |
278 return properties->connected.value(); | |
279 } | |
280 | |
281 bool BluetoothDeviceBlueZ::IsGattConnected() const { | |
282 NOTIMPLEMENTED(); | |
283 return false; | |
284 } | |
285 | |
286 bool BluetoothDeviceBlueZ::IsConnectable() const { | |
287 bluez::BluetoothInputClient::Properties* input_properties = | |
288 bluez::BluezDBusManager::Get()->GetBluetoothInputClient()->GetProperties( | |
289 object_path_); | |
290 // GetProperties returns NULL when the device does not implement the given | |
291 // interface. Non HID devices are normally connectable. | |
292 if (!input_properties) | |
293 return true; | |
294 | |
295 return input_properties->reconnect_mode.value() != "device"; | |
296 } | |
297 | |
298 bool BluetoothDeviceBlueZ::IsConnecting() const { | |
299 return num_connecting_calls_ > 0; | |
300 } | |
301 | |
302 BluetoothDeviceBlueZ::UUIDList BluetoothDeviceBlueZ::GetUUIDs() const { | |
303 bluez::BluetoothDeviceClient::Properties* properties = | |
304 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
305 object_path_); | |
306 DCHECK(properties); | |
307 | |
308 std::vector<device::BluetoothUUID> uuids; | |
309 const std::vector<std::string>& dbus_uuids = properties->uuids.value(); | |
310 for (std::vector<std::string>::const_iterator iter = dbus_uuids.begin(); | |
311 iter != dbus_uuids.end(); ++iter) { | |
312 device::BluetoothUUID uuid(*iter); | |
313 DCHECK(uuid.IsValid()); | |
314 uuids.push_back(uuid); | |
315 } | |
316 return uuids; | |
317 } | |
318 | |
319 int16_t BluetoothDeviceBlueZ::GetInquiryRSSI() const { | |
320 bluez::BluetoothDeviceClient::Properties* properties = | |
321 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
322 object_path_); | |
323 DCHECK(properties); | |
324 | |
325 if (!properties->rssi.is_valid()) | |
326 return kUnknownPower; | |
327 | |
328 return properties->rssi.value(); | |
329 } | |
330 | |
331 int16_t BluetoothDeviceBlueZ::GetInquiryTxPower() const { | |
332 bluez::BluetoothDeviceClient::Properties* properties = | |
333 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( | |
334 object_path_); | |
335 DCHECK(properties); | |
336 | |
337 if (!properties->tx_power.is_valid()) | |
338 return kUnknownPower; | |
339 | |
340 return properties->tx_power.value(); | |
341 } | |
342 | |
343 bool BluetoothDeviceBlueZ::ExpectingPinCode() const { | |
344 return pairing_.get() && pairing_->ExpectingPinCode(); | |
345 } | |
346 | |
347 bool BluetoothDeviceBlueZ::ExpectingPasskey() const { | |
348 return pairing_.get() && pairing_->ExpectingPasskey(); | |
349 } | |
350 | |
351 bool BluetoothDeviceBlueZ::ExpectingConfirmation() const { | |
352 return pairing_.get() && pairing_->ExpectingConfirmation(); | |
353 } | |
354 | |
355 void BluetoothDeviceBlueZ::GetConnectionInfo( | |
356 const ConnectionInfoCallback& callback) { | |
357 // DBus method call should gracefully return an error if the device is not | |
358 // currently connected. | |
359 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetConnInfo( | |
360 object_path_, base::Bind(&BluetoothDeviceBlueZ::OnGetConnInfo, | |
361 weak_ptr_factory_.GetWeakPtr(), callback), | |
362 base::Bind(&BluetoothDeviceBlueZ::OnGetConnInfoError, | |
363 weak_ptr_factory_.GetWeakPtr(), callback)); | |
364 } | |
365 | |
366 void BluetoothDeviceBlueZ::Connect( | |
367 BluetoothDevice::PairingDelegate* pairing_delegate, | |
368 const base::Closure& callback, | |
369 const ConnectErrorCallback& error_callback) { | |
370 if (num_connecting_calls_++ == 0) | |
371 adapter()->NotifyDeviceChanged(this); | |
372 | |
373 VLOG(1) << object_path_.value() << ": Connecting, " << num_connecting_calls_ | |
374 << " in progress"; | |
375 | |
376 if (IsPaired() || !pairing_delegate || !IsPairable()) { | |
377 // No need to pair, or unable to, skip straight to connection. | |
378 ConnectInternal(false, callback, error_callback); | |
379 } else { | |
380 // Initiate high-security connection with pairing. | |
381 BeginPairing(pairing_delegate); | |
382 | |
383 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Pair( | |
384 object_path_, | |
385 base::Bind(&BluetoothDeviceBlueZ::OnPairDuringConnect, | |
386 weak_ptr_factory_.GetWeakPtr(), callback, error_callback), | |
387 base::Bind(&BluetoothDeviceBlueZ::OnPairDuringConnectError, | |
388 weak_ptr_factory_.GetWeakPtr(), error_callback)); | |
389 } | |
390 } | |
391 | |
392 void BluetoothDeviceBlueZ::Pair( | |
393 BluetoothDevice::PairingDelegate* pairing_delegate, | |
394 const base::Closure& callback, | |
395 const ConnectErrorCallback& error_callback) { | |
396 DCHECK(pairing_delegate); | |
397 BeginPairing(pairing_delegate); | |
398 | |
399 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Pair( | |
400 object_path_, base::Bind(&BluetoothDeviceBlueZ::OnPair, | |
401 weak_ptr_factory_.GetWeakPtr(), callback), | |
402 base::Bind(&BluetoothDeviceBlueZ::OnPairError, | |
403 weak_ptr_factory_.GetWeakPtr(), error_callback)); | |
404 } | |
405 | |
406 void BluetoothDeviceBlueZ::SetPinCode(const std::string& pincode) { | |
407 if (!pairing_.get()) | |
408 return; | |
409 | |
410 pairing_->SetPinCode(pincode); | |
411 } | |
412 | |
413 void BluetoothDeviceBlueZ::SetPasskey(uint32_t passkey) { | |
414 if (!pairing_.get()) | |
415 return; | |
416 | |
417 pairing_->SetPasskey(passkey); | |
418 } | |
419 | |
420 void BluetoothDeviceBlueZ::ConfirmPairing() { | |
421 if (!pairing_.get()) | |
422 return; | |
423 | |
424 pairing_->ConfirmPairing(); | |
425 } | |
426 | |
427 void BluetoothDeviceBlueZ::RejectPairing() { | |
428 if (!pairing_.get()) | |
429 return; | |
430 | |
431 pairing_->RejectPairing(); | |
432 } | |
433 | |
434 void BluetoothDeviceBlueZ::CancelPairing() { | |
435 bool canceled = false; | |
436 | |
437 // If there is a callback in progress that we can reply to then use that | |
438 // to cancel the current pairing request. | |
439 if (pairing_.get() && pairing_->CancelPairing()) | |
440 canceled = true; | |
441 | |
442 // If not we have to send an explicit CancelPairing() to the device instead. | |
443 if (!canceled) { | |
444 VLOG(1) << object_path_.value() << ": No pairing context or callback. " | |
445 << "Sending explicit cancel"; | |
446 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->CancelPairing( | |
447 object_path_, base::Bind(&base::DoNothing), | |
448 base::Bind(&BluetoothDeviceBlueZ::OnCancelPairingError, | |
449 weak_ptr_factory_.GetWeakPtr())); | |
450 } | |
451 | |
452 // Since there is no callback to this method it's possible that the pairing | |
453 // delegate is going to be freed before things complete (indeed it's | |
454 // documented that this is the method you should call while freeing the | |
455 // pairing delegate), so clear our the context holding on to it. | |
456 EndPairing(); | |
457 } | |
458 | |
459 void BluetoothDeviceBlueZ::Disconnect(const base::Closure& callback, | |
460 const ErrorCallback& error_callback) { | |
461 VLOG(1) << object_path_.value() << ": Disconnecting"; | |
462 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Disconnect( | |
463 object_path_, base::Bind(&BluetoothDeviceBlueZ::OnDisconnect, | |
464 weak_ptr_factory_.GetWeakPtr(), callback), | |
465 base::Bind(&BluetoothDeviceBlueZ::OnDisconnectError, | |
466 weak_ptr_factory_.GetWeakPtr(), error_callback)); | |
467 } | |
468 | |
469 void BluetoothDeviceBlueZ::Forget(const base::Closure& callback, | |
470 const ErrorCallback& error_callback) { | |
471 VLOG(1) << object_path_.value() << ": Removing device"; | |
472 bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->RemoveDevice( | |
473 adapter()->object_path(), object_path_, callback, | |
474 base::Bind(&BluetoothDeviceBlueZ::OnForgetError, | |
475 weak_ptr_factory_.GetWeakPtr(), error_callback)); | |
476 } | |
477 | |
478 void BluetoothDeviceBlueZ::ConnectToService( | |
479 const BluetoothUUID& uuid, | |
480 const ConnectToServiceCallback& callback, | |
481 const ConnectToServiceErrorCallback& error_callback) { | |
482 VLOG(1) << object_path_.value() | |
483 << ": Connecting to service: " << uuid.canonical_value(); | |
484 scoped_refptr<BluetoothSocketBlueZ> socket = | |
485 BluetoothSocketBlueZ::CreateBluetoothSocket(ui_task_runner_, | |
486 socket_thread_); | |
487 socket->Connect(this, uuid, BluetoothSocketBlueZ::SECURITY_LEVEL_MEDIUM, | |
488 base::Bind(callback, socket), error_callback); | |
489 } | |
490 | |
491 void BluetoothDeviceBlueZ::ConnectToServiceInsecurely( | |
492 const BluetoothUUID& uuid, | |
493 const ConnectToServiceCallback& callback, | |
494 const ConnectToServiceErrorCallback& error_callback) { | |
495 VLOG(1) << object_path_.value() | |
496 << ": Connecting insecurely to service: " << uuid.canonical_value(); | |
497 scoped_refptr<BluetoothSocketBlueZ> socket = | |
498 BluetoothSocketBlueZ::CreateBluetoothSocket(ui_task_runner_, | |
499 socket_thread_); | |
500 socket->Connect(this, uuid, BluetoothSocketBlueZ::SECURITY_LEVEL_LOW, | |
501 base::Bind(callback, socket), error_callback); | |
502 } | |
503 | |
504 void BluetoothDeviceBlueZ::CreateGattConnection( | |
505 const GattConnectionCallback& callback, | |
506 const ConnectErrorCallback& error_callback) { | |
507 // TODO(sacomoto): Workaround to retrieve the connection for already connected | |
508 // devices. Currently, BluetoothGattConnection::Disconnect doesn't do | |
509 // anything, the unique underlying physical GATT connection is kept. This | |
510 // should be removed once the correct behavour is implemented and the GATT | |
511 // connections are reference counted (see todo below). | |
512 if (IsConnected()) { | |
513 OnCreateGattConnection(callback); | |
514 return; | |
515 } | |
516 | |
517 // TODO(armansito): Until there is a way to create a reference counted GATT | |
518 // connection in bluetoothd, simply do a regular connect. | |
519 Connect(NULL, base::Bind(&BluetoothDeviceBlueZ::OnCreateGattConnection, | |
520 weak_ptr_factory_.GetWeakPtr(), callback), | |
521 error_callback); | |
522 } | |
523 | |
524 BluetoothPairingBlueZ* BluetoothDeviceBlueZ::BeginPairing( | |
525 BluetoothDevice::PairingDelegate* pairing_delegate) { | |
526 pairing_.reset(new BluetoothPairingBlueZ(this, pairing_delegate)); | |
527 return pairing_.get(); | |
528 } | |
529 | |
530 void BluetoothDeviceBlueZ::EndPairing() { | |
531 pairing_.reset(); | |
532 } | |
533 | |
534 BluetoothPairingBlueZ* BluetoothDeviceBlueZ::GetPairing() const { | |
535 return pairing_.get(); | |
536 } | |
537 | |
538 BluetoothAdapterBlueZ* BluetoothDeviceBlueZ::adapter() const { | |
539 return static_cast<BluetoothAdapterBlueZ*>(adapter_); | |
540 } | |
541 | |
542 void BluetoothDeviceBlueZ::GattServiceAdded( | |
543 const dbus::ObjectPath& object_path) { | |
544 if (GetGattService(object_path.value())) { | |
545 VLOG(1) << "Remote GATT service already exists: " << object_path.value(); | |
546 return; | |
547 } | |
548 | |
549 bluez::BluetoothGattServiceClient::Properties* properties = | |
550 bluez::BluezDBusManager::Get() | |
551 ->GetBluetoothGattServiceClient() | |
552 ->GetProperties(object_path); | |
553 DCHECK(properties); | |
554 if (properties->device.value() != object_path_) { | |
555 VLOG(2) << "Remote GATT service does not belong to this device."; | |
556 return; | |
557 } | |
558 | |
559 VLOG(1) << "Adding new remote GATT service for device: " << GetAddress(); | |
560 | |
561 BluetoothRemoteGattServiceBlueZ* service = | |
562 new BluetoothRemoteGattServiceBlueZ(adapter(), this, object_path); | |
563 | |
564 gatt_services_.set(service->GetIdentifier(), | |
565 std::unique_ptr<BluetoothGattService>(service)); | |
566 DCHECK(service->object_path() == object_path); | |
567 DCHECK(service->GetUUID().IsValid()); | |
568 | |
569 DCHECK(adapter_); | |
570 adapter()->NotifyGattServiceAdded(service); | |
571 } | |
572 | |
573 void BluetoothDeviceBlueZ::GattServiceRemoved( | |
574 const dbus::ObjectPath& object_path) { | |
575 GattServiceMap::const_iterator iter = | |
576 gatt_services_.find(object_path.value()); | |
577 if (iter == gatt_services_.end()) { | |
578 VLOG(3) << "Unknown GATT service removed: " << object_path.value(); | |
579 return; | |
580 } | |
581 | |
582 BluetoothRemoteGattServiceBlueZ* service = | |
583 static_cast<BluetoothRemoteGattServiceBlueZ*>(iter->second); | |
584 | |
585 VLOG(1) << "Removing remote GATT service with UUID: '" | |
586 << service->GetUUID().canonical_value() | |
587 << "' from device: " << GetAddress(); | |
588 | |
589 DCHECK(service->object_path() == object_path); | |
590 std::unique_ptr<BluetoothGattService> scoped_service = | |
591 gatt_services_.take_and_erase(iter->first); | |
592 | |
593 DCHECK(adapter_); | |
594 adapter()->NotifyGattServiceRemoved(service); | |
595 } | |
596 | |
597 void BluetoothDeviceBlueZ::OnGetConnInfo(const ConnectionInfoCallback& callback, | |
598 int16_t rssi, | |
599 int16_t transmit_power, | |
600 int16_t max_transmit_power) { | |
601 callback.Run(ConnectionInfo(rssi, transmit_power, max_transmit_power)); | |
602 } | |
603 | |
604 void BluetoothDeviceBlueZ::OnGetConnInfoError( | |
605 const ConnectionInfoCallback& callback, | |
606 const std::string& error_name, | |
607 const std::string& error_message) { | |
608 LOG(WARNING) << object_path_.value() | |
609 << ": Failed to get connection info: " << error_name << ": " | |
610 << error_message; | |
611 callback.Run(ConnectionInfo()); | |
612 } | |
613 | |
614 void BluetoothDeviceBlueZ::ConnectInternal( | |
615 bool after_pairing, | |
616 const base::Closure& callback, | |
617 const ConnectErrorCallback& error_callback) { | |
618 VLOG(1) << object_path_.value() << ": Connecting"; | |
619 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->Connect( | |
620 object_path_, | |
621 base::Bind(&BluetoothDeviceBlueZ::OnConnect, | |
622 weak_ptr_factory_.GetWeakPtr(), after_pairing, callback), | |
623 base::Bind(&BluetoothDeviceBlueZ::OnConnectError, | |
624 weak_ptr_factory_.GetWeakPtr(), after_pairing, | |
625 error_callback)); | |
626 } | |
627 | |
628 void BluetoothDeviceBlueZ::OnConnect(bool after_pairing, | |
629 const base::Closure& callback) { | |
630 if (--num_connecting_calls_ == 0) | |
631 adapter()->NotifyDeviceChanged(this); | |
632 | |
633 DCHECK(num_connecting_calls_ >= 0); | |
634 VLOG(1) << object_path_.value() << ": Connected, " << num_connecting_calls_ | |
635 << " still in progress"; | |
636 | |
637 SetTrusted(); | |
638 | |
639 if (after_pairing) | |
640 UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingResult", | |
641 UMA_PAIRING_RESULT_SUCCESS, | |
642 UMA_PAIRING_RESULT_COUNT); | |
643 | |
644 callback.Run(); | |
645 } | |
646 | |
647 void BluetoothDeviceBlueZ::OnCreateGattConnection( | |
648 const GattConnectionCallback& callback) { | |
649 std::unique_ptr<device::BluetoothGattConnection> conn( | |
650 new BluetoothGattConnectionBlueZ(adapter_, GetAddress(), object_path_)); | |
651 callback.Run(std::move(conn)); | |
652 } | |
653 | |
654 void BluetoothDeviceBlueZ::OnConnectError( | |
655 bool after_pairing, | |
656 const ConnectErrorCallback& error_callback, | |
657 const std::string& error_name, | |
658 const std::string& error_message) { | |
659 if (--num_connecting_calls_ == 0) | |
660 adapter()->NotifyDeviceChanged(this); | |
661 | |
662 DCHECK(num_connecting_calls_ >= 0); | |
663 LOG(WARNING) << object_path_.value() | |
664 << ": Failed to connect device: " << error_name << ": " | |
665 << error_message; | |
666 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ | |
667 << " still in progress"; | |
668 | |
669 // Determine the error code from error_name. | |
670 ConnectErrorCode error_code = ERROR_UNKNOWN; | |
671 if (error_name == bluetooth_device::kErrorFailed) { | |
672 error_code = ERROR_FAILED; | |
673 } else if (error_name == bluetooth_device::kErrorInProgress) { | |
674 error_code = ERROR_INPROGRESS; | |
675 } else if (error_name == bluetooth_device::kErrorNotSupported) { | |
676 error_code = ERROR_UNSUPPORTED_DEVICE; | |
677 } | |
678 | |
679 if (after_pairing) | |
680 RecordPairingResult(error_code); | |
681 error_callback.Run(error_code); | |
682 } | |
683 | |
684 void BluetoothDeviceBlueZ::OnPairDuringConnect( | |
685 const base::Closure& callback, | |
686 const ConnectErrorCallback& error_callback) { | |
687 VLOG(1) << object_path_.value() << ": Paired"; | |
688 | |
689 EndPairing(); | |
690 | |
691 ConnectInternal(true, callback, error_callback); | |
692 } | |
693 | |
694 void BluetoothDeviceBlueZ::OnPairDuringConnectError( | |
695 const ConnectErrorCallback& error_callback, | |
696 const std::string& error_name, | |
697 const std::string& error_message) { | |
698 if (--num_connecting_calls_ == 0) | |
699 adapter()->NotifyDeviceChanged(this); | |
700 | |
701 DCHECK(num_connecting_calls_ >= 0); | |
702 LOG(WARNING) << object_path_.value() | |
703 << ": Failed to pair device: " << error_name << ": " | |
704 << error_message; | |
705 VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ | |
706 << " still in progress"; | |
707 | |
708 EndPairing(); | |
709 | |
710 // Determine the error code from error_name. | |
711 ConnectErrorCode error_code = DBusErrorToConnectError(error_name); | |
712 | |
713 RecordPairingResult(error_code); | |
714 error_callback.Run(error_code); | |
715 } | |
716 | |
717 void BluetoothDeviceBlueZ::OnPair(const base::Closure& callback) { | |
718 VLOG(1) << object_path_.value() << ": Paired"; | |
719 EndPairing(); | |
720 callback.Run(); | |
721 } | |
722 | |
723 void BluetoothDeviceBlueZ::OnPairError( | |
724 const ConnectErrorCallback& error_callback, | |
725 const std::string& error_name, | |
726 const std::string& error_message) { | |
727 LOG(WARNING) << object_path_.value() | |
728 << ": Failed to pair device: " << error_name << ": " | |
729 << error_message; | |
730 EndPairing(); | |
731 ConnectErrorCode error_code = DBusErrorToConnectError(error_name); | |
732 RecordPairingResult(error_code); | |
733 error_callback.Run(error_code); | |
734 } | |
735 | |
736 void BluetoothDeviceBlueZ::OnCancelPairingError( | |
737 const std::string& error_name, | |
738 const std::string& error_message) { | |
739 LOG(WARNING) << object_path_.value() | |
740 << ": Failed to cancel pairing: " << error_name << ": " | |
741 << error_message; | |
742 } | |
743 | |
744 void BluetoothDeviceBlueZ::SetTrusted() { | |
745 // Unconditionally send the property change, rather than checking the value | |
746 // first; there's no harm in doing this and it solves any race conditions | |
747 // with the property becoming true or false and this call happening before | |
748 // we get the D-Bus signal about the earlier change. | |
749 bluez::BluezDBusManager::Get() | |
750 ->GetBluetoothDeviceClient() | |
751 ->GetProperties(object_path_) | |
752 ->trusted.Set(true, base::Bind(&BluetoothDeviceBlueZ::OnSetTrusted, | |
753 weak_ptr_factory_.GetWeakPtr())); | |
754 } | |
755 | |
756 void BluetoothDeviceBlueZ::OnSetTrusted(bool success) { | |
757 LOG_IF(WARNING, !success) << object_path_.value() | |
758 << ": Failed to set device as trusted"; | |
759 } | |
760 | |
761 void BluetoothDeviceBlueZ::OnDisconnect(const base::Closure& callback) { | |
762 VLOG(1) << object_path_.value() << ": Disconnected"; | |
763 callback.Run(); | |
764 } | |
765 | |
766 void BluetoothDeviceBlueZ::OnDisconnectError( | |
767 const ErrorCallback& error_callback, | |
768 const std::string& error_name, | |
769 const std::string& error_message) { | |
770 LOG(WARNING) << object_path_.value() | |
771 << ": Failed to disconnect device: " << error_name << ": " | |
772 << error_message; | |
773 error_callback.Run(); | |
774 } | |
775 | |
776 void BluetoothDeviceBlueZ::OnForgetError(const ErrorCallback& error_callback, | |
777 const std::string& error_name, | |
778 const std::string& error_message) { | |
779 LOG(WARNING) << object_path_.value() | |
780 << ": Failed to remove device: " << error_name << ": " | |
781 << error_message; | |
782 error_callback.Run(); | |
783 } | |
784 | |
785 } // namespace bluez | |
OLD | NEW |