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.
5 #include "components/proximity_auth/ble/bluetooth_low_energy_connection.h"
8 #include "base/location.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/task_runner.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/time/time.h"
14 #include "components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h"
15 #include "components/proximity_auth/ble/fake_wire_message.h"
16 #include "components/proximity_auth/bluetooth_throttler.h"
17 #include "components/proximity_auth/connection_finder.h"
18 #include "components/proximity_auth/logging/logging.h"
19 #include "components/proximity_auth/wire_message.h"
20 #include "device/bluetooth/bluetooth_adapter.h"
21 #include "device/bluetooth/bluetooth_device.h"
22 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
23 #include "device/bluetooth/bluetooth_gatt_connection.h"
24 #include "device/bluetooth/bluetooth_gatt_notify_session.h"
25 #include "device/bluetooth/bluetooth_uuid.h"
27 using device::BluetoothAdapter
;
28 using device::BluetoothDevice
;
29 using device::BluetoothGattConnection
;
30 using device::BluetoothGattService
;
31 using device::BluetoothGattCharacteristic
;
32 using device::BluetoothGattNotifySession
;
33 using device::BluetoothUUID
;
35 namespace proximity_auth
{
38 // The UUID of the characteristic used to send data to the peripheral.
39 const char kToPeripheralCharUUID
[] = "977c6674-1239-4e72-993b-502369b8bb5a";
41 // The UUID of the characteristic used to receive data from the peripheral.
42 const char kFromPeripheralCharUUID
[] = "f4b904a2-a030-43b3-98a8-221c536c03cb";
44 // Deprecated signal send as the first byte in send byte operations.
45 const int kFirstByteZero
= 0;
47 // The maximum number of bytes written in a remote characteristic with a single
48 // write request. This is not the connection MTU, we are assuming that the
49 // remote device allows for writes larger than MTU.
50 const int kMaxChunkSize
= 500;
52 // This delay is necessary as a workaroud for crbug.com/507325. Reading/writing
53 // characteristics immediatelly after the connection is complete fails with
55 const int kDelayAfterGattConnectionMilliseconds
= 1000;
59 BluetoothLowEnergyConnection::BluetoothLowEnergyConnection(
60 const RemoteDevice
& device
,
61 scoped_refptr
<device::BluetoothAdapter
> adapter
,
62 const BluetoothUUID remote_service_uuid
,
63 BluetoothThrottler
* bluetooth_throttler
,
64 int max_number_of_write_attempts
)
67 remote_service_({remote_service_uuid
, ""}),
68 to_peripheral_char_({BluetoothUUID(kToPeripheralCharUUID
), ""}),
69 from_peripheral_char_({BluetoothUUID(kFromPeripheralCharUUID
), ""}),
70 bluetooth_throttler_(bluetooth_throttler
),
71 task_runner_(base::ThreadTaskRunnerHandle::Get()),
72 sub_status_(SubStatus::DISCONNECTED
),
73 receiving_bytes_(false),
74 write_remote_characteristic_pending_(false),
75 max_number_of_write_attempts_(max_number_of_write_attempts
),
76 max_chunk_size_(kMaxChunkSize
),
77 delay_after_gatt_connection_(base::TimeDelta::FromMilliseconds(
78 kDelayAfterGattConnectionMilliseconds
)),
79 weak_ptr_factory_(this) {
81 DCHECK(adapter_
->IsInitialized());
83 adapter_
->AddObserver(this);
86 BluetoothLowEnergyConnection::~BluetoothLowEnergyConnection() {
87 PA_LOG(INFO
) << "Connection destroyed.";
90 adapter_
->RemoveObserver(this);
95 void BluetoothLowEnergyConnection::Connect() {
96 DCHECK(sub_status() == SubStatus::DISCONNECTED
);
98 SetSubStatus(SubStatus::WAITING_GATT_CONNECTION
);
99 base::TimeDelta throttler_delay
= bluetooth_throttler_
->GetDelay();
100 PA_LOG(INFO
) << "Connecting in " << throttler_delay
;
102 start_time_
= base::TimeTicks::Now();
104 // If necessary, wait to create a new GATT connection.
106 // Avoid creating a new GATT connection immediately after a given device was
107 // disconnected. This is a workaround for crbug.com/508919.
108 if (!throttler_delay
.is_zero()) {
109 task_runner_
->PostDelayedTask(
111 base::Bind(&BluetoothLowEnergyConnection::CreateGattConnection
,
112 weak_ptr_factory_
.GetWeakPtr()),
117 CreateGattConnection();
120 void BluetoothLowEnergyConnection::CreateGattConnection() {
121 DCHECK(sub_status() == SubStatus::WAITING_GATT_CONNECTION
);
123 BluetoothDevice
* remote_device
= GetRemoteDevice();
125 PA_LOG(INFO
) << "Creating GATT connection with "
126 << remote_device
->GetAddress();
128 remote_device
->CreateGattConnection(
129 base::Bind(&BluetoothLowEnergyConnection::OnGattConnectionCreated
,
130 weak_ptr_factory_
.GetWeakPtr()),
131 base::Bind(&BluetoothLowEnergyConnection::OnCreateGattConnectionError
,
132 weak_ptr_factory_
.GetWeakPtr()));
136 void BluetoothLowEnergyConnection::Disconnect() {
137 if (sub_status() != SubStatus::DISCONNECTED
) {
138 ClearWriteRequestsQueue();
140 characteristic_finder_
.reset();
141 if (gatt_connection_
) {
142 PA_LOG(INFO
) << "Disconnect from device "
143 << gatt_connection_
->GetDeviceAddress();
145 // Destroying BluetoothGattConnection also disconnects it.
146 gatt_connection_
.reset();
149 // Only transition to the DISCONNECTED state after perfoming all necessary
150 // operations. Otherwise, it'll trigger observers that can pontentially
151 // destroy the current instance (causing a crash).
152 SetSubStatus(SubStatus::DISCONNECTED
);
156 void BluetoothLowEnergyConnection::SetSubStatus(SubStatus new_sub_status
) {
157 sub_status_
= new_sub_status
;
159 // Sets the status of parent class proximity_auth::Connection accordingly.
160 if (new_sub_status
== SubStatus::CONNECTED
) {
161 SetStatus(CONNECTED
);
162 } else if (new_sub_status
== SubStatus::DISCONNECTED
) {
163 SetStatus(DISCONNECTED
);
165 SetStatus(IN_PROGRESS
);
169 void BluetoothLowEnergyConnection::SetTaskRunnerForTesting(
170 scoped_refptr
<base::TaskRunner
> task_runner
) {
171 task_runner_
= task_runner
;
174 void BluetoothLowEnergyConnection::SendMessageImpl(
175 scoped_ptr
<WireMessage
> message
) {
176 PA_LOG(INFO
) << "Sending message " << message
->Serialize();
177 std::string serialized_msg
= message
->Serialize();
179 // [First write]: Build a header with the [send signal] + [size of the
181 WriteRequest write_request
= BuildWriteRequest(
182 ToByteVector(static_cast<uint32
>(ControlSignal::kSendSignal
)),
183 ToByteVector(static_cast<uint32
>(serialized_msg
.size())), false);
185 // [First write]: Fill the it with a prefix of |serialized_msg| up to
186 // |max_chunk_size_|.
187 size_t first_chunk_size
= std::min(
188 max_chunk_size_
- write_request
.value
.size(), serialized_msg
.size());
189 std::vector
<uint8
> bytes(serialized_msg
.begin(),
190 serialized_msg
.begin() + first_chunk_size
);
191 write_request
.value
.insert(write_request
.value
.end(), bytes
.begin(),
194 bool is_last_write_request
= first_chunk_size
== serialized_msg
.size();
195 write_request
.is_last_write_for_wire_message
= is_last_write_request
;
196 WriteRemoteCharacteristic(write_request
);
197 if (is_last_write_request
)
200 // [Other write requests]: Each chunk has to include a deprecated signal:
201 // |kFirstByteZero| as the first byte.
202 int chunk_size
= max_chunk_size_
- 1;
203 std::vector
<uint8
> kFirstByteZeroVector
;
204 kFirstByteZeroVector
.push_back(static_cast<uint8
>(kFirstByteZero
));
206 int message_size
= static_cast<int>(serialized_msg
.size());
207 int start_index
= first_chunk_size
;
208 while (start_index
< message_size
) {
209 int end_index
= (start_index
+ chunk_size
) <= message_size
210 ? (start_index
+ chunk_size
)
212 bool is_last_write_request
= (end_index
== message_size
);
213 write_request
= BuildWriteRequest(
214 kFirstByteZeroVector
,
215 std::vector
<uint8
>(serialized_msg
.begin() + start_index
,
216 serialized_msg
.begin() + end_index
),
217 is_last_write_request
);
218 WriteRemoteCharacteristic(write_request
);
219 start_index
= end_index
;
223 // Changes in the GATT connection with the remote device should be observed
224 // here. If the GATT connection is dropped, we should call Disconnect() anyway,
225 // so the object can notify its observers.
226 void BluetoothLowEnergyConnection::DeviceChanged(BluetoothAdapter
* adapter
,
227 BluetoothDevice
* device
) {
229 if (sub_status() == SubStatus::DISCONNECTED
||
230 device
->GetAddress() != GetRemoteDeviceAddress())
233 if (sub_status() != SubStatus::WAITING_GATT_CONNECTION
&&
234 !device
->IsConnected()) {
235 PA_LOG(INFO
) << "GATT connection dropped " << GetRemoteDeviceAddress()
236 << "\ndevice connected: " << device
->IsConnected()
237 << "\ngatt connection: "
238 << (gatt_connection_
? gatt_connection_
->IsConnected()
244 void BluetoothLowEnergyConnection::DeviceRemoved(BluetoothAdapter
* adapter
,
245 BluetoothDevice
* device
) {
247 if (sub_status_
== SubStatus::DISCONNECTED
||
248 device
->GetAddress() != GetRemoteDeviceAddress())
251 PA_LOG(INFO
) << "Device removed " << GetRemoteDeviceAddress();
255 void BluetoothLowEnergyConnection::GattCharacteristicValueChanged(
256 BluetoothAdapter
* adapter
,
257 BluetoothGattCharacteristic
* characteristic
,
258 const std::vector
<uint8
>& value
) {
259 DCHECK_EQ(adapter
, adapter_
.get());
260 if (sub_status() != SubStatus::WAITING_RESPONSE_SIGNAL
&&
261 sub_status() != SubStatus::CONNECTED
)
264 PA_LOG(INFO
) << "Characteristic value changed: "
265 << characteristic
->GetUUID().canonical_value();
267 if (characteristic
->GetIdentifier() == from_peripheral_char_
.id
) {
268 if (receiving_bytes_
) {
269 // Ignoring the first byte, as it contains a deprecated signal.
270 const std::string
bytes(value
.begin() + 1, value
.end());
271 incoming_bytes_buffer_
.append(bytes
);
272 if (incoming_bytes_buffer_
.size() >= expected_number_of_incoming_bytes_
) {
273 OnBytesReceived(incoming_bytes_buffer_
);
274 receiving_bytes_
= false;
279 if (value
.size() < 4) {
280 PA_LOG(WARNING
) << "Incoming data corrupted, no signal found.";
284 const ControlSignal signal
= static_cast<ControlSignal
>(ToUint32(value
));
286 case ControlSignal::kInvitationResponseSignal
:
287 if (sub_status() == SubStatus::WAITING_RESPONSE_SIGNAL
)
288 CompleteConnection();
290 case ControlSignal::kInviteToConnectSignal
:
292 case ControlSignal::kSendSignal
: {
293 if (value
.size() < 8) {
295 << "Incoming data corrupted, expected message size not found.";
298 std::vector
<uint8
> size(value
.begin() + 4, value
.begin() + 8);
299 expected_number_of_incoming_bytes_
=
300 static_cast<size_t>(ToUint32(size
));
301 receiving_bytes_
= true;
302 incoming_bytes_buffer_
.clear();
304 const std::string
bytes(value
.begin() + 8, value
.end());
305 incoming_bytes_buffer_
.append(bytes
);
306 if (incoming_bytes_buffer_
.size() >=
307 expected_number_of_incoming_bytes_
) {
308 OnBytesReceived(incoming_bytes_buffer_
);
309 receiving_bytes_
= false;
313 case ControlSignal::kDisconnectSignal
:
314 PA_LOG(INFO
) << "Disconnect signal received.";
321 BluetoothLowEnergyConnection::WriteRequest::WriteRequest(
322 const std::vector
<uint8
>& val
,
325 is_last_write_for_wire_message(flag
),
326 number_of_failed_attempts(0) {
329 BluetoothLowEnergyConnection::WriteRequest::~WriteRequest() {
332 void BluetoothLowEnergyConnection::CompleteConnection() {
333 PA_LOG(INFO
) << "Connection completed. Time elapsed: "
334 << base::TimeTicks::Now() - start_time_
;
335 SetSubStatus(SubStatus::CONNECTED
);
338 void BluetoothLowEnergyConnection::OnCreateGattConnectionError(
339 device::BluetoothDevice::ConnectErrorCode error_code
) {
340 DCHECK(sub_status_
== SubStatus::WAITING_GATT_CONNECTION
);
341 PA_LOG(WARNING
) << "Error creating GATT connection to "
342 << remote_device().bluetooth_address
343 << "error code: " << error_code
;
347 void BluetoothLowEnergyConnection::OnGattConnectionCreated(
348 scoped_ptr
<device::BluetoothGattConnection
> gatt_connection
) {
349 DCHECK(sub_status() == SubStatus::WAITING_GATT_CONNECTION
);
350 PA_LOG(INFO
) << "GATT connection with " << gatt_connection
->GetDeviceAddress()
353 gatt_connection_
= gatt_connection
.Pass();
354 SetSubStatus(SubStatus::WAITING_CHARACTERISTICS
);
355 characteristic_finder_
.reset(CreateCharacteristicsFinder(
356 base::Bind(&BluetoothLowEnergyConnection::OnCharacteristicsFound
,
357 weak_ptr_factory_
.GetWeakPtr()),
358 base::Bind(&BluetoothLowEnergyConnection::OnCharacteristicsFinderError
,
359 weak_ptr_factory_
.GetWeakPtr())));
361 // Informing |bluetooth_trottler_| a new connection was established.
362 bluetooth_throttler_
->OnConnection(this);
365 BluetoothLowEnergyCharacteristicsFinder
*
366 BluetoothLowEnergyConnection::CreateCharacteristicsFinder(
367 const BluetoothLowEnergyCharacteristicsFinder::SuccessCallback
&
369 const BluetoothLowEnergyCharacteristicsFinder::ErrorCallback
&
371 return new BluetoothLowEnergyCharacteristicsFinder(
372 adapter_
, GetRemoteDevice(), remote_service_
, to_peripheral_char_
,
373 from_peripheral_char_
, success_callback
, error_callback
);
376 void BluetoothLowEnergyConnection::OnCharacteristicsFound(
377 const RemoteAttribute
& service
,
378 const RemoteAttribute
& to_peripheral_char
,
379 const RemoteAttribute
& from_peripheral_char
) {
380 DCHECK(sub_status() == SubStatus::WAITING_CHARACTERISTICS
);
381 remote_service_
= service
;
382 to_peripheral_char_
= to_peripheral_char
;
383 from_peripheral_char_
= from_peripheral_char
;
385 SetSubStatus(SubStatus::CHARACTERISTICS_FOUND
);
386 StartNotifySession();
389 void BluetoothLowEnergyConnection::OnCharacteristicsFinderError(
390 const RemoteAttribute
& to_peripheral_char
,
391 const RemoteAttribute
& from_peripheral_char
) {
392 DCHECK(sub_status() == SubStatus::WAITING_CHARACTERISTICS
);
393 PA_LOG(WARNING
) << "Connection error, missing characteristics for SmartLock "
395 << (to_peripheral_char
.id
.empty()
396 ? to_peripheral_char
.uuid
.canonical_value()
398 << (from_peripheral_char
.id
.empty()
399 ? ", " + from_peripheral_char
.uuid
.canonical_value()
400 : "") << " not found.";
405 void BluetoothLowEnergyConnection::StartNotifySession() {
406 if (sub_status() == SubStatus::CHARACTERISTICS_FOUND
) {
407 BluetoothGattCharacteristic
* characteristic
=
408 GetGattCharacteristic(from_peripheral_char_
.id
);
409 DCHECK(characteristic
);
411 // This is a workaround for crbug.com/507325. If |characteristic| is already
412 // notifying |characteristic->StartNotifySession()| will fail with
413 // GATT_ERROR_FAILED.
414 if (characteristic
->IsNotifying()) {
415 PA_LOG(INFO
) << characteristic
->GetUUID().canonical_value()
416 << " already notifying.";
417 SetSubStatus(SubStatus::NOTIFY_SESSION_READY
);
418 SendInviteToConnectSignal();
422 SetSubStatus(SubStatus::WAITING_NOTIFY_SESSION
);
423 characteristic
->StartNotifySession(
424 base::Bind(&BluetoothLowEnergyConnection::OnNotifySessionStarted
,
425 weak_ptr_factory_
.GetWeakPtr()),
426 base::Bind(&BluetoothLowEnergyConnection::OnNotifySessionError
,
427 weak_ptr_factory_
.GetWeakPtr()));
431 void BluetoothLowEnergyConnection::OnNotifySessionError(
432 BluetoothGattService::GattErrorCode error
) {
433 DCHECK(sub_status() == SubStatus::WAITING_NOTIFY_SESSION
);
434 PA_LOG(WARNING
) << "Error starting notification session: " << error
;
438 void BluetoothLowEnergyConnection::OnNotifySessionStarted(
439 scoped_ptr
<BluetoothGattNotifySession
> notify_session
) {
440 DCHECK(sub_status() == SubStatus::WAITING_NOTIFY_SESSION
);
441 PA_LOG(INFO
) << "Notification session started "
442 << notify_session
->GetCharacteristicIdentifier();
444 SetSubStatus(SubStatus::NOTIFY_SESSION_READY
);
445 notify_session_
= notify_session
.Pass();
447 SendInviteToConnectSignal();
450 void BluetoothLowEnergyConnection::StopNotifySession() {
451 if (notify_session_
) {
452 notify_session_
->Stop(base::Bind(&base::DoNothing
));
453 notify_session_
.reset();
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
);
462 WriteRequest write_request
= BuildWriteRequest(
464 static_cast<uint32
>(ControlSignal::kInviteToConnectSignal
)),
465 std::vector
<uint8
>(), false);
467 // This is a workaround for crbug.com/498850. Currently, trying to
468 // write/read characteristics immediatelly after the GATT connection was
469 // established fails with GATT_ERROR_FAILED.
470 task_runner_
->PostDelayedTask(
472 base::Bind(&BluetoothLowEnergyConnection::WriteRemoteCharacteristic
,
473 weak_ptr_factory_
.GetWeakPtr(), write_request
),
474 delay_after_gatt_connection_
);
478 void BluetoothLowEnergyConnection::WriteRemoteCharacteristic(
479 WriteRequest request
) {
480 write_requests_queue_
.push(request
);
481 ProcessNextWriteRequest();
484 void BluetoothLowEnergyConnection::ProcessNextWriteRequest() {
485 BluetoothGattCharacteristic
* characteristic
=
486 GetGattCharacteristic(to_peripheral_char_
.id
);
487 if (!write_requests_queue_
.empty() && !write_remote_characteristic_pending_
&&
489 write_remote_characteristic_pending_
= true;
490 WriteRequest next_request
= write_requests_queue_
.front();
491 PA_LOG(INFO
) << "Writing characteristic...";
492 characteristic
->WriteRemoteCharacteristic(
494 base::Bind(&BluetoothLowEnergyConnection::OnRemoteCharacteristicWritten
,
495 weak_ptr_factory_
.GetWeakPtr(),
496 next_request
.is_last_write_for_wire_message
),
498 &BluetoothLowEnergyConnection::OnWriteRemoteCharacteristicError
,
499 weak_ptr_factory_
.GetWeakPtr(),
500 next_request
.is_last_write_for_wire_message
));
504 void BluetoothLowEnergyConnection::OnRemoteCharacteristicWritten(
505 bool run_did_send_message_callback
) {
506 PA_LOG(INFO
) << "Characteristic written.";
507 write_remote_characteristic_pending_
= false;
508 // TODO(sacomoto): Actually pass the current message to the observer.
509 if (run_did_send_message_callback
)
510 OnDidSendMessage(WireMessage(std::string(), std::string()), true);
512 // Removes the top of queue (already processed) and process the next request.
513 DCHECK(!write_requests_queue_
.empty());
514 write_requests_queue_
.pop();
515 ProcessNextWriteRequest();
518 void BluetoothLowEnergyConnection::OnWriteRemoteCharacteristicError(
519 bool run_did_send_message_callback
,
520 BluetoothGattService::GattErrorCode error
) {
521 PA_LOG(WARNING
) << "Error " << error
<< " writing characteristic: "
522 << to_peripheral_char_
.uuid
.canonical_value();
523 write_remote_characteristic_pending_
= false;
524 // TODO(sacomoto): Actually pass the current message to the observer.
525 if (run_did_send_message_callback
)
526 OnDidSendMessage(WireMessage(std::string(), std::string()), false);
528 // Increases the number of failed attempts and retry.
529 DCHECK(!write_requests_queue_
.empty());
530 if (++write_requests_queue_
.front().number_of_failed_attempts
>=
531 max_number_of_write_attempts_
) {
535 ProcessNextWriteRequest();
538 BluetoothLowEnergyConnection::WriteRequest
539 BluetoothLowEnergyConnection::BuildWriteRequest(
540 const std::vector
<uint8
>& signal
,
541 const std::vector
<uint8
>& bytes
,
542 bool is_last_write_for_wire_message
) {
543 std::vector
<uint8
> value(signal
.begin(), signal
.end());
544 value
.insert(value
.end(), bytes
.begin(), bytes
.end());
545 return WriteRequest(value
, is_last_write_for_wire_message
);
548 void BluetoothLowEnergyConnection::ClearWriteRequestsQueue() {
549 while (!write_requests_queue_
.empty())
550 write_requests_queue_
.pop();
553 const std::string
& BluetoothLowEnergyConnection::GetRemoteDeviceAddress() {
554 return remote_device().bluetooth_address
;
557 BluetoothDevice
* BluetoothLowEnergyConnection::GetRemoteDevice() {
558 // It's not possible to simply use
559 // |adapter_->GetDevice(GetRemoteDeviceAddress())| to find the device with MAC
560 // address |GetRemoteDeviceAddress()|. For paired devices,
561 // BluetoothAdapter::GetDevice(XXX) searches for the temporary MAC address
562 // XXX, whereas |GetRemoteDeviceAddress()| is the real MAC address. This is a
563 // bug in the way device::BluetoothAdapter is storing the devices (see
564 // crbug.com/497841).
565 std::vector
<BluetoothDevice
*> devices
= adapter_
->GetDevices();
566 for (const auto& device
: devices
) {
567 if (device
->GetAddress() == GetRemoteDeviceAddress())
574 BluetoothGattService
* BluetoothLowEnergyConnection::GetRemoteService() {
575 BluetoothDevice
* remote_device
= GetRemoteDevice();
576 if (!remote_device
) {
577 PA_LOG(WARNING
) << "Remote device not found.";
580 if (remote_service_
.id
.empty()) {
581 std::vector
<BluetoothGattService
*> services
=
582 remote_device
->GetGattServices();
583 for (const auto& service
: services
)
584 if (service
->GetUUID() == remote_service_
.uuid
) {
585 remote_service_
.id
= service
->GetIdentifier();
589 return remote_device
->GetGattService(remote_service_
.id
);
592 BluetoothGattCharacteristic
*
593 BluetoothLowEnergyConnection::GetGattCharacteristic(
594 const std::string
& gatt_characteristic
) {
595 BluetoothGattService
* remote_service
= GetRemoteService();
596 if (!remote_service
) {
597 PA_LOG(WARNING
) << "Remote service not found.";
600 return remote_service
->GetCharacteristic(gatt_characteristic
);
603 // TODO(sacomoto): make this robust to byte ordering in both sides of the
604 // SmartLock BLE socket.
605 uint32
BluetoothLowEnergyConnection::ToUint32(const std::vector
<uint8
>& bytes
) {
606 return bytes
[0] | (bytes
[1] << 8) | (bytes
[2] << 16) | (bytes
[3] << 24);
609 // TODO(sacomoto): make this robust to byte ordering in both sides of the
610 // SmartLock BLE socket.
611 const std::vector
<uint8
> BluetoothLowEnergyConnection::ToByteVector(
612 const uint32 value
) {
613 std::vector
<uint8
> bytes(4, 0);
614 bytes
[0] = static_cast<uint8
>(value
);
615 bytes
[1] = static_cast<uint8
>(value
>> 8);
616 bytes
[2] = static_cast<uint8
>(value
>> 16);
617 bytes
[3] = static_cast<uint8
>(value
>> 24);
621 } // namespace proximity_auth