1 // Copyright 2016 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 "chromeos/services/secure_channel/ble_weave_client_connection.h"
6
7 #include <memory>
8 #include <sstream>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/callback_helpers.h"
13 #include "base/location.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/stl_util.h"
16 #include "base/task_runner.h"
17 #include "base/threading/thread_task_runner_handle.h"
18 #include "base/timer/timer.h"
19 #include "chromeos/components/multidevice/logging/logging.h"
20 #include "chromeos/services/secure_channel/background_eid_generator.h"
21 #include "chromeos/services/secure_channel/wire_message.h"
22 #include "device/bluetooth/bluetooth_gatt_connection.h"
23
24 namespace chromeos {
25
26 namespace secure_channel {
27
28 namespace weave {
29
30 namespace {
31
32 typedef BluetoothLowEnergyWeavePacketReceiver::State ReceiverState;
33
34 // The UUID of the TX characteristic used to transmit data to the server.
35 const char kTXCharacteristicUUID[] = "00000100-0004-1000-8000-001A11000101";
36
37 // The UUID of the RX characteristic used to receive data from the server.
38 const char kRXCharacteristicUUID[] = "00000100-0004-1000-8000-001A11000102";
39
40 // If sending a message fails, retry up to 2 additional times. This means that
41 // each message gets 3 attempts: the first one, and 2 retries.
42 const int kMaxNumberOfRetryAttempts = 2;
43
44 // Timeouts for various status types.
45 const int kConnectionLatencyTimeoutSeconds = 2;
46 const int kGattConnectionTimeoutSeconds = 15;
47 const int kGattCharacteristicsTimeoutSeconds = 10;
48 const int kNotifySessionTimeoutSeconds = 5;
49 const int kConnectionResponseTimeoutSeconds = 2;
50 const int kSendingMessageTimeoutSeconds = 5;
51
52 } // namespace
53
54 // static
55 BluetoothLowEnergyWeaveClientConnection::Factory*
56 BluetoothLowEnergyWeaveClientConnection::Factory::factory_instance_ =
57 nullptr;
58
59 // static
60 std::unique_ptr<Connection>
Create(multidevice::RemoteDeviceRef remote_device,scoped_refptr<device::BluetoothAdapter> adapter,const device::BluetoothUUID remote_service_uuid,const std::string & device_address,bool should_set_low_connection_latency)61 BluetoothLowEnergyWeaveClientConnection::Factory::Create(
62 multidevice::RemoteDeviceRef remote_device,
63 scoped_refptr<device::BluetoothAdapter> adapter,
64 const device::BluetoothUUID remote_service_uuid,
65 const std::string& device_address,
66 bool should_set_low_connection_latency) {
67 if (factory_instance_) {
68 return factory_instance_->CreateInstance(
69 remote_device, adapter, remote_service_uuid, device_address,
70 should_set_low_connection_latency);
71 }
72
73 return std::make_unique<BluetoothLowEnergyWeaveClientConnection>(
74 remote_device, adapter, remote_service_uuid, device_address,
75 should_set_low_connection_latency);
76 }
77
78 // static
SetFactoryForTesting(Factory * factory)79 void BluetoothLowEnergyWeaveClientConnection::Factory::SetFactoryForTesting(
80 Factory* factory) {
81 factory_instance_ = factory;
82 }
83
84 // static
GetTimeoutForSubStatus(SubStatus sub_status)85 base::TimeDelta BluetoothLowEnergyWeaveClientConnection::GetTimeoutForSubStatus(
86 SubStatus sub_status) {
87 switch (sub_status) {
88 case SubStatus::WAITING_CONNECTION_RESPONSE:
89 return base::TimeDelta::FromSeconds(kConnectionResponseTimeoutSeconds);
90 case SubStatus::WAITING_CONNECTION_LATENCY:
91 return base::TimeDelta::FromSeconds(kConnectionLatencyTimeoutSeconds);
92 case SubStatus::WAITING_GATT_CONNECTION:
93 return base::TimeDelta::FromSeconds(kGattConnectionTimeoutSeconds);
94 case SubStatus::WAITING_CHARACTERISTICS:
95 return base::TimeDelta::FromSeconds(kGattCharacteristicsTimeoutSeconds);
96 case SubStatus::WAITING_NOTIFY_SESSION:
97 return base::TimeDelta::FromSeconds(kNotifySessionTimeoutSeconds);
98 case SubStatus::CONNECTED_AND_SENDING_MESSAGE:
99 return base::TimeDelta::FromSeconds(kSendingMessageTimeoutSeconds);
100 default:
101 // Max signifies that there should be no timeout.
102 return base::TimeDelta::Max();
103 }
104 }
105
106 // static
SubStatusToString(SubStatus sub_status)107 std::string BluetoothLowEnergyWeaveClientConnection::SubStatusToString(
108 SubStatus sub_status) {
109 switch (sub_status) {
110 case SubStatus::DISCONNECTED:
111 return "[disconnected]";
112 case SubStatus::WAITING_CONNECTION_LATENCY:
113 return "[waiting to set connection latency]";
114 case SubStatus::WAITING_GATT_CONNECTION:
115 return "[waiting for GATT connection to be created]";
116 case SubStatus::WAITING_CHARACTERISTICS:
117 return "[waiting for GATT characteristics to be found]";
118 case SubStatus::CHARACTERISTICS_FOUND:
119 return "[GATT characteristics have been found]";
120 case SubStatus::WAITING_NOTIFY_SESSION:
121 return "[waiting for notify session to begin]";
122 case SubStatus::NOTIFY_SESSION_READY:
123 return "[notify session is ready]";
124 case SubStatus::WAITING_CONNECTION_RESPONSE:
125 return "[waiting for \"connection response\" uWeave packet]";
126 case SubStatus::CONNECTED_AND_IDLE:
127 return "[connected and idle]";
128 case SubStatus::CONNECTED_AND_SENDING_MESSAGE:
129 return "[connected and sending message]";
130 default:
131 return "[invalid state]";
132 }
133 }
134
135 BluetoothLowEnergyWeaveClientConnection::
BluetoothLowEnergyWeaveClientConnection(multidevice::RemoteDeviceRef device,scoped_refptr<device::BluetoothAdapter> adapter,const device::BluetoothUUID remote_service_uuid,const std::string & device_address,bool should_set_low_connection_latency)136 BluetoothLowEnergyWeaveClientConnection(
137 multidevice::RemoteDeviceRef device,
138 scoped_refptr<device::BluetoothAdapter> adapter,
139 const device::BluetoothUUID remote_service_uuid,
140 const std::string& device_address,
141 bool should_set_low_connection_latency)
142 : Connection(device),
143 initial_device_address_(device_address),
144 should_set_low_connection_latency_(should_set_low_connection_latency),
145 adapter_(adapter),
146 remote_service_({remote_service_uuid, std::string()}),
147 packet_generator_(
148 std::make_unique<BluetoothLowEnergyWeavePacketGenerator>()),
149 packet_receiver_(std::make_unique<BluetoothLowEnergyWeavePacketReceiver>(
150 BluetoothLowEnergyWeavePacketReceiver::ReceiverType::CLIENT)),
151 tx_characteristic_(
152 {device::BluetoothUUID(kTXCharacteristicUUID), std::string()}),
153 rx_characteristic_(
154 {device::BluetoothUUID(kRXCharacteristicUUID), std::string()}),
155 task_runner_(base::ThreadTaskRunnerHandle::Get()),
156 timer_(std::make_unique<base::OneShotTimer>()),
157 sub_status_(SubStatus::DISCONNECTED) {
158 DCHECK(!initial_device_address_.empty());
159 adapter_->AddObserver(this);
160 }
161
162 BluetoothLowEnergyWeaveClientConnection::
~BluetoothLowEnergyWeaveClientConnection()163 ~BluetoothLowEnergyWeaveClientConnection() {
164 if (sub_status() == SubStatus::WAITING_CONNECTION_RESPONSE || IsConnected()) {
165 // Deleting this object without calling Disconnect() may result in the
166 // connection staying active longer than intended, which can lead to errors.
167 // See https://crbug.com/763604.
168 PA_LOG(WARNING) << "Warning: Deleting "
169 << "BluetoothLowEnergyWeaveClientConnection object with an "
170 << "active connection to " << GetDeviceInfoLogString()
171 << ". This may result in disconnection errors; trying to "
172 << "send uWeave \"connection close\" packet before "
173 << "deleting.";
174 ClearQueueAndSendConnectionClose();
175 }
176
177 DestroyConnection(
178 BleWeaveConnectionResult::BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
179 }
180
Connect()181 void BluetoothLowEnergyWeaveClientConnection::Connect() {
182 DCHECK(sub_status() == SubStatus::DISCONNECTED);
183
184 if (should_set_low_connection_latency_)
185 SetConnectionLatency();
186 else
187 CreateGattConnection();
188 }
189
SetConnectionLatency()190 void BluetoothLowEnergyWeaveClientConnection::SetConnectionLatency() {
191 DCHECK(sub_status() == SubStatus::DISCONNECTED);
192 SetSubStatus(SubStatus::WAITING_CONNECTION_LATENCY);
193
194 device::BluetoothDevice* bluetooth_device = GetBluetoothDevice();
195 if (!bluetooth_device) {
196 PA_LOG(WARNING) << "Device not found; cannot set connection latency for "
197 << GetDeviceInfoLogString() << ".";
198 DestroyConnection(
199 BleWeaveConnectionResult::
200 BLE_WEAVE_CONNECTION_RESULT_ERROR_BLUETOOTH_DEVICE_NOT_AVAILABLE);
201 return;
202 }
203
204 bluetooth_device->SetConnectionLatency(
205 device::BluetoothDevice::ConnectionLatency::CONNECTION_LATENCY_LOW,
206 base::BindRepeating(&BluetoothLowEnergyWeaveClientConnection::
207 OnSetConnectionLatencySuccess,
208 weak_ptr_factory_.GetWeakPtr()),
209 base::BindRepeating(&BluetoothLowEnergyWeaveClientConnection::
210 OnSetConnectionLatencyErrorOrTimeout,
211 weak_ptr_factory_.GetWeakPtr()));
212 }
213
CreateGattConnection()214 void BluetoothLowEnergyWeaveClientConnection::CreateGattConnection() {
215 DCHECK(sub_status() == SubStatus::DISCONNECTED ||
216 sub_status() == SubStatus::WAITING_CONNECTION_LATENCY);
217 SetSubStatus(SubStatus::WAITING_GATT_CONNECTION);
218
219 device::BluetoothDevice* bluetooth_device = GetBluetoothDevice();
220 if (!bluetooth_device) {
221 PA_LOG(WARNING) << "Device not found; cannot create GATT connection to "
222 << GetDeviceInfoLogString() << ".";
223 DestroyConnection(
224 BleWeaveConnectionResult::
225 BLE_WEAVE_CONNECTION_RESULT_ERROR_BLUETOOTH_DEVICE_NOT_AVAILABLE);
226 return;
227 }
228
229 PA_LOG(INFO) << "Creating GATT connection with " << GetDeviceInfoLogString()
230 << ".";
231 bluetooth_device->CreateGattConnection(
232 base::BindOnce(
233 &BluetoothLowEnergyWeaveClientConnection::OnGattConnectionCreated,
234 weak_ptr_factory_.GetWeakPtr()),
235 base::BindOnce(
236 &BluetoothLowEnergyWeaveClientConnection::OnCreateGattConnectionError,
237 weak_ptr_factory_.GetWeakPtr()));
238 }
239
Disconnect()240 void BluetoothLowEnergyWeaveClientConnection::Disconnect() {
241 if (IsConnected()) {
242 // If a disconnection is already in progress, there is nothing to do.
243 if (has_triggered_disconnection_)
244 return;
245
246 has_triggered_disconnection_ = true;
247 PA_LOG(INFO) << "Disconnection requested; sending \"connection close\" "
248 << "uWeave packet to " << GetDeviceInfoLogString() << ".";
249
250 // Send a "connection close" uWeave packet. After the send has completed,
251 // the connection will disconnect automatically.
252 ClearQueueAndSendConnectionClose();
253 return;
254 }
255
256 DestroyConnection(
257 BleWeaveConnectionResult::BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
258 }
259
DestroyConnection(BleWeaveConnectionResult result)260 void BluetoothLowEnergyWeaveClientConnection::DestroyConnection(
261 BleWeaveConnectionResult result) {
262 if (!has_recorded_connection_result_) {
263 has_recorded_connection_result_ = true;
264 RecordBleWeaveConnectionResult(result);
265 }
266
267 if (adapter_) {
268 adapter_->RemoveObserver(this);
269 adapter_ = nullptr;
270 }
271
272 weak_ptr_factory_.InvalidateWeakPtrs();
273 notify_session_.reset();
274 characteristic_finder_.reset();
275
276 if (gatt_connection_) {
277 PA_LOG(INFO) << "Disconnecting from " << GetDeviceInfoLogString();
278 gatt_connection_.reset();
279 }
280
281 SetSubStatus(SubStatus::DISCONNECTED);
282 }
283
SetSubStatus(SubStatus new_sub_status)284 void BluetoothLowEnergyWeaveClientConnection::SetSubStatus(
285 SubStatus new_sub_status) {
286 sub_status_ = new_sub_status;
287 timer_->Stop();
288
289 base::TimeDelta timeout_for_sub_status = GetTimeoutForSubStatus(sub_status_);
290 if (!timeout_for_sub_status.is_max()) {
291 timer_->Start(
292 FROM_HERE, timeout_for_sub_status,
293 base::BindOnce(
294 &BluetoothLowEnergyWeaveClientConnection::OnTimeoutForSubStatus,
295 weak_ptr_factory_.GetWeakPtr(), sub_status_));
296 }
297
298 // Sets the status of base class Connection.
299 switch (new_sub_status) {
300 case SubStatus::CONNECTED_AND_IDLE:
301 case SubStatus::CONNECTED_AND_SENDING_MESSAGE:
302 SetStatus(Status::CONNECTED);
303 break;
304 case SubStatus::DISCONNECTED:
305 SetStatus(Status::DISCONNECTED);
306 break;
307 default:
308 SetStatus(Status::IN_PROGRESS);
309 }
310 }
311
OnTimeoutForSubStatus(SubStatus timed_out_sub_status)312 void BluetoothLowEnergyWeaveClientConnection::OnTimeoutForSubStatus(
313 SubStatus timed_out_sub_status) {
314 // Ensure that |timed_out_sub_status| is still the active status.
315 DCHECK(timed_out_sub_status == sub_status());
316
317 if (timed_out_sub_status == SubStatus::WAITING_CONNECTION_LATENCY) {
318 OnSetConnectionLatencyErrorOrTimeout();
319 return;
320 }
321
322 PA_LOG(ERROR) << "Timed out waiting during SubStatus "
323 << SubStatusToString(timed_out_sub_status) << ". "
324 << "Destroying connection.";
325
326 BleWeaveConnectionResult result =
327 BleWeaveConnectionResult::BLE_WEAVE_CONNECTION_RESULT_MAX;
328 switch (timed_out_sub_status) {
329 case SubStatus::WAITING_GATT_CONNECTION:
330 result = BleWeaveConnectionResult::
331 BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_CREATING_GATT_CONNECTION;
332 break;
333 case SubStatus::WAITING_CHARACTERISTICS:
334 result = BleWeaveConnectionResult::
335 BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_FINDING_GATT_CHARACTERISTICS;
336 break;
337 case SubStatus::WAITING_NOTIFY_SESSION:
338 result = BleWeaveConnectionResult::
339 BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_STARTING_NOTIFY_SESSION;
340 break;
341 case SubStatus::WAITING_CONNECTION_RESPONSE:
342 result = BleWeaveConnectionResult::
343 BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_WAITING_FOR_CONNECTION_RESPONSE;
344 break;
345 case SubStatus::CONNECTED_AND_SENDING_MESSAGE:
346 result = BleWeaveConnectionResult::
347 BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_WAITING_FOR_MESSAGE_TO_SEND;
348 break;
349 default:
350 NOTREACHED();
351 }
352
353 DestroyConnection(result);
354 }
355
SetupTestDoubles(scoped_refptr<base::TaskRunner> test_task_runner,std::unique_ptr<base::OneShotTimer> test_timer,std::unique_ptr<BluetoothLowEnergyWeavePacketGenerator> test_generator,std::unique_ptr<BluetoothLowEnergyWeavePacketReceiver> test_receiver)356 void BluetoothLowEnergyWeaveClientConnection::SetupTestDoubles(
357 scoped_refptr<base::TaskRunner> test_task_runner,
358 std::unique_ptr<base::OneShotTimer> test_timer,
359 std::unique_ptr<BluetoothLowEnergyWeavePacketGenerator> test_generator,
360 std::unique_ptr<BluetoothLowEnergyWeavePacketReceiver> test_receiver) {
361 task_runner_ = test_task_runner;
362 timer_ = std::move(test_timer);
363 packet_generator_ = std::move(test_generator);
364 packet_receiver_ = std::move(test_receiver);
365 }
366
SendMessageImpl(std::unique_ptr<WireMessage> message)367 void BluetoothLowEnergyWeaveClientConnection::SendMessageImpl(
368 std::unique_ptr<WireMessage> message) {
369 DCHECK(IsConnected());
370
371 // Split |message| up into multiple packets which can be sent as one uWeave
372 // message.
373 std::vector<Packet> weave_packets =
374 packet_generator_->EncodeDataMessage(message->Serialize());
375
376 // For each packet, create a WriteRequest and add it to the queue.
377 for (uint32_t i = 0; i < weave_packets.size(); ++i) {
378 WriteRequestType request_type = (i != weave_packets.size() - 1)
379 ? WriteRequestType::REGULAR
380 : WriteRequestType::MESSAGE_COMPLETE;
381 queued_write_requests_.emplace(std::make_unique<WriteRequest>(
382 weave_packets[i], request_type, message.get()));
383 }
384
385 // Add |message| to the queue of WireMessages.
386 queued_wire_messages_.emplace(std::move(message));
387
388 ProcessNextWriteRequest();
389 }
390
DeviceConnectedStateChanged(device::BluetoothAdapter * adapter,device::BluetoothDevice * device,bool is_now_connected)391 void BluetoothLowEnergyWeaveClientConnection::DeviceConnectedStateChanged(
392 device::BluetoothAdapter* adapter,
393 device::BluetoothDevice* device,
394 bool is_now_connected) {
395 // Ignore updates about other devices.
396 if (device->GetAddress() != GetDeviceAddress())
397 return;
398
399 if (sub_status() == SubStatus::DISCONNECTED ||
400 sub_status() == SubStatus::WAITING_CONNECTION_LATENCY ||
401 sub_status() == SubStatus::WAITING_GATT_CONNECTION) {
402 // Ignore status change events if a connection has not yet occurred.
403 return;
404 }
405
406 // If a connection has already occurred and |device| is still connected, there
407 // is nothing to do.
408 if (is_now_connected)
409 return;
410
411 PA_LOG(WARNING) << "GATT connection to " << GetDeviceInfoLogString()
412 << " has been dropped.";
413 DestroyConnection(BleWeaveConnectionResult::
414 BLE_WEAVE_CONNECTION_RESULT_ERROR_CONNECTION_DROPPED);
415 }
416
GattCharacteristicValueChanged(device::BluetoothAdapter * adapter,device::BluetoothRemoteGattCharacteristic * characteristic,const Packet & value)417 void BluetoothLowEnergyWeaveClientConnection::GattCharacteristicValueChanged(
418 device::BluetoothAdapter* adapter,
419 device::BluetoothRemoteGattCharacteristic* characteristic,
420 const Packet& value) {
421 DCHECK_EQ(adapter, adapter_.get());
422
423 // Ignore characteristics which do not apply to this connection.
424 if (characteristic->GetIdentifier() != rx_characteristic_.id)
425 return;
426
427 if (sub_status() != SubStatus::WAITING_CONNECTION_RESPONSE &&
428 !IsConnected()) {
429 PA_LOG(WARNING) << "Received message from " << GetDeviceInfoLogString()
430 << ", but was not expecting one. sub_status() = "
431 << sub_status();
432 return;
433 }
434
435 switch (packet_receiver_->ReceivePacket(value)) {
436 case ReceiverState::DATA_READY:
437 OnBytesReceived(packet_receiver_->GetDataMessage());
438 break;
439 case ReceiverState::CONNECTION_CLOSED:
440 PA_LOG(INFO) << "Received \"connection close\" uWeave packet from "
441 << GetDeviceInfoLogString()
442 << ". Reason: " << GetReasonForClose() << ".";
443 DestroyConnection(BleWeaveConnectionResult::
444 BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
445 return;
446 case ReceiverState::ERROR_DETECTED:
447 PA_LOG(ERROR) << "Received invalid packet from "
448 << GetDeviceInfoLogString() << ". ";
449 ClearQueueAndSendConnectionClose();
450 break;
451 case ReceiverState::WAITING:
452 CompleteConnection();
453 break;
454 case ReceiverState::RECEIVING_DATA:
455 // Continue to wait for more packets to arrive; once the rest of the
456 // packets for this message are received, |packet_receiver_| will
457 // transition to the DATA_READY state.
458 break;
459 default:
460 NOTREACHED();
461 }
462 }
463
CompleteConnection()464 void BluetoothLowEnergyWeaveClientConnection::CompleteConnection() {
465 DCHECK(sub_status() == SubStatus::WAITING_CONNECTION_RESPONSE);
466
467 uint16_t max_packet_size = packet_receiver_->GetMaxPacketSize();
468 PA_LOG(INFO) << "Received uWeave \"connection response\" packet; connection "
469 << "is now fully initialized for " << GetDeviceInfoLogString()
470 << ". Max packet size: " << max_packet_size;
471
472 // Now that the "connection close" uWeave packet has been received,
473 // |packet_receiver_| should have received a max packet size from the GATT
474 // server.
475 packet_generator_->SetMaxPacketSize(max_packet_size);
476
477 SetSubStatus(SubStatus::CONNECTED_AND_IDLE);
478 }
479
OnSetConnectionLatencySuccess()480 void BluetoothLowEnergyWeaveClientConnection::OnSetConnectionLatencySuccess() {
481 // TODO(crbug.com/929518): Record how long it took to set connection latency.
482
483 // It's possible that we timed out when attempting to set the connection
484 // latency before this callback was called, resulting in this class moving
485 // forward with a GATT connection (i.e., in any state other than
486 // |SubStatus::WAITING_CONNECTION_LATENCY|). That could mean, at this point in
487 // time, that we're in the middle of connecting, already connected, or any
488 // state in between. That's fine; simply early return in order to prevent
489 // trying to create yet another GATT connection (which will fail).
490 if (sub_status() != SubStatus::WAITING_CONNECTION_LATENCY) {
491 PA_LOG(WARNING) << "Setting connection latency succeeded but GATT "
492 << "connection to " << GetDeviceInfoLogString()
493 << " is already in progress or complete.";
494 return;
495 }
496
497 CreateGattConnection();
498 }
499
500 void BluetoothLowEnergyWeaveClientConnection::
OnSetConnectionLatencyErrorOrTimeout()501 OnSetConnectionLatencyErrorOrTimeout() {
502 // TODO(crbug.com/929518): Record when setting connection latency fails or
503 // times out.
504
505 DCHECK(sub_status_ == SubStatus::WAITING_CONNECTION_LATENCY);
506 PA_LOG(WARNING)
507 << "Error or timeout setting connection latency for connection to "
508 << GetDeviceInfoLogString() << ".";
509
510 // Even if setting the connection latency fails, continue with the
511 // connection. This is unfortunate but should not be considered a fatal error.
512 CreateGattConnection();
513 }
514
OnCreateGattConnectionError(device::BluetoothDevice::ConnectErrorCode error_code)515 void BluetoothLowEnergyWeaveClientConnection::OnCreateGattConnectionError(
516 device::BluetoothDevice::ConnectErrorCode error_code) {
517 DCHECK(sub_status_ == SubStatus::WAITING_GATT_CONNECTION);
518 RecordGattConnectionResult(
519 BluetoothDeviceConnectErrorCodeToGattConnectionResult(error_code));
520 PA_LOG(WARNING) << "Error creating GATT connection to "
521 << GetDeviceInfoLogString() << ". Error code: " << error_code;
522 DestroyConnection(
523 BleWeaveConnectionResult::
524 BLE_WEAVE_CONNECTION_RESULT_ERROR_CREATING_GATT_CONNECTION);
525 }
526
OnGattConnectionCreated(std::unique_ptr<device::BluetoothGattConnection> gatt_connection)527 void BluetoothLowEnergyWeaveClientConnection::OnGattConnectionCreated(
528 std::unique_ptr<device::BluetoothGattConnection> gatt_connection) {
529 DCHECK(sub_status() == SubStatus::WAITING_GATT_CONNECTION);
530 RecordGattConnectionResult(
531 GattConnectionResult::GATT_CONNECTION_RESULT_SUCCESS);
532
533 gatt_connection_ = std::move(gatt_connection);
534 SetSubStatus(SubStatus::WAITING_CHARACTERISTICS);
535
536 PA_LOG(INFO) << "Finding GATT characteristics for "
537 << GetDeviceInfoLogString() << ".";
538 characteristic_finder_.reset(CreateCharacteristicsFinder(
539 base::BindOnce(
540 &BluetoothLowEnergyWeaveClientConnection::OnCharacteristicsFound,
541 weak_ptr_factory_.GetWeakPtr()),
542 base::BindOnce(&BluetoothLowEnergyWeaveClientConnection::
543 OnCharacteristicsFinderError,
544 weak_ptr_factory_.GetWeakPtr())));
545 }
546
547 BluetoothLowEnergyCharacteristicsFinder*
CreateCharacteristicsFinder(BluetoothLowEnergyCharacteristicsFinder::SuccessCallback success_callback,base::OnceClosure error_callback)548 BluetoothLowEnergyWeaveClientConnection::CreateCharacteristicsFinder(
549 BluetoothLowEnergyCharacteristicsFinder::SuccessCallback success_callback,
550 base::OnceClosure error_callback) {
551 return new BluetoothLowEnergyCharacteristicsFinder(
552 adapter_, GetBluetoothDevice(), remote_service_, tx_characteristic_,
553 rx_characteristic_, std::move(success_callback),
554 std::move(error_callback), remote_device(),
555 std::make_unique<BackgroundEidGenerator>());
556 }
557
OnCharacteristicsFound(const RemoteAttribute & service,const RemoteAttribute & tx_characteristic,const RemoteAttribute & rx_characteristic)558 void BluetoothLowEnergyWeaveClientConnection::OnCharacteristicsFound(
559 const RemoteAttribute& service,
560 const RemoteAttribute& tx_characteristic,
561 const RemoteAttribute& rx_characteristic) {
562 DCHECK(sub_status() == SubStatus::WAITING_CHARACTERISTICS);
563
564 remote_service_ = service;
565 tx_characteristic_ = tx_characteristic;
566 rx_characteristic_ = rx_characteristic;
567 characteristic_finder_.reset();
568
569 SetSubStatus(SubStatus::CHARACTERISTICS_FOUND);
570
571 StartNotifySession();
572 }
573
OnCharacteristicsFinderError()574 void BluetoothLowEnergyWeaveClientConnection::OnCharacteristicsFinderError() {
575 DCHECK(sub_status() == SubStatus::WAITING_CHARACTERISTICS);
576
577 PA_LOG(ERROR) << "Could not find GATT characteristics for "
578 << GetDeviceInfoLogString();
579
580 characteristic_finder_.reset();
581
582 DestroyConnection(
583 BleWeaveConnectionResult::
584 BLE_WEAVE_CONNECTION_RESULT_ERROR_FINDING_GATT_CHARACTERISTICS);
585 }
586
StartNotifySession()587 void BluetoothLowEnergyWeaveClientConnection::StartNotifySession() {
588 DCHECK(sub_status() == SubStatus::CHARACTERISTICS_FOUND);
589
590 device::BluetoothRemoteGattCharacteristic* characteristic =
591 GetGattCharacteristic(rx_characteristic_.id);
592 if (!characteristic) {
593 PA_LOG(ERROR) << "Characteristic no longer available after it was found. "
594 << "Cannot start notification session for "
595 << GetDeviceInfoLogString() << ".";
596 DestroyConnection(
597 BleWeaveConnectionResult::
598 BLE_WEAVE_CONNECTION_RESULT_ERROR_GATT_CHARACTERISTIC_NOT_AVAILABLE);
599 return;
600 }
601
602 // Workaround for crbug.com/507325. If |characteristic| is already notifying,
603 // characteristic->StartNotifySession() fails with GATT_ERROR_FAILED.
604 if (characteristic->IsNotifying()) {
605 SetSubStatus(SubStatus::NOTIFY_SESSION_READY);
606 SendConnectionRequest();
607 return;
608 }
609
610 SetSubStatus(SubStatus::WAITING_NOTIFY_SESSION);
611 PA_LOG(INFO) << "Starting notification session for "
612 << GetDeviceInfoLogString() << ".";
613 characteristic->StartNotifySession(
614 base::BindOnce(
615 &BluetoothLowEnergyWeaveClientConnection::OnNotifySessionStarted,
616 weak_ptr_factory_.GetWeakPtr()),
617 base::BindOnce(
618 &BluetoothLowEnergyWeaveClientConnection::OnNotifySessionError,
619 weak_ptr_factory_.GetWeakPtr()));
620 }
621
OnNotifySessionStarted(std::unique_ptr<device::BluetoothGattNotifySession> notify_session)622 void BluetoothLowEnergyWeaveClientConnection::OnNotifySessionStarted(
623 std::unique_ptr<device::BluetoothGattNotifySession> notify_session) {
624 DCHECK(sub_status() == SubStatus::WAITING_NOTIFY_SESSION);
625 RecordGattNotifySessionResult(
626 GattServiceOperationResult::GATT_SERVICE_OPERATION_RESULT_SUCCESS);
627 notify_session_ = std::move(notify_session);
628 SetSubStatus(SubStatus::NOTIFY_SESSION_READY);
629 SendConnectionRequest();
630 }
631
OnNotifySessionError(device::BluetoothRemoteGattService::GattErrorCode error)632 void BluetoothLowEnergyWeaveClientConnection::OnNotifySessionError(
633 device::BluetoothRemoteGattService::GattErrorCode error) {
634 DCHECK(sub_status() == SubStatus::WAITING_NOTIFY_SESSION);
635 RecordGattNotifySessionResult(
636 BluetoothRemoteDeviceGattServiceGattErrorCodeToGattServiceOperationResult(
637 error));
638 PA_LOG(ERROR) << "Cannot start notification session for "
639 << GetDeviceInfoLogString() << ". Error: " << error << ".";
640 DestroyConnection(
641 BleWeaveConnectionResult::
642 BLE_WEAVE_CONNECTION_RESULT_ERROR_STARTING_NOTIFY_SESSION);
643 }
644
SendConnectionRequest()645 void BluetoothLowEnergyWeaveClientConnection::SendConnectionRequest() {
646 DCHECK(sub_status() == SubStatus::NOTIFY_SESSION_READY);
647 SetSubStatus(SubStatus::WAITING_CONNECTION_RESPONSE);
648
649 PA_LOG(INFO) << "Sending \"connection request\" uWeave packet to "
650 << GetDeviceInfoLogString();
651
652 queued_write_requests_.emplace(std::make_unique<WriteRequest>(
653 packet_generator_->CreateConnectionRequest(),
654 WriteRequestType::CONNECTION_REQUEST));
655 ProcessNextWriteRequest();
656 }
657
ProcessNextWriteRequest()658 void BluetoothLowEnergyWeaveClientConnection::ProcessNextWriteRequest() {
659 // If there is already an in-progress write or there are no pending
660 // WriteRequests, there is nothing to do.
661 if (pending_write_request_ || queued_write_requests_.empty())
662 return;
663
664 pending_write_request_ = std::move(queued_write_requests_.front());
665 queued_write_requests_.pop();
666
667 PA_LOG(INFO) << "Writing " << pending_write_request_->value.size() << " "
668 << "bytes to " << GetDeviceInfoLogString() << ".";
669 SendPendingWriteRequest();
670 }
671
SendPendingWriteRequest()672 void BluetoothLowEnergyWeaveClientConnection::SendPendingWriteRequest() {
673 DCHECK(pending_write_request_);
674
675 device::BluetoothRemoteGattCharacteristic* characteristic =
676 GetGattCharacteristic(tx_characteristic_.id);
677 if (!characteristic) {
678 PA_LOG(ERROR) << "Characteristic no longer available after it was found. "
679 << "Cannot process write request for "
680 << GetDeviceInfoLogString() << ".";
681 DestroyConnection(
682 BleWeaveConnectionResult::
683 BLE_WEAVE_CONNECTION_RESULT_ERROR_GATT_CHARACTERISTIC_NOT_AVAILABLE);
684 return;
685 }
686
687 // If the current status is CONNECTED_AND_IDLE, transition to
688 // CONNECTED_AND_SENDING_MESSAGE. This function also runs when the status is
689 // WAITING_CONNECTION_RESPONSE; in that case, the status should remain
690 // unchanged until the connection response has been received.
691 if (sub_status() == SubStatus::CONNECTED_AND_IDLE)
692 SetSubStatus(SubStatus::CONNECTED_AND_SENDING_MESSAGE);
693
694 // Note: the Android implementation of this GATT characteristic does not
695 // support kWithoutResponse; we must specify kWithResponse.
696 characteristic->WriteRemoteCharacteristic(
697 pending_write_request_->value,
698 device::BluetoothRemoteGattCharacteristic::WriteType::kWithResponse,
699 base::BindOnce(&BluetoothLowEnergyWeaveClientConnection::
700 OnRemoteCharacteristicWritten,
701 weak_ptr_factory_.GetWeakPtr()),
702 base::BindOnce(&BluetoothLowEnergyWeaveClientConnection::
703 OnWriteRemoteCharacteristicError,
704 weak_ptr_factory_.GetWeakPtr()));
705 }
706
OnRemoteCharacteristicWritten()707 void BluetoothLowEnergyWeaveClientConnection::OnRemoteCharacteristicWritten() {
708 DCHECK(sub_status() == SubStatus::WAITING_CONNECTION_RESPONSE ||
709 sub_status() == SubStatus::CONNECTED_AND_SENDING_MESSAGE);
710 if (sub_status() == SubStatus::CONNECTED_AND_SENDING_MESSAGE)
711 SetSubStatus(SubStatus::CONNECTED_AND_IDLE);
712
713 RecordGattWriteCharacteristicResult(
714 GattServiceOperationResult::GATT_SERVICE_OPERATION_RESULT_SUCCESS);
715
716 if (!pending_write_request_) {
717 PA_LOG(ERROR) << "OnRemoteCharacteristicWritten() called, but no pending "
718 << "WriteRequest. Stopping connection to "
719 << GetDeviceInfoLogString();
720 DestroyConnection(
721 BleWeaveConnectionResult::
722 BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITE_QUEUE_OUT_OF_SYNC);
723 return;
724 }
725
726 if (pending_write_request_->request_type ==
727 WriteRequestType::CONNECTION_CLOSE) {
728 // Once a "connection close" uWeave packet has been sent, the connection
729 // is ready to be disconnected.
730 PA_LOG(INFO) << "uWeave \"connection close\" packet sent to "
731 << GetDeviceInfoLogString() << ". Destroying connection.";
732 DestroyConnection(
733 BleWeaveConnectionResult::BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
734 return;
735 }
736
737 if (pending_write_request_->request_type ==
738 WriteRequestType::MESSAGE_COMPLETE) {
739 if (queued_wire_messages_.empty()) {
740 PA_LOG(ERROR) << "Sent a WriteRequest with type == MESSAGE_COMPLETE, but "
741 << "there were no queued WireMessages. Cannot process "
742 << "completed write to " << GetDeviceInfoLogString();
743 DestroyConnection(
744 BleWeaveConnectionResult::
745 BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITING_GATT_CHARACTERISTIC);
746 return;
747 }
748
749 std::unique_ptr<WireMessage> sent_message =
750 std::move(queued_wire_messages_.front());
751 queued_wire_messages_.pop();
752 DCHECK_EQ(sent_message.get(),
753 pending_write_request_->associated_wire_message);
754
755 // Notify observers of the message being sent via a task on the run loop to
756 // ensure that if an observer deletes this object in response to receiving
757 // the OnSendCompleted() callback, a null pointer is not deferenced.
758 task_runner_->PostTask(
759 FROM_HERE,
760 base::BindOnce(
761 &BluetoothLowEnergyWeaveClientConnection::OnDidSendMessage,
762 weak_ptr_factory_.GetWeakPtr(), *sent_message, true /* success */));
763 }
764
765 pending_write_request_.reset();
766 ProcessNextWriteRequest();
767 }
768
OnWriteRemoteCharacteristicError(device::BluetoothRemoteGattService::GattErrorCode error)769 void BluetoothLowEnergyWeaveClientConnection::OnWriteRemoteCharacteristicError(
770 device::BluetoothRemoteGattService::GattErrorCode error) {
771 DCHECK(sub_status() == SubStatus::WAITING_CONNECTION_RESPONSE ||
772 sub_status() == SubStatus::CONNECTED_AND_SENDING_MESSAGE);
773 if (sub_status() == SubStatus::CONNECTED_AND_SENDING_MESSAGE)
774 SetSubStatus(SubStatus::CONNECTED_AND_IDLE);
775
776 RecordGattWriteCharacteristicResult(
777 BluetoothRemoteDeviceGattServiceGattErrorCodeToGattServiceOperationResult(
778 error));
779
780 if (!pending_write_request_) {
781 PA_LOG(ERROR) << "OnWriteRemoteCharacteristicError() called, but no "
782 << "pending WriteRequest. Stopping connection to "
783 << GetDeviceInfoLogString();
784 DestroyConnection(
785 BleWeaveConnectionResult::
786 BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITE_QUEUE_OUT_OF_SYNC);
787 return;
788 }
789
790 ++pending_write_request_->number_of_failed_attempts;
791 if (pending_write_request_->number_of_failed_attempts <
792 kMaxNumberOfRetryAttempts + 1) {
793 PA_LOG(WARNING) << "Error sending WriteRequest to "
794 << GetDeviceInfoLogString() << "; failure number "
795 << pending_write_request_->number_of_failed_attempts
796 << ". Retrying.";
797 SendPendingWriteRequest();
798 return;
799 }
800
801 if (pending_write_request_->request_type == WriteRequestType::REGULAR ||
802 pending_write_request_->request_type ==
803 WriteRequestType::MESSAGE_COMPLETE) {
804 std::unique_ptr<WireMessage> failed_message =
805 std::move(queued_wire_messages_.front());
806 queued_wire_messages_.pop();
807 DCHECK_EQ(failed_message.get(),
808 pending_write_request_->associated_wire_message);
809
810 OnDidSendMessage(*failed_message, false /* success */);
811 }
812
813 // Since the try limit has been hit, this is a fatal error. Destroy the
814 // connection, but post it as a new task to ensure that observers have a
815 // chance to process the OnSendCompleted() call.
816 task_runner_->PostTask(
817 FROM_HERE,
818 base::BindOnce(
819 &BluetoothLowEnergyWeaveClientConnection::DestroyConnection,
820 weak_ptr_factory_.GetWeakPtr(),
821 BleWeaveConnectionResult::
822 BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITING_GATT_CHARACTERISTIC));
823 }
824
OnDidSendMessage(const WireMessage & message,bool success)825 void BluetoothLowEnergyWeaveClientConnection::OnDidSendMessage(
826 const WireMessage& message,
827 bool success) {
828 Connection::OnDidSendMessage(message, success);
829 }
830
831 void BluetoothLowEnergyWeaveClientConnection::
ClearQueueAndSendConnectionClose()832 ClearQueueAndSendConnectionClose() {
833 DCHECK(sub_status() == SubStatus::WAITING_CONNECTION_RESPONSE ||
834 IsConnected());
835
836 // The connection is now in an invalid state. Clear queued writes.
837 while (!queued_write_requests_.empty())
838 queued_write_requests_.pop();
839
840 // Now, queue up a "connection close" uWeave packet. If there was a pending
841 // write, we must wait for it to complete before the "connection close" can
842 // be sent.
843 queued_write_requests_.emplace(
844 std::make_unique<WriteRequest>(packet_generator_->CreateConnectionClose(
845 packet_receiver_->GetReasonToClose()),
846 WriteRequestType::CONNECTION_CLOSE));
847
848 if (pending_write_request_) {
849 PA_LOG(WARNING) << "Waiting for current write to complete, then will send "
850 << "a \"connection close\" uWeave packet to "
851 << GetDeviceInfoLogString() << ".";
852 } else {
853 PA_LOG(INFO) << "Sending a \"connection close\" uWeave packet to "
854 << GetDeviceInfoLogString() << ".";
855 }
856
857 ProcessNextWriteRequest();
858 }
859
GetDeviceAddress()860 std::string BluetoothLowEnergyWeaveClientConnection::GetDeviceAddress() {
861 // When the remote device is connected, rely on the address given by
862 // |gatt_connection_|. Unpaired BLE device addresses are ephemeral and are
863 // expected to change periodically.
864 return gatt_connection_ ? gatt_connection_->GetDeviceAddress()
865 : initial_device_address_;
866 }
867
GetConnectionRssi(base::OnceCallback<void (base::Optional<int32_t>)> callback)868 void BluetoothLowEnergyWeaveClientConnection::GetConnectionRssi(
869 base::OnceCallback<void(base::Optional<int32_t>)> callback) {
870 device::BluetoothDevice* bluetooth_device = GetBluetoothDevice();
871 if (!bluetooth_device || !bluetooth_device->IsConnected()) {
872 std::move(callback).Run(base::nullopt);
873 return;
874 }
875
876 // device::BluetoothDevice has not converted to using a base::OnceCallback
877 // instead of a base::Callback, so use a wrapper for now.
878 auto callback_holder = base::AdaptCallbackForRepeating(std::move(callback));
879 bluetooth_device->GetConnectionInfo(
880 base::BindOnce(&BluetoothLowEnergyWeaveClientConnection::OnConnectionInfo,
881 weak_ptr_factory_.GetWeakPtr(), callback_holder));
882 }
883
OnConnectionInfo(base::RepeatingCallback<void (base::Optional<int32_t>)> rssi_callback,const device::BluetoothDevice::ConnectionInfo & connection_info)884 void BluetoothLowEnergyWeaveClientConnection::OnConnectionInfo(
885 base::RepeatingCallback<void(base::Optional<int32_t>)> rssi_callback,
886 const device::BluetoothDevice::ConnectionInfo& connection_info) {
887 if (connection_info.rssi == device::BluetoothDevice::kUnknownPower) {
888 std::move(rssi_callback).Run(base::nullopt);
889 return;
890 }
891
892 std::move(rssi_callback).Run(connection_info.rssi);
893 }
894
895 device::BluetoothRemoteGattService*
GetRemoteService()896 BluetoothLowEnergyWeaveClientConnection::GetRemoteService() {
897 device::BluetoothDevice* bluetooth_device = GetBluetoothDevice();
898 if (!bluetooth_device) {
899 PA_LOG(WARNING) << "Cannot find Bluetooth device for "
900 << GetDeviceInfoLogString();
901 return nullptr;
902 }
903
904 if (remote_service_.id.empty()) {
905 for (auto* service : bluetooth_device->GetGattServices()) {
906 if (service->GetUUID() == remote_service_.uuid) {
907 remote_service_.id = service->GetIdentifier();
908 break;
909 }
910 }
911 }
912
913 return bluetooth_device->GetGattService(remote_service_.id);
914 }
915
916 device::BluetoothRemoteGattCharacteristic*
GetGattCharacteristic(const std::string & gatt_characteristic)917 BluetoothLowEnergyWeaveClientConnection::GetGattCharacteristic(
918 const std::string& gatt_characteristic) {
919 device::BluetoothRemoteGattService* remote_service = GetRemoteService();
920 if (!remote_service) {
921 PA_LOG(WARNING) << "Cannot find GATT service for "
922 << GetDeviceInfoLogString();
923 return nullptr;
924 }
925 return remote_service->GetCharacteristic(gatt_characteristic);
926 }
927
928 device::BluetoothDevice*
GetBluetoothDevice()929 BluetoothLowEnergyWeaveClientConnection::GetBluetoothDevice() {
930 return adapter_ ? adapter_->GetDevice(GetDeviceAddress()) : nullptr;
931 }
932
GetReasonForClose()933 std::string BluetoothLowEnergyWeaveClientConnection::GetReasonForClose() {
934 switch (packet_receiver_->GetReasonForClose()) {
935 case ReasonForClose::CLOSE_WITHOUT_ERROR:
936 return "CLOSE_WITHOUT_ERROR";
937 case ReasonForClose::UNKNOWN_ERROR:
938 return "UNKNOWN_ERROR";
939 case ReasonForClose::NO_COMMON_VERSION_SUPPORTED:
940 return "NO_COMMON_VERSION_SUPPORTED";
941 case ReasonForClose::RECEIVED_PACKET_OUT_OF_SEQUENCE:
942 return "RECEIVED_PACKET_OUT_OF_SEQUENCE";
943 case ReasonForClose::APPLICATION_ERROR:
944 return "APPLICATION_ERROR";
945 default:
946 NOTREACHED();
947 return "";
948 }
949 }
950
RecordBleWeaveConnectionResult(BleWeaveConnectionResult result)951 void BluetoothLowEnergyWeaveClientConnection::RecordBleWeaveConnectionResult(
952 BleWeaveConnectionResult result) {
953 UMA_HISTOGRAM_ENUMERATION(
954 "ProximityAuth.BleWeaveConnectionResult", result,
955 BleWeaveConnectionResult::BLE_WEAVE_CONNECTION_RESULT_MAX);
956 }
957
RecordGattConnectionResult(GattConnectionResult result)958 void BluetoothLowEnergyWeaveClientConnection::RecordGattConnectionResult(
959 GattConnectionResult result) {
960 UMA_HISTOGRAM_ENUMERATION("ProximityAuth.BluetoothGattConnectionResult",
961 result,
962 GattConnectionResult::GATT_CONNECTION_RESULT_MAX);
963 }
964
965 BluetoothLowEnergyWeaveClientConnection::GattConnectionResult
966 BluetoothLowEnergyWeaveClientConnection::
BluetoothDeviceConnectErrorCodeToGattConnectionResult(device::BluetoothDevice::ConnectErrorCode error_code)967 BluetoothDeviceConnectErrorCodeToGattConnectionResult(
968 device::BluetoothDevice::ConnectErrorCode error_code) {
969 switch (error_code) {
970 case device::BluetoothDevice::ConnectErrorCode::ERROR_AUTH_CANCELED:
971 return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_AUTH_CANCELED;
972 case device::BluetoothDevice::ConnectErrorCode::ERROR_AUTH_FAILED:
973 return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_AUTH_FAILED;
974 case device::BluetoothDevice::ConnectErrorCode::ERROR_AUTH_REJECTED:
975 return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_AUTH_REJECTED;
976 case device::BluetoothDevice::ConnectErrorCode::ERROR_AUTH_TIMEOUT:
977 return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_AUTH_TIMEOUT;
978 case device::BluetoothDevice::ConnectErrorCode::ERROR_FAILED:
979 return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_FAILED;
980 case device::BluetoothDevice::ConnectErrorCode::ERROR_INPROGRESS:
981 return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_INPROGRESS;
982 case device::BluetoothDevice::ConnectErrorCode::ERROR_UNKNOWN:
983 return GattConnectionResult::GATT_CONNECTION_RESULT_ERROR_UNKNOWN;
984 case device::BluetoothDevice::ConnectErrorCode::ERROR_UNSUPPORTED_DEVICE:
985 return GattConnectionResult::
986 GATT_CONNECTION_RESULT_ERROR_UNSUPPORTED_DEVICE;
987 default:
988 return GattConnectionResult::GATT_CONNECTION_RESULT_UNKNOWN;
989 }
990 }
991
RecordGattNotifySessionResult(GattServiceOperationResult result)992 void BluetoothLowEnergyWeaveClientConnection::RecordGattNotifySessionResult(
993 GattServiceOperationResult result) {
994 UMA_HISTOGRAM_ENUMERATION(
995 "ProximityAuth.BluetoothGattNotifySessionResult", result,
996 GattServiceOperationResult::GATT_SERVICE_OPERATION_RESULT_MAX);
997 }
998
999 void BluetoothLowEnergyWeaveClientConnection::
RecordGattWriteCharacteristicResult(GattServiceOperationResult result)1000 RecordGattWriteCharacteristicResult(GattServiceOperationResult result) {
1001 UMA_HISTOGRAM_ENUMERATION(
1002 "ProximityAuth.BluetoothGattWriteCharacteristicResult", result,
1003 GattServiceOperationResult::GATT_SERVICE_OPERATION_RESULT_MAX);
1004 }
1005
1006 BluetoothLowEnergyWeaveClientConnection::GattServiceOperationResult
1007 BluetoothLowEnergyWeaveClientConnection::
BluetoothRemoteDeviceGattServiceGattErrorCodeToGattServiceOperationResult(device::BluetoothRemoteGattService::GattErrorCode error_code)1008 BluetoothRemoteDeviceGattServiceGattErrorCodeToGattServiceOperationResult(
1009 device::BluetoothRemoteGattService::GattErrorCode error_code) {
1010 switch (error_code) {
1011 case device::BluetoothRemoteGattService::GattErrorCode::GATT_ERROR_UNKNOWN:
1012 return GattServiceOperationResult::
1013 GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_UNKNOWN;
1014 case device::BluetoothRemoteGattService::GattErrorCode::GATT_ERROR_FAILED:
1015 return GattServiceOperationResult::
1016 GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_FAILED;
1017 case device::BluetoothRemoteGattService::GattErrorCode::
1018 GATT_ERROR_IN_PROGRESS:
1019 return GattServiceOperationResult::
1020 GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_IN_PROGRESS;
1021 case device::BluetoothRemoteGattService::GattErrorCode::
1022 GATT_ERROR_INVALID_LENGTH:
1023 return GattServiceOperationResult::
1024 GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_INVALID_LENGTH;
1025 case device::BluetoothRemoteGattService::GattErrorCode::
1026 GATT_ERROR_NOT_PERMITTED:
1027 return GattServiceOperationResult::
1028 GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_NOT_PERMITTED;
1029 case device::BluetoothRemoteGattService::GattErrorCode::
1030 GATT_ERROR_NOT_AUTHORIZED:
1031 return GattServiceOperationResult::
1032 GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_NOT_AUTHORIZED;
1033 case device::BluetoothRemoteGattService::GattErrorCode::
1034 GATT_ERROR_NOT_PAIRED:
1035 return GattServiceOperationResult::
1036 GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_NOT_PAIRED;
1037 case device::BluetoothRemoteGattService::GattErrorCode::
1038 GATT_ERROR_NOT_SUPPORTED:
1039 return GattServiceOperationResult::
1040 GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_NOT_SUPPORTED;
1041 default:
1042 return GattServiceOperationResult::GATT_SERVICE_OPERATION_RESULT_UNKNOWN;
1043 }
1044 }
1045
WriteRequest(const Packet & val,WriteRequestType request_type,WireMessage * associated_wire_message)1046 BluetoothLowEnergyWeaveClientConnection::WriteRequest::WriteRequest(
1047 const Packet& val,
1048 WriteRequestType request_type,
1049 WireMessage* associated_wire_message)
1050 : value(val),
1051 request_type(request_type),
1052 associated_wire_message(associated_wire_message) {}
1053
WriteRequest(const Packet & val,WriteRequestType request_type)1054 BluetoothLowEnergyWeaveClientConnection::WriteRequest::WriteRequest(
1055 const Packet& val,
1056 WriteRequestType request_type)
1057 : WriteRequest(val, request_type, nullptr /* associated_wire_message */) {}
1058
~WriteRequest()1059 BluetoothLowEnergyWeaveClientConnection::WriteRequest::~WriteRequest() {}
1060
1061 } // namespace weave
1062
1063 } // namespace secure_channel
1064
1065 } // namespace chromeos
1066