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