OLD | NEW |
| (Empty) |
1 // Copyright 2015 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 "components/proximity_auth/ble/bluetooth_low_energy_connection.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/location.h" | |
11 #include "base/memory/ref_counted.h" | |
12 #include "base/memory/weak_ptr.h" | |
13 #include "base/task_runner.h" | |
14 #include "base/threading/thread_task_runner_handle.h" | |
15 #include "base/time/time.h" | |
16 #include "components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h
" | |
17 #include "components/cryptauth/ble/fake_wire_message.h" | |
18 #include "components/cryptauth/bluetooth_throttler.h" | |
19 #include "components/cryptauth/connection.h" | |
20 #include "components/cryptauth/connection_finder.h" | |
21 #include "components/cryptauth/wire_message.h" | |
22 #include "components/proximity_auth/logging/logging.h" | |
23 #include "device/bluetooth/bluetooth_adapter.h" | |
24 #include "device/bluetooth/bluetooth_device.h" | |
25 #include "device/bluetooth/bluetooth_gatt_connection.h" | |
26 #include "device/bluetooth/bluetooth_gatt_notify_session.h" | |
27 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h" | |
28 #include "device/bluetooth/bluetooth_uuid.h" | |
29 | |
30 using device::BluetoothAdapter; | |
31 using device::BluetoothDevice; | |
32 using device::BluetoothGattConnection; | |
33 using device::BluetoothRemoteGattService; | |
34 using device::BluetoothRemoteGattCharacteristic; | |
35 using device::BluetoothGattNotifySession; | |
36 using device::BluetoothUUID; | |
37 | |
38 namespace proximity_auth { | |
39 namespace { | |
40 | |
41 // The UUID of the characteristic used to send data to the peripheral. | |
42 const char kToPeripheralCharUUID[] = "977c6674-1239-4e72-993b-502369b8bb5a"; | |
43 | |
44 // The UUID of the characteristic used to receive data from the peripheral. | |
45 const char kFromPeripheralCharUUID[] = "f4b904a2-a030-43b3-98a8-221c536c03cb"; | |
46 | |
47 // Deprecated signal send as the first byte in send byte operations. | |
48 const int kFirstByteZero = 0; | |
49 | |
50 // The maximum number of bytes written in a remote characteristic with a single | |
51 // write request. This is not the connection MTU, we are assuming that the | |
52 // remote device allows for writes larger than MTU. | |
53 const int kMaxChunkSize = 500; | |
54 } // namespace | |
55 | |
56 BluetoothLowEnergyConnection::BluetoothLowEnergyConnection( | |
57 const cryptauth::RemoteDevice& device, | |
58 scoped_refptr<device::BluetoothAdapter> adapter, | |
59 const BluetoothUUID remote_service_uuid, | |
60 cryptauth::BluetoothThrottler* bluetooth_throttler, | |
61 int max_number_of_write_attempts) | |
62 : cryptauth::Connection(device), | |
63 adapter_(adapter), | |
64 remote_service_({remote_service_uuid, ""}), | |
65 to_peripheral_char_({BluetoothUUID(kToPeripheralCharUUID), ""}), | |
66 from_peripheral_char_({BluetoothUUID(kFromPeripheralCharUUID), ""}), | |
67 bluetooth_throttler_(bluetooth_throttler), | |
68 task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
69 sub_status_(SubStatus::DISCONNECTED), | |
70 receiving_bytes_(false), | |
71 write_remote_characteristic_pending_(false), | |
72 max_number_of_write_attempts_(max_number_of_write_attempts), | |
73 max_chunk_size_(kMaxChunkSize), | |
74 weak_ptr_factory_(this) { | |
75 DCHECK(adapter_); | |
76 DCHECK(adapter_->IsInitialized()); | |
77 | |
78 adapter_->AddObserver(this); | |
79 } | |
80 | |
81 BluetoothLowEnergyConnection::~BluetoothLowEnergyConnection() { | |
82 Disconnect(); | |
83 if (adapter_) { | |
84 adapter_->RemoveObserver(this); | |
85 adapter_ = NULL; | |
86 } | |
87 } | |
88 | |
89 void BluetoothLowEnergyConnection::Connect() { | |
90 DCHECK(sub_status() == SubStatus::DISCONNECTED); | |
91 | |
92 SetSubStatus(SubStatus::WAITING_GATT_CONNECTION); | |
93 base::TimeDelta throttler_delay = bluetooth_throttler_->GetDelay(); | |
94 PA_LOG(INFO) << "Connecting in " << throttler_delay; | |
95 | |
96 start_time_ = base::TimeTicks::Now(); | |
97 | |
98 // If necessary, wait to create a new GATT connection. | |
99 // | |
100 // Avoid creating a new GATT connection immediately after a given device was | |
101 // disconnected. This is a workaround for crbug.com/508919. | |
102 if (!throttler_delay.is_zero()) { | |
103 task_runner_->PostDelayedTask( | |
104 FROM_HERE, | |
105 base::Bind(&BluetoothLowEnergyConnection::CreateGattConnection, | |
106 weak_ptr_factory_.GetWeakPtr()), | |
107 throttler_delay); | |
108 return; | |
109 } | |
110 | |
111 CreateGattConnection(); | |
112 } | |
113 | |
114 void BluetoothLowEnergyConnection::CreateGattConnection() { | |
115 DCHECK(sub_status() == SubStatus::WAITING_GATT_CONNECTION); | |
116 | |
117 BluetoothDevice* remote_device = GetRemoteDevice(); | |
118 if (remote_device) { | |
119 PA_LOG(INFO) << "Creating GATT connection with " | |
120 << remote_device->GetAddress(); | |
121 | |
122 remote_device->CreateGattConnection( | |
123 base::Bind(&BluetoothLowEnergyConnection::OnGattConnectionCreated, | |
124 weak_ptr_factory_.GetWeakPtr()), | |
125 base::Bind(&BluetoothLowEnergyConnection::OnCreateGattConnectionError, | |
126 weak_ptr_factory_.GetWeakPtr())); | |
127 } | |
128 } | |
129 | |
130 void BluetoothLowEnergyConnection::Disconnect() { | |
131 if (sub_status() != SubStatus::DISCONNECTED) { | |
132 weak_ptr_factory_.InvalidateWeakPtrs(); | |
133 StopNotifySession(); | |
134 characteristic_finder_.reset(); | |
135 if (gatt_connection_) { | |
136 PA_LOG(INFO) << "Disconnect from device " | |
137 << gatt_connection_->GetDeviceAddress(); | |
138 | |
139 // Destroying BluetoothGattConnection also disconnects it. | |
140 gatt_connection_.reset(); | |
141 } | |
142 | |
143 // Only transition to the DISCONNECTED state after perfoming all necessary | |
144 // operations. Otherwise, it'll trigger observers that can pontentially | |
145 // destroy the current instance (causing a crash). | |
146 SetSubStatus(SubStatus::DISCONNECTED); | |
147 } | |
148 } | |
149 | |
150 void BluetoothLowEnergyConnection::SetSubStatus(SubStatus new_sub_status) { | |
151 sub_status_ = new_sub_status; | |
152 | |
153 // Sets the status of parent class cryptauth::Connection accordingly. | |
154 if (new_sub_status == SubStatus::CONNECTED) { | |
155 SetStatus(CONNECTED); | |
156 } else if (new_sub_status == SubStatus::DISCONNECTED) { | |
157 SetStatus(DISCONNECTED); | |
158 } else { | |
159 SetStatus(IN_PROGRESS); | |
160 } | |
161 } | |
162 | |
163 void BluetoothLowEnergyConnection::SetTaskRunnerForTesting( | |
164 scoped_refptr<base::TaskRunner> task_runner) { | |
165 task_runner_ = task_runner; | |
166 } | |
167 | |
168 void BluetoothLowEnergyConnection::SendMessageImpl( | |
169 std::unique_ptr<cryptauth::WireMessage> message) { | |
170 PA_LOG(INFO) << "Sending message " << message->Serialize(); | |
171 std::string serialized_msg = message->Serialize(); | |
172 | |
173 // [First write]: Build a header with the [send signal] + [size of the | |
174 // message]. | |
175 WriteRequest write_request = BuildWriteRequest( | |
176 ToByteVector(static_cast<uint32_t>(ControlSignal::kSendSignal)), | |
177 ToByteVector(static_cast<uint32_t>(serialized_msg.size())), false); | |
178 | |
179 // [First write]: Fill the it with a prefix of |serialized_msg| up to | |
180 // |max_chunk_size_|. | |
181 size_t first_chunk_size = std::min( | |
182 max_chunk_size_ - write_request.value.size(), serialized_msg.size()); | |
183 std::vector<uint8_t> bytes(serialized_msg.begin(), | |
184 serialized_msg.begin() + first_chunk_size); | |
185 write_request.value.insert(write_request.value.end(), bytes.begin(), | |
186 bytes.end()); | |
187 | |
188 bool is_last_write_request = first_chunk_size == serialized_msg.size(); | |
189 write_request.is_last_write_for_wire_message = is_last_write_request; | |
190 WriteRemoteCharacteristic(write_request); | |
191 if (is_last_write_request) | |
192 return; | |
193 | |
194 // [Other write requests]: Each chunk has to include a deprecated signal: | |
195 // |kFirstByteZero| as the first byte. | |
196 int chunk_size = max_chunk_size_ - 1; | |
197 std::vector<uint8_t> kFirstByteZeroVector; | |
198 kFirstByteZeroVector.push_back(static_cast<uint8_t>(kFirstByteZero)); | |
199 | |
200 int message_size = static_cast<int>(serialized_msg.size()); | |
201 int start_index = first_chunk_size; | |
202 while (start_index < message_size) { | |
203 int end_index = (start_index + chunk_size) <= message_size | |
204 ? (start_index + chunk_size) | |
205 : message_size; | |
206 bool is_last_write_request = (end_index == message_size); | |
207 write_request = BuildWriteRequest( | |
208 kFirstByteZeroVector, | |
209 std::vector<uint8_t>(serialized_msg.begin() + start_index, | |
210 serialized_msg.begin() + end_index), | |
211 is_last_write_request); | |
212 WriteRemoteCharacteristic(write_request); | |
213 start_index = end_index; | |
214 } | |
215 } | |
216 | |
217 // Changes in the GATT connection with the remote device should be observed | |
218 // here. If the GATT connection is dropped, we should call Disconnect() anyway, | |
219 // so the object can notify its observers. | |
220 void BluetoothLowEnergyConnection::DeviceChanged(BluetoothAdapter* adapter, | |
221 BluetoothDevice* device) { | |
222 DCHECK(device); | |
223 if (sub_status() == SubStatus::DISCONNECTED || | |
224 device->GetAddress() != GetDeviceAddress()) | |
225 return; | |
226 | |
227 if (sub_status() != SubStatus::WAITING_GATT_CONNECTION && | |
228 !device->IsConnected()) { | |
229 PA_LOG(INFO) << "GATT connection dropped " << GetDeviceAddress() | |
230 << "\ndevice connected: " << device->IsConnected() | |
231 << "\ngatt connection: " | |
232 << (gatt_connection_ ? gatt_connection_->IsConnected() | |
233 : false); | |
234 Disconnect(); | |
235 } | |
236 } | |
237 | |
238 void BluetoothLowEnergyConnection::DeviceRemoved(BluetoothAdapter* adapter, | |
239 BluetoothDevice* device) { | |
240 DCHECK(device); | |
241 if (sub_status_ == SubStatus::DISCONNECTED || | |
242 device->GetAddress() != GetDeviceAddress()) | |
243 return; | |
244 | |
245 PA_LOG(INFO) << "Device removed " << GetDeviceAddress(); | |
246 Disconnect(); | |
247 } | |
248 | |
249 void BluetoothLowEnergyConnection::GattCharacteristicValueChanged( | |
250 BluetoothAdapter* adapter, | |
251 BluetoothRemoteGattCharacteristic* characteristic, | |
252 const std::vector<uint8_t>& value) { | |
253 DCHECK_EQ(adapter, adapter_.get()); | |
254 if (sub_status() != SubStatus::WAITING_RESPONSE_SIGNAL && | |
255 sub_status() != SubStatus::CONNECTED) | |
256 return; | |
257 | |
258 PA_LOG(INFO) << "Characteristic value changed: " | |
259 << characteristic->GetUUID().canonical_value(); | |
260 | |
261 if (characteristic->GetIdentifier() == from_peripheral_char_.id) { | |
262 if (receiving_bytes_) { | |
263 // Ignoring the first byte, as it contains a deprecated signal. | |
264 const std::string bytes(value.begin() + 1, value.end()); | |
265 incoming_bytes_buffer_.append(bytes); | |
266 if (incoming_bytes_buffer_.size() >= expected_number_of_incoming_bytes_) { | |
267 OnBytesReceived(incoming_bytes_buffer_); | |
268 receiving_bytes_ = false; | |
269 } | |
270 return; | |
271 } | |
272 | |
273 if (value.size() < 4) { | |
274 PA_LOG(WARNING) << "Incoming data corrupted, no signal found."; | |
275 return; | |
276 } | |
277 | |
278 const ControlSignal signal = static_cast<ControlSignal>(ToUint32(value)); | |
279 switch (signal) { | |
280 case ControlSignal::kInvitationResponseSignal: | |
281 if (sub_status() == SubStatus::WAITING_RESPONSE_SIGNAL) | |
282 CompleteConnection(); | |
283 break; | |
284 case ControlSignal::kInviteToConnectSignal: | |
285 break; | |
286 case ControlSignal::kSendSignal: { | |
287 if (value.size() < 8) { | |
288 PA_LOG(WARNING) | |
289 << "Incoming data corrupted, expected message size not found."; | |
290 return; | |
291 } | |
292 std::vector<uint8_t> size(value.begin() + 4, value.begin() + 8); | |
293 expected_number_of_incoming_bytes_ = | |
294 static_cast<size_t>(ToUint32(size)); | |
295 receiving_bytes_ = true; | |
296 incoming_bytes_buffer_.clear(); | |
297 | |
298 const std::string bytes(value.begin() + 8, value.end()); | |
299 incoming_bytes_buffer_.append(bytes); | |
300 if (incoming_bytes_buffer_.size() >= | |
301 expected_number_of_incoming_bytes_) { | |
302 OnBytesReceived(incoming_bytes_buffer_); | |
303 receiving_bytes_ = false; | |
304 } | |
305 break; | |
306 } | |
307 case ControlSignal::kDisconnectSignal: | |
308 PA_LOG(INFO) << "Disconnect signal received."; | |
309 Disconnect(); | |
310 break; | |
311 } | |
312 } | |
313 } | |
314 | |
315 BluetoothLowEnergyConnection::WriteRequest::WriteRequest( | |
316 const std::vector<uint8_t>& val, | |
317 bool flag) | |
318 : value(val), | |
319 is_last_write_for_wire_message(flag), | |
320 number_of_failed_attempts(0) {} | |
321 | |
322 BluetoothLowEnergyConnection::WriteRequest::WriteRequest( | |
323 const WriteRequest& other) = default; | |
324 | |
325 BluetoothLowEnergyConnection::WriteRequest::~WriteRequest() {} | |
326 | |
327 void BluetoothLowEnergyConnection::CompleteConnection() { | |
328 PA_LOG(INFO) << "Connection completed. Time elapsed: " | |
329 << base::TimeTicks::Now() - start_time_; | |
330 SetSubStatus(SubStatus::CONNECTED); | |
331 } | |
332 | |
333 void BluetoothLowEnergyConnection::OnCreateGattConnectionError( | |
334 device::BluetoothDevice::ConnectErrorCode error_code) { | |
335 DCHECK(sub_status_ == SubStatus::WAITING_GATT_CONNECTION); | |
336 PA_LOG(WARNING) << "Error creating GATT connection to " | |
337 << remote_device().bluetooth_address | |
338 << "error code: " << error_code; | |
339 Disconnect(); | |
340 } | |
341 | |
342 void BluetoothLowEnergyConnection::OnGattConnectionCreated( | |
343 std::unique_ptr<device::BluetoothGattConnection> gatt_connection) { | |
344 DCHECK(sub_status() == SubStatus::WAITING_GATT_CONNECTION); | |
345 PA_LOG(INFO) << "GATT connection with " << gatt_connection->GetDeviceAddress() | |
346 << " created."; | |
347 PrintTimeElapsed(); | |
348 | |
349 // Informing |bluetooth_trottler_| a new connection was established. | |
350 bluetooth_throttler_->OnConnection(this); | |
351 | |
352 gatt_connection_ = std::move(gatt_connection); | |
353 SetSubStatus(SubStatus::WAITING_CHARACTERISTICS); | |
354 characteristic_finder_.reset(CreateCharacteristicsFinder( | |
355 base::Bind(&BluetoothLowEnergyConnection::OnCharacteristicsFound, | |
356 weak_ptr_factory_.GetWeakPtr()), | |
357 base::Bind(&BluetoothLowEnergyConnection::OnCharacteristicsFinderError, | |
358 weak_ptr_factory_.GetWeakPtr()))); | |
359 } | |
360 | |
361 cryptauth::BluetoothLowEnergyCharacteristicsFinder* | |
362 BluetoothLowEnergyConnection::CreateCharacteristicsFinder( | |
363 const cryptauth::BluetoothLowEnergyCharacteristicsFinder::SuccessCallback& | |
364 success_callback, | |
365 const cryptauth::BluetoothLowEnergyCharacteristicsFinder::ErrorCallback& | |
366 error_callback) { | |
367 return new cryptauth::BluetoothLowEnergyCharacteristicsFinder( | |
368 adapter_, GetRemoteDevice(), remote_service_, to_peripheral_char_, | |
369 from_peripheral_char_, success_callback, error_callback); | |
370 } | |
371 | |
372 void BluetoothLowEnergyConnection::OnCharacteristicsFound( | |
373 const cryptauth::RemoteAttribute& service, | |
374 const cryptauth::RemoteAttribute& to_peripheral_char, | |
375 const cryptauth::RemoteAttribute& from_peripheral_char) { | |
376 PA_LOG(INFO) << "Remote chacteristics found."; | |
377 PrintTimeElapsed(); | |
378 | |
379 DCHECK(sub_status() == SubStatus::WAITING_CHARACTERISTICS); | |
380 remote_service_ = service; | |
381 to_peripheral_char_ = to_peripheral_char; | |
382 from_peripheral_char_ = from_peripheral_char; | |
383 | |
384 SetSubStatus(SubStatus::CHARACTERISTICS_FOUND); | |
385 StartNotifySession(); | |
386 } | |
387 | |
388 void BluetoothLowEnergyConnection::OnCharacteristicsFinderError( | |
389 const cryptauth::RemoteAttribute& to_peripheral_char, | |
390 const cryptauth::RemoteAttribute& from_peripheral_char) { | |
391 DCHECK(sub_status() == SubStatus::WAITING_CHARACTERISTICS); | |
392 PA_LOG(WARNING) << "Connection error, missing characteristics for SmartLock " | |
393 "service.\n" | |
394 << (to_peripheral_char.id.empty() | |
395 ? to_peripheral_char.uuid.canonical_value() | |
396 : "") | |
397 << (from_peripheral_char.id.empty() | |
398 ? ", " + from_peripheral_char.uuid.canonical_value() | |
399 : "") << " not found."; | |
400 | |
401 Disconnect(); | |
402 } | |
403 | |
404 void BluetoothLowEnergyConnection::StartNotifySession() { | |
405 if (sub_status() == SubStatus::CHARACTERISTICS_FOUND) { | |
406 BluetoothRemoteGattCharacteristic* characteristic = | |
407 GetGattCharacteristic(from_peripheral_char_.id); | |
408 DCHECK(characteristic); | |
409 | |
410 // This is a workaround for crbug.com/507325. If |characteristic| is already | |
411 // notifying |characteristic->StartNotifySession()| will fail with | |
412 // GATT_ERROR_FAILED. | |
413 if (characteristic->IsNotifying()) { | |
414 PA_LOG(INFO) << characteristic->GetUUID().canonical_value() | |
415 << " already notifying."; | |
416 SetSubStatus(SubStatus::NOTIFY_SESSION_READY); | |
417 SendInviteToConnectSignal(); | |
418 return; | |
419 } | |
420 | |
421 SetSubStatus(SubStatus::WAITING_NOTIFY_SESSION); | |
422 characteristic->StartNotifySession( | |
423 base::Bind(&BluetoothLowEnergyConnection::OnNotifySessionStarted, | |
424 weak_ptr_factory_.GetWeakPtr()), | |
425 base::Bind(&BluetoothLowEnergyConnection::OnNotifySessionError, | |
426 weak_ptr_factory_.GetWeakPtr())); | |
427 } | |
428 } | |
429 | |
430 void BluetoothLowEnergyConnection::OnNotifySessionError( | |
431 BluetoothRemoteGattService::GattErrorCode error) { | |
432 DCHECK(sub_status() == SubStatus::WAITING_NOTIFY_SESSION); | |
433 PA_LOG(WARNING) << "Error starting notification session: " << error; | |
434 Disconnect(); | |
435 } | |
436 | |
437 void BluetoothLowEnergyConnection::OnNotifySessionStarted( | |
438 std::unique_ptr<BluetoothGattNotifySession> notify_session) { | |
439 DCHECK(sub_status() == SubStatus::WAITING_NOTIFY_SESSION); | |
440 PA_LOG(INFO) << "Notification session started " | |
441 << notify_session->GetCharacteristicIdentifier(); | |
442 PrintTimeElapsed(); | |
443 | |
444 SetSubStatus(SubStatus::NOTIFY_SESSION_READY); | |
445 notify_session_ = std::move(notify_session); | |
446 | |
447 SendInviteToConnectSignal(); | |
448 } | |
449 | |
450 void BluetoothLowEnergyConnection::StopNotifySession() { | |
451 if (notify_session_) { | |
452 notify_session_->Stop(base::Bind(&base::DoNothing)); | |
453 notify_session_.reset(); | |
454 } | |
455 } | |
456 | |
457 void BluetoothLowEnergyConnection::SendInviteToConnectSignal() { | |
458 if (sub_status() == SubStatus::NOTIFY_SESSION_READY) { | |
459 PA_LOG(INFO) << "Sending invite to connect signal"; | |
460 SetSubStatus(SubStatus::WAITING_RESPONSE_SIGNAL); | |
461 | |
462 WriteRequest write_request = BuildWriteRequest( | |
463 ToByteVector( | |
464 static_cast<uint32_t>(ControlSignal::kInviteToConnectSignal)), | |
465 std::vector<uint8_t>(), false); | |
466 | |
467 WriteRemoteCharacteristic(write_request); | |
468 } | |
469 } | |
470 | |
471 void BluetoothLowEnergyConnection::WriteRemoteCharacteristic( | |
472 WriteRequest request) { | |
473 write_requests_queue_.push(request); | |
474 ProcessNextWriteRequest(); | |
475 } | |
476 | |
477 void BluetoothLowEnergyConnection::ProcessNextWriteRequest() { | |
478 BluetoothRemoteGattCharacteristic* characteristic = | |
479 GetGattCharacteristic(to_peripheral_char_.id); | |
480 if (!write_requests_queue_.empty() && !write_remote_characteristic_pending_ && | |
481 characteristic) { | |
482 write_remote_characteristic_pending_ = true; | |
483 WriteRequest next_request = write_requests_queue_.front(); | |
484 PA_LOG(INFO) << "Writing characteristic..."; | |
485 characteristic->WriteRemoteCharacteristic( | |
486 next_request.value, | |
487 base::Bind(&BluetoothLowEnergyConnection::OnRemoteCharacteristicWritten, | |
488 weak_ptr_factory_.GetWeakPtr(), | |
489 next_request.is_last_write_for_wire_message), | |
490 base::Bind( | |
491 &BluetoothLowEnergyConnection::OnWriteRemoteCharacteristicError, | |
492 weak_ptr_factory_.GetWeakPtr(), | |
493 next_request.is_last_write_for_wire_message)); | |
494 } | |
495 } | |
496 | |
497 void BluetoothLowEnergyConnection::OnRemoteCharacteristicWritten( | |
498 bool run_did_send_message_callback) { | |
499 PA_LOG(INFO) << "Characteristic written."; | |
500 write_remote_characteristic_pending_ = false; | |
501 // TODO(sacomoto): Actually pass the current message to the observer. | |
502 if (run_did_send_message_callback) | |
503 OnDidSendMessage(cryptauth::WireMessage(std::string(), std::string()), | |
504 true); | |
505 | |
506 // Removes the top of queue (already processed) and process the next request. | |
507 DCHECK(!write_requests_queue_.empty()); | |
508 write_requests_queue_.pop(); | |
509 ProcessNextWriteRequest(); | |
510 } | |
511 | |
512 void BluetoothLowEnergyConnection::OnWriteRemoteCharacteristicError( | |
513 bool run_did_send_message_callback, | |
514 BluetoothRemoteGattService::GattErrorCode error) { | |
515 PA_LOG(WARNING) << "Error " << error << " writing characteristic: " | |
516 << to_peripheral_char_.uuid.canonical_value(); | |
517 write_remote_characteristic_pending_ = false; | |
518 // TODO(sacomoto): Actually pass the current message to the observer. | |
519 if (run_did_send_message_callback) | |
520 OnDidSendMessage(cryptauth::WireMessage(std::string(), std::string()), | |
521 false); | |
522 | |
523 // Increases the number of failed attempts and retry. | |
524 DCHECK(!write_requests_queue_.empty()); | |
525 if (++write_requests_queue_.front().number_of_failed_attempts >= | |
526 max_number_of_write_attempts_) { | |
527 Disconnect(); | |
528 return; | |
529 } | |
530 ProcessNextWriteRequest(); | |
531 } | |
532 | |
533 BluetoothLowEnergyConnection::WriteRequest | |
534 BluetoothLowEnergyConnection::BuildWriteRequest( | |
535 const std::vector<uint8_t>& signal, | |
536 const std::vector<uint8_t>& bytes, | |
537 bool is_last_write_for_wire_message) { | |
538 std::vector<uint8_t> value(signal.begin(), signal.end()); | |
539 value.insert(value.end(), bytes.begin(), bytes.end()); | |
540 return WriteRequest(value, is_last_write_for_wire_message); | |
541 } | |
542 | |
543 void BluetoothLowEnergyConnection::PrintTimeElapsed() { | |
544 PA_LOG(INFO) << "Time elapsed: " << base::TimeTicks::Now() - start_time_; | |
545 } | |
546 | |
547 std::string BluetoothLowEnergyConnection::GetDeviceAddress() { | |
548 // When the remote device is connected we should rely on the address given by | |
549 // |gatt_connection_|. As the device address may change if the device is | |
550 // paired. The address in |gatt_connection_| is automatically updated in this | |
551 // case. | |
552 return gatt_connection_ ? gatt_connection_->GetDeviceAddress() | |
553 : remote_device().bluetooth_address; | |
554 } | |
555 | |
556 BluetoothDevice* BluetoothLowEnergyConnection::GetRemoteDevice() { | |
557 // It's not possible to simply use | |
558 // |adapter_->GetDevice(GetDeviceAddress())| to find the device with MAC | |
559 // address |GetDeviceAddress()|. For paired devices, | |
560 // BluetoothAdapter::GetDevice(XXX) searches for the temporary MAC address | |
561 // XXX, whereas |GetDeviceAddress()| is the real MAC address. This is a | |
562 // bug in the way device::BluetoothAdapter is storing the devices (see | |
563 // crbug.com/497841). | |
564 std::vector<BluetoothDevice*> devices = adapter_->GetDevices(); | |
565 for (auto* device : devices) { | |
566 if (device->GetAddress() == GetDeviceAddress()) | |
567 return device; | |
568 } | |
569 | |
570 return nullptr; | |
571 } | |
572 | |
573 BluetoothRemoteGattService* BluetoothLowEnergyConnection::GetRemoteService() { | |
574 BluetoothDevice* remote_device = GetRemoteDevice(); | |
575 if (!remote_device) { | |
576 PA_LOG(WARNING) << "Remote device not found."; | |
577 return NULL; | |
578 } | |
579 if (remote_service_.id.empty()) { | |
580 std::vector<BluetoothRemoteGattService*> services = | |
581 remote_device->GetGattServices(); | |
582 for (const auto* service : services) | |
583 if (service->GetUUID() == remote_service_.uuid) { | |
584 remote_service_.id = service->GetIdentifier(); | |
585 break; | |
586 } | |
587 } | |
588 return remote_device->GetGattService(remote_service_.id); | |
589 } | |
590 | |
591 BluetoothRemoteGattCharacteristic* | |
592 BluetoothLowEnergyConnection::GetGattCharacteristic( | |
593 const std::string& gatt_characteristic) { | |
594 BluetoothRemoteGattService* remote_service = GetRemoteService(); | |
595 if (!remote_service) { | |
596 PA_LOG(WARNING) << "Remote service not found."; | |
597 return NULL; | |
598 } | |
599 return remote_service->GetCharacteristic(gatt_characteristic); | |
600 } | |
601 | |
602 // TODO(sacomoto): make this robust to byte ordering in both sides of the | |
603 // SmartLock BLE socket. | |
604 uint32_t BluetoothLowEnergyConnection::ToUint32( | |
605 const std::vector<uint8_t>& bytes) { | |
606 return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); | |
607 } | |
608 | |
609 // TODO(sacomoto): make this robust to byte ordering in both sides of the | |
610 // SmartLock BLE socket. | |
611 const std::vector<uint8_t> BluetoothLowEnergyConnection::ToByteVector( | |
612 const uint32_t value) { | |
613 std::vector<uint8_t> bytes(4, 0); | |
614 bytes[0] = static_cast<uint8_t>(value); | |
615 bytes[1] = static_cast<uint8_t>(value >> 8); | |
616 bytes[2] = static_cast<uint8_t>(value >> 16); | |
617 bytes[3] = static_cast<uint8_t>(value >> 24); | |
618 return bytes; | |
619 } | |
620 | |
621 } // namespace proximity_auth | |
OLD | NEW |