Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / proximity_auth / ble / bluetooth_low_energy_connection.cc
blob8878585426e84b3919f8b64e260ed5b9b6f94fc9
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"
7 #include "base/bind.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 {
36 namespace {
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
54 // GATT_ERROR_FAILED.
55 const int kDelayAfterGattConnectionMilliseconds = 1000;
57 } // namespace
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)
65 : Connection(device),
66 adapter_(adapter),
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) {
80 DCHECK(adapter_);
81 DCHECK(adapter_->IsInitialized());
83 adapter_->AddObserver(this);
86 BluetoothLowEnergyConnection::~BluetoothLowEnergyConnection() {
87 PA_LOG(INFO) << "Connection destroyed.";
88 Disconnect();
89 if (adapter_) {
90 adapter_->RemoveObserver(this);
91 adapter_ = NULL;
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(
110 FROM_HERE,
111 base::Bind(&BluetoothLowEnergyConnection::CreateGattConnection,
112 weak_ptr_factory_.GetWeakPtr()),
113 throttler_delay);
114 return;
117 CreateGattConnection();
120 void BluetoothLowEnergyConnection::CreateGattConnection() {
121 DCHECK(sub_status() == SubStatus::WAITING_GATT_CONNECTION);
123 BluetoothDevice* remote_device = GetRemoteDevice();
124 if (remote_device) {
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();
139 StopNotifySession();
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);
164 } else {
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
180 // message].
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(),
192 bytes.end());
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)
198 return;
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)
211 : message_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) {
228 DCHECK(device);
229 if (sub_status() == SubStatus::DISCONNECTED ||
230 device->GetAddress() != GetRemoteDeviceAddress())
231 return;
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()
239 : false);
240 Disconnect();
244 void BluetoothLowEnergyConnection::DeviceRemoved(BluetoothAdapter* adapter,
245 BluetoothDevice* device) {
246 DCHECK(device);
247 if (sub_status_ == SubStatus::DISCONNECTED ||
248 device->GetAddress() != GetRemoteDeviceAddress())
249 return;
251 PA_LOG(INFO) << "Device removed " << GetRemoteDeviceAddress();
252 Disconnect();
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)
262 return;
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;
276 return;
279 if (value.size() < 4) {
280 PA_LOG(WARNING) << "Incoming data corrupted, no signal found.";
281 return;
284 const ControlSignal signal = static_cast<ControlSignal>(ToUint32(value));
285 switch (signal) {
286 case ControlSignal::kInvitationResponseSignal:
287 if (sub_status() == SubStatus::WAITING_RESPONSE_SIGNAL)
288 CompleteConnection();
289 break;
290 case ControlSignal::kInviteToConnectSignal:
291 break;
292 case ControlSignal::kSendSignal: {
293 if (value.size() < 8) {
294 PA_LOG(WARNING)
295 << "Incoming data corrupted, expected message size not found.";
296 return;
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;
311 break;
313 case ControlSignal::kDisconnectSignal:
314 PA_LOG(INFO) << "Disconnect signal received.";
315 Disconnect();
316 break;
321 BluetoothLowEnergyConnection::WriteRequest::WriteRequest(
322 const std::vector<uint8>& val,
323 bool flag)
324 : value(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;
344 Disconnect();
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()
351 << " created.";
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&
368 success_callback,
369 const BluetoothLowEnergyCharacteristicsFinder::ErrorCallback&
370 error_callback) {
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 "
394 "service.\n"
395 << (to_peripheral_char.id.empty()
396 ? to_peripheral_char.uuid.canonical_value()
397 : "")
398 << (from_peripheral_char.id.empty()
399 ? ", " + from_peripheral_char.uuid.canonical_value()
400 : "") << " not found.";
402 Disconnect();
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();
419 return;
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;
435 Disconnect();
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(
463 ToByteVector(
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(
471 FROM_HERE,
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_ &&
488 characteristic) {
489 write_remote_characteristic_pending_ = true;
490 WriteRequest next_request = write_requests_queue_.front();
491 PA_LOG(INFO) << "Writing characteristic...";
492 characteristic->WriteRemoteCharacteristic(
493 next_request.value,
494 base::Bind(&BluetoothLowEnergyConnection::OnRemoteCharacteristicWritten,
495 weak_ptr_factory_.GetWeakPtr(),
496 next_request.is_last_write_for_wire_message),
497 base::Bind(
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_) {
532 Disconnect();
533 return;
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())
568 return device;
571 return nullptr;
574 BluetoothGattService* BluetoothLowEnergyConnection::GetRemoteService() {
575 BluetoothDevice* remote_device = GetRemoteDevice();
576 if (!remote_device) {
577 PA_LOG(WARNING) << "Remote device not found.";
578 return NULL;
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();
586 break;
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.";
598 return NULL;
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);
618 return bytes;
621 } // namespace proximity_auth