Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: chromeos/components/tether/ble_connection_manager.cc

Issue 2697763002: [CrOS Tether]: Create BleConnectionManager, which manages secure connections between the current de… (Closed)
Patch Set: Add missing DEP. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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/components/tether/ble_connection_manager.h"
6
7 #include "chromeos/components/tether/ble_constants.h"
8 #include "components/cryptauth/ble/bluetooth_low_energy_weave_client_connection. h"
9 #include "components/proximity_auth/logging/logging.h"
10 #include "device/bluetooth/bluetooth_uuid.h"
11
12 namespace chromeos {
13
14 namespace tether {
15
16 namespace {
17 const char kTetherFeature[] = "magic_tether";
18 } // namespace
19
20 const int64_t BleConnectionManager::kAdvertisingTimeoutMillis = 12000;
21 const int64_t BleConnectionManager::kFailImmediatelyTimeoutMillis = 0;
22
23 // static
24 std::string BleConnectionManager::MessageTypeToString(
25 const MessageType& reason) {
26 switch (reason) {
27 case MessageType::TETHER_AVAILABILITY_REQUEST:
28 return "[TetherAvailabilityRequest]";
29 case MessageType::CONNECT_TETHERING_REQUEST:
30 return "[ConnectTetheringRequest]";
31 case MessageType::KEEP_ALIVE_TICKLE:
32 return "[KeepAliveTickle]";
33 case MessageType::DISCONNECT_TETHERING_REQUEST:
34 return "[DisconnectTetheringRequest]";
35 default:
36 return "[invalid MessageType]";
37 }
38 }
39
40 BleConnectionManager::ConnectionMetadata::ConnectionMetadata(
41 const cryptauth::RemoteDevice remote_device,
42 std::shared_ptr<base::Timer> timer,
43 base::WeakPtr<BleConnectionManager> manager)
44 : remote_device_(remote_device),
45 connection_attempt_timeout_timer_(timer),
46 manager_(manager),
47 weak_ptr_factory_(this) {}
48
49 BleConnectionManager::ConnectionMetadata::~ConnectionMetadata() {}
50
51 void BleConnectionManager::ConnectionMetadata::RegisterConnectionReason(
52 const MessageType& connection_reason) {
53 active_connection_reasons_.insert(connection_reason);
54 }
55
56 void BleConnectionManager::ConnectionMetadata::UnregisterConnectionReason(
57 const MessageType& connection_reason) {
58 active_connection_reasons_.erase(connection_reason);
59 }
60
61 bool BleConnectionManager::ConnectionMetadata::HasReasonForConnection() const {
62 return !active_connection_reasons_.empty();
63 }
64
65 bool BleConnectionManager::ConnectionMetadata::HasEstablishedConnection()
66 const {
67 return secure_channel_.get();
68 }
69
70 cryptauth::SecureChannel::Status
71 BleConnectionManager::ConnectionMetadata::GetStatus() const {
72 if (connection_attempt_timeout_timer_->IsRunning()) {
73 // If the timer is running, a connection attempt is in progress but a
74 // channel has not been established.
75 return cryptauth::SecureChannel::Status::CONNECTING;
76 } else if (!HasEstablishedConnection()) {
77 // If there is no timer and a channel has not been established, the channel
78 // is disconnected.
79 return cryptauth::SecureChannel::Status::DISCONNECTED;
80 }
81
82 // If a channel has been established, return its status.
83 return secure_channel_->status();
84 }
85
86 void BleConnectionManager::ConnectionMetadata::StartConnectionAttemptTimer(
87 bool fail_immediately) {
88 DCHECK(!secure_channel_);
89 DCHECK(!connection_attempt_timeout_timer_->IsRunning());
90
91 int64_t timeout_millis = fail_immediately ? kFailImmediatelyTimeoutMillis
92 : kAdvertisingTimeoutMillis;
93
94 connection_attempt_timeout_timer_->Start(
95 FROM_HERE, base::TimeDelta::FromMilliseconds(timeout_millis),
96 base::Bind(&ConnectionMetadata::OnConnectionAttemptTimeout,
97 weak_ptr_factory_.GetWeakPtr()));
98 }
99
100 void BleConnectionManager::ConnectionMetadata::OnConnectionAttemptTimeout() {
101 manager_->OnConnectionAttemptTimeout(remote_device_);
102 }
103
104 void BleConnectionManager::ConnectionMetadata::SetSecureChannel(
105 std::unique_ptr<cryptauth::SecureChannel> secure_channel) {
106 DCHECK(!secure_channel_);
107
108 // The connection has succeeded, so cancel the timeout.
109 connection_attempt_timeout_timer_->Stop();
110
111 secure_channel_ = std::move(secure_channel);
112 secure_channel_->AddObserver(this);
113 secure_channel_->Initialize();
114 }
115
116 void BleConnectionManager::ConnectionMetadata::SendMessage(
117 const std::string& payload) {
118 DCHECK(GetStatus() == cryptauth::SecureChannel::Status::AUTHENTICATED);
119 secure_channel_->SendMessage(std::string(kTetherFeature), payload);
120 }
121
122 void BleConnectionManager::ConnectionMetadata::OnSecureChannelStatusChanged(
123 cryptauth::SecureChannel* secure_channel,
124 const cryptauth::SecureChannel::Status& old_status,
125 const cryptauth::SecureChannel::Status& new_status) {
126 DCHECK(secure_channel_.get() == secure_channel);
127
128 if (new_status == cryptauth::SecureChannel::Status::CONNECTING) {
129 // BleConnectionManager already broadcasts "disconnected => connecting"
130 // status updates when a connection attempt begins, so there is no need to
131 // handle this case.
132 return;
133 }
134
135 // Make a copy of the two statuses. If |secure_channel_.reset()| is called
136 // below, the SecureChannel instance will be destroyed and |old_status| and
137 // |new_status| may refer to memory which has been deleted.
138 const cryptauth::SecureChannel::Status old_status_copy = old_status;
139 const cryptauth::SecureChannel::Status new_status_copy = new_status;
140
141 if (new_status == cryptauth::SecureChannel::Status::DISCONNECTED) {
142 secure_channel_->RemoveObserver(this);
143 secure_channel_.reset();
144 }
145
146 manager_->OnSecureChannelStatusChanged(remote_device_, old_status_copy,
147 new_status_copy);
148 }
149
150 void BleConnectionManager::ConnectionMetadata::OnMessageReceived(
151 cryptauth::SecureChannel* secure_channel,
152 const std::string& feature,
153 const std::string& payload) {
154 DCHECK(secure_channel_.get() == secure_channel);
155 if (feature != std::string(kTetherFeature)) {
156 // If the message received was not a tether feature, ignore it.
157 return;
158 }
159
160 manager_->SendMessageReceivedEvent(remote_device_, payload);
161 }
162
163 std::unique_ptr<base::Timer> BleConnectionManager::TimerFactory::CreateTimer() {
164 return base::MakeUnique<base::OneShotTimer>();
165 }
166
167 BleConnectionManager::BleConnectionManager(
168 std::unique_ptr<Delegate> delegate,
169 scoped_refptr<device::BluetoothAdapter> adapter,
170 const LocalDeviceDataProvider* local_device_data_provider,
171 const cryptauth::RemoteBeaconSeedFetcher* remote_beacon_seed_fetcher,
172 cryptauth::BluetoothThrottler* bluetooth_throttler)
173 : BleConnectionManager(
174 std::move(delegate),
175 adapter,
176 // TODO(khorimoto): Inject |adapter| into |BleScanner|.
177 base::MakeUnique<BleScanner>(local_device_data_provider),
178 base::MakeUnique<BleAdvertiser>(adapter,
179 local_device_data_provider,
180 remote_beacon_seed_fetcher),
181 base::MakeUnique<BleAdvertisementDeviceQueue>(),
182 base::WrapUnique<TimerFactory>(new TimerFactory()),
183 bluetooth_throttler) {}
184
185 BleConnectionManager::BleConnectionManager(
186 std::unique_ptr<Delegate> delegate,
187 scoped_refptr<device::BluetoothAdapter> adapter,
188 std::unique_ptr<BleScanner> ble_scanner,
189 std::unique_ptr<BleAdvertiser> ble_advertiser,
190 std::unique_ptr<BleAdvertisementDeviceQueue> device_queue,
191 std::unique_ptr<TimerFactory> timer_factory,
192 cryptauth::BluetoothThrottler* bluetooth_throttler)
193 : delegate_(std::move(delegate)),
194 adapter_(adapter),
195 ble_scanner_(std::move(ble_scanner)),
196 ble_advertiser_(std::move(ble_advertiser)),
197 device_queue_(std::move(device_queue)),
198 timer_factory_(std::move(timer_factory)),
199 bluetooth_throttler_(bluetooth_throttler),
200 weak_ptr_factory_(this) {
201 ble_scanner_->AddObserver(this);
202 }
203
204 BleConnectionManager::~BleConnectionManager() {
205 ble_scanner_->RemoveObserver(this);
206 }
207
208 void BleConnectionManager::RegisterRemoteDevice(
209 const cryptauth::RemoteDevice& remote_device,
210 const MessageType& connection_reason) {
211 PA_LOG(INFO) << "Registering device with ID "
212 << remote_device.GetTruncatedDeviceIdForLogs() << " for reason "
213 << MessageTypeToString(connection_reason);
214
215 std::shared_ptr<ConnectionMetadata> connection_metadata =
216 GetConnectionMetadata(remote_device);
217 if (!connection_metadata) {
218 connection_metadata = AddMetadataForDevice(remote_device);
219 }
220
221 connection_metadata->RegisterConnectionReason(connection_reason);
222 UpdateConnectionAttempts();
223 }
224
225 void BleConnectionManager::UnregisterRemoteDevice(
226 const cryptauth::RemoteDevice& remote_device,
227 const MessageType& connection_reason) {
228 PA_LOG(INFO) << "Unregistering device with ID "
229 << remote_device.GetTruncatedDeviceIdForLogs() << " for reason "
230 << MessageTypeToString(connection_reason);
231
232 std::shared_ptr<ConnectionMetadata> connection_metadata =
233 GetConnectionMetadata(remote_device);
234 if (!connection_metadata) {
235 // If the device was not registered, there is nothing to do.
236 return;
237 }
238
239 connection_metadata->UnregisterConnectionReason(connection_reason);
240 if (!connection_metadata->HasReasonForConnection()) {
241 cryptauth::SecureChannel::Status status_before_disconnect =
242 connection_metadata->GetStatus();
243 device_to_metadata_map_.erase(remote_device);
244 if (status_before_disconnect ==
245 cryptauth::SecureChannel::Status::CONNECTING) {
246 StopConnectionAttemptAndMoveToEndOfQueue(remote_device);
247 }
248 if (status_before_disconnect !=
249 cryptauth::SecureChannel::Status::DISCONNECTED) {
250 // Send a status update for the disconnection.
251 SendSecureChannelStatusChangeEvent(
252 remote_device, status_before_disconnect,
253 cryptauth::SecureChannel::Status::DISCONNECTED);
254 }
255 }
256
257 UpdateConnectionAttempts();
258 }
259
260 void BleConnectionManager::SendMessage(
261 const cryptauth::RemoteDevice& remote_device,
262 const std::string& message) {
263 std::shared_ptr<ConnectionMetadata> connection_metadata =
264 GetConnectionMetadata(remote_device);
265 if (!connection_metadata ||
266 connection_metadata->GetStatus() !=
267 cryptauth::SecureChannel::Status::AUTHENTICATED) {
268 PA_LOG(ERROR) << "Attempted to send a message to device with ID "
269 << remote_device.GetTruncatedDeviceIdForLogs() << ". "
270 << "Message: \"" << message << "\"";
271 return;
272 }
273
274 PA_LOG(INFO) << "Sending message to device with ID "
275 << remote_device.GetTruncatedDeviceIdForLogs() << ". "
276 << "Message: \"" << message << "\"";
277 connection_metadata->SendMessage(message);
278 }
279
280 void BleConnectionManager::AddObserver(Observer* observer) {
281 observer_list_.AddObserver(observer);
282 }
283
284 void BleConnectionManager::RemoveObserver(Observer* observer) {
285 observer_list_.RemoveObserver(observer);
286 }
287
288 void BleConnectionManager::OnReceivedAdvertisementFromDevice(
289 const std::string& device_address,
290 cryptauth::RemoteDevice remote_device) {
291 std::shared_ptr<ConnectionMetadata> connection_metadata =
292 GetConnectionMetadata(remote_device);
293 if (!connection_metadata) {
294 // If an advertisement is received from a device that is not registered,
295 // ignore it.
296 PA_LOG(WARNING) << "Received an advertisement from a device which is not "
297 << "registered. Bluetooth address: " << device_address
298 << ", Remote Device ID: " << remote_device.GetDeviceId();
299 return;
300 }
301
302 PA_LOG(INFO) << "Received advertisement from device with ID "
303 << remote_device.GetTruncatedDeviceIdForLogs() << ". "
304 << "Starting authentication handshake to that device.";
305
306 // Create a connection to that device.
307 std::unique_ptr<cryptauth::Connection> connection =
308 cryptauth::weave::BluetoothLowEnergyWeaveClientConnection::Factory::
309 NewInstance(remote_device, device_address, adapter_,
310 device::BluetoothUUID(std::string(kGattServerUuid)),
311 bluetooth_throttler_);
312 std::unique_ptr<cryptauth::SecureChannel> secure_channel =
313 cryptauth::SecureChannel::Factory::NewInstance(
314 std::move(connection), delegate_->CreateSecureChannelDelegate());
315 connection_metadata->SetSecureChannel(std::move(secure_channel));
316
317 // Stop trying to connect to that device, since a connection already exists.
318 StopConnectionAttemptAndMoveToEndOfQueue(remote_device);
319 UpdateConnectionAttempts();
320 }
321
322 std::shared_ptr<BleConnectionManager::ConnectionMetadata>
323 BleConnectionManager::GetConnectionMetadata(
324 const cryptauth::RemoteDevice& remote_device) {
325 const auto map_iter = device_to_metadata_map_.find(remote_device);
326 if (map_iter == device_to_metadata_map_.end()) {
327 return nullptr;
328 }
329
330 return map_iter->second;
331 }
332
333 std::shared_ptr<BleConnectionManager::ConnectionMetadata>
334 BleConnectionManager::AddMetadataForDevice(
335 const cryptauth::RemoteDevice& remote_device) {
336 std::shared_ptr<ConnectionMetadata> existing_data =
337 GetConnectionMetadata(remote_device);
338 if (existing_data) {
339 return existing_data;
340 }
341
342 std::unique_ptr<base::Timer> timer = timer_factory_->CreateTimer();
343 device_to_metadata_map_.insert(
344 std::pair<cryptauth::RemoteDevice, std::shared_ptr<ConnectionMetadata>>(
345 remote_device,
346 std::shared_ptr<ConnectionMetadata>(
347 new ConnectionMetadata(remote_device, std::move(timer),
348 weak_ptr_factory_.GetWeakPtr()))));
349 return device_to_metadata_map_.at(remote_device);
350 }
351
352 void BleConnectionManager::UpdateConnectionAttempts() {
353 UpdateAdvertisementQueue();
354
355 std::vector<cryptauth::RemoteDevice> should_advertise_to =
356 device_queue_->GetDevicesToWhichToAdvertise();
357 DCHECK(should_advertise_to.size() <=
358 static_cast<size_t>(kMaxConcurrentAdvertisements));
359
360 for (const auto& remote_device : should_advertise_to) {
361 std::shared_ptr<ConnectionMetadata> associated_data =
362 GetConnectionMetadata(remote_device);
363 if (associated_data->GetStatus() !=
364 cryptauth::SecureChannel::Status::CONNECTING) {
365 // If there is no active attempt to connect to a device at the front of
366 // the queue, start a connection attempt.
367 StartConnectionAttempt(remote_device);
368 }
369 }
370 }
371
372 void BleConnectionManager::UpdateAdvertisementQueue() {
373 std::vector<cryptauth::RemoteDevice> devices_for_queue;
374 for (const auto& map_entry : device_to_metadata_map_) {
375 if (map_entry.second->HasEstablishedConnection()) {
376 // If there is already an active connection to the device, there is no
377 // need to advertise to the device to bootstrap a connection.
378 continue;
379 }
380
381 devices_for_queue.push_back(map_entry.first);
382 }
383
384 device_queue_->SetDevices(devices_for_queue);
385 }
386
387 void BleConnectionManager::StartConnectionAttempt(
388 const cryptauth::RemoteDevice& remote_device) {
389 std::shared_ptr<ConnectionMetadata> connection_metadata =
390 GetConnectionMetadata(remote_device);
391 DCHECK(connection_metadata);
392
393 PA_LOG(INFO) << "Starting connection attempt to device with ID "
394 << remote_device.GetTruncatedDeviceIdForLogs();
395
396 // Send a "disconnected => connecting" update to alert clients that a
397 // connection attempt for |remote_device| is underway.
398 SendSecureChannelStatusChangeEvent(
399 remote_device, cryptauth::SecureChannel::Status::DISCONNECTED,
400 cryptauth::SecureChannel::Status::CONNECTING);
401
402 bool success = ble_scanner_->RegisterScanFilterForDevice(remote_device) &&
403 ble_advertiser_->StartAdvertisingToDevice(remote_device);
404
405 // Start a timer; if a connection is unable to be created before the timer
406 // fires, a timeout occurs. Note that if this class is unable to start both
407 // the scanner and advertiser successfully (i.e., |success| is |false|), a
408 // the connection fails immediately insetad of waiting for a timeout, which
409 // has the effect of quickly sending out "disconnected => connecting =>
410 // disconnecting" status updates. The timer is used here instead of a special
411 // case in order to route all connection failures through the same code path.
412 connection_metadata->StartConnectionAttemptTimer(
413 !success /* fail_immediately */);
414 }
415
416 void BleConnectionManager::StopConnectionAttemptAndMoveToEndOfQueue(
417 const cryptauth::RemoteDevice& remote_device) {
418 PA_LOG(INFO) << "Stopping connection attempt to device with ID "
419 << remote_device.GetTruncatedDeviceIdForLogs();
420
421 ble_scanner_->UnregisterScanFilterForDevice(remote_device);
422 ble_advertiser_->StopAdvertisingToDevice(remote_device);
423
424 device_queue_->MoveDeviceToEnd(remote_device.GetDeviceId());
425 }
426
427 void BleConnectionManager::OnConnectionAttemptTimeout(
428 const cryptauth::RemoteDevice& remote_device) {
429 PA_LOG(INFO) << "Connection attempt timed out for device with ID "
430 << remote_device.GetTruncatedDeviceIdForLogs();
431
432 StopConnectionAttemptAndMoveToEndOfQueue(remote_device);
433
434 // Send a "connecting => disconnected" update to alert clients that a
435 // connection attempt for |remote_device| has failed.
436 SendSecureChannelStatusChangeEvent(
437 remote_device, cryptauth::SecureChannel::Status::CONNECTING,
438 cryptauth::SecureChannel::Status::DISCONNECTED);
439
440 UpdateConnectionAttempts();
441 }
442
443 void BleConnectionManager::OnSecureChannelStatusChanged(
444 const cryptauth::RemoteDevice& remote_device,
445 const cryptauth::SecureChannel::Status& old_status,
446 const cryptauth::SecureChannel::Status& new_status) {
447 SendSecureChannelStatusChangeEvent(remote_device, old_status, new_status);
448 UpdateConnectionAttempts();
449 }
450
451 void BleConnectionManager::SendMessageReceivedEvent(
452 const cryptauth::RemoteDevice& remote_device,
453 const std::string& payload) {
454 PA_LOG(INFO) << "Broadcasting message received event: "
455 << "Device ID \"" << remote_device.GetTruncatedDeviceIdForLogs()
456 << "\" received message \"" << payload << "\".";
457 for (auto& observer : observer_list_) {
458 observer.OnMessageReceived(remote_device, payload);
459 }
460 }
461
462 void BleConnectionManager::SendSecureChannelStatusChangeEvent(
463 const cryptauth::RemoteDevice& remote_device,
464 const cryptauth::SecureChannel::Status& old_status,
465 const cryptauth::SecureChannel::Status& new_status) {
466 PA_LOG(INFO) << "Broadcasting status change event: "
467 << "Device ID \"" << remote_device.GetTruncatedDeviceIdForLogs()
468 << "\": " << cryptauth::SecureChannel::StatusToString(old_status)
469 << " => "
470 << cryptauth::SecureChannel::StatusToString(new_status);
471 for (auto& observer : observer_list_) {
472 observer.OnSecureChannelStatusChanged(remote_device, old_status,
473 new_status);
474 }
475 }
476
477 } // namespace tether
478
479 } // namespace chromeos
OLDNEW
« no previous file with comments | « chromeos/components/tether/ble_connection_manager.h ('k') | chromeos/components/tether/ble_connection_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698