| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromeos/components/tether/ble_connection_manager.h" |
| |
| #include "base/memory/ptr_util.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "chromeos/components/proximity_auth/logging/logging.h" |
| #include "chromeos/components/tether/timer_factory.h" |
| #include "chromeos/services/secure_channel/ble_constants.h" |
| #include "components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h" |
| #include "components/cryptauth/remote_device_ref.h" |
| #include "device/bluetooth/bluetooth_uuid.h" |
| |
| namespace chromeos { |
| |
| namespace tether { |
| |
| namespace { |
| |
| const char kTetherFeature[] = "magic_tether"; |
| |
| std::string StateChangeDetailToString( |
| BleConnectionManager::StateChangeDetail state_change_detail) { |
| switch (state_change_detail) { |
| case BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE: |
| return "[none]"; |
| case BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_COULD_NOT_ATTEMPT_CONNECTION: |
| return "[could not attempt connection]"; |
| case BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_GATT_CONNECTION_WAS_ATTEMPTED: |
| return "[GATT connection was attempted]"; |
| case BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_INTERRUPTED_BY_HIGHER_PRIORITY: |
| return "[attempt interrupted by higher priority]"; |
| case BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED: |
| return "[device was unregistered]"; |
| default: |
| NOTREACHED(); |
| return std::string(); |
| } |
| } |
| |
| } // namespace |
| |
| const int64_t BleConnectionManager::kAdvertisingTimeoutMillis = 12000; |
| const int64_t BleConnectionManager::kFailImmediatelyTimeoutMillis = 0; |
| |
| BleConnectionManager::ConnectionMetadata::ConnectionMetadata( |
| const std::string& device_id, |
| std::unique_ptr<base::OneShotTimer> timer, |
| base::WeakPtr<BleConnectionManager> manager) |
| : device_id_(device_id), |
| connection_attempt_timeout_timer_(std::move(timer)), |
| manager_(manager), |
| weak_ptr_factory_(this) {} |
| |
| BleConnectionManager::ConnectionMetadata::~ConnectionMetadata() = default; |
| |
| void BleConnectionManager::ConnectionMetadata::RegisterConnectionRequest( |
| const base::UnguessableToken& request_id, |
| secure_channel::ConnectionPriority connection_priority) { |
| DCHECK(!base::ContainsKey(request_id_to_priority_map_, request_id)); |
| request_id_to_priority_map_.insert( |
| std::make_pair(request_id, connection_priority)); |
| } |
| |
| void BleConnectionManager::ConnectionMetadata::UnregisterConnectionRequest( |
| const base::UnguessableToken& request_id) { |
| request_id_to_priority_map_.erase(request_id); |
| } |
| |
| secure_channel::ConnectionPriority |
| BleConnectionManager::ConnectionMetadata::GetConnectionPriority() { |
| DCHECK(HasPendingConnectionRequests()); |
| |
| secure_channel::ConnectionPriority highest_priority = |
| secure_channel::ConnectionPriority::kLow; |
| for (const auto& map_entry : request_id_to_priority_map_) { |
| if (map_entry.second > highest_priority) |
| highest_priority = map_entry.second; |
| } |
| |
| return highest_priority; |
| } |
| |
| bool BleConnectionManager::ConnectionMetadata::HasPendingConnectionRequests() |
| const { |
| return !request_id_to_priority_map_.empty(); |
| } |
| |
| bool BleConnectionManager::ConnectionMetadata::HasEstablishedConnection() |
| const { |
| return secure_channel_.get(); |
| } |
| |
| cryptauth::SecureChannel::Status |
| BleConnectionManager::ConnectionMetadata::GetStatus() const { |
| if (connection_attempt_timeout_timer_->IsRunning()) { |
| // If the timer is running, a connection attempt is in progress but a |
| // channel has not been established. |
| return cryptauth::SecureChannel::Status::CONNECTING; |
| } else if (!HasEstablishedConnection()) { |
| // If there is no timer and a channel has not been established, the channel |
| // is disconnected. |
| return cryptauth::SecureChannel::Status::DISCONNECTED; |
| } |
| |
| // If a channel has been established, return its status. |
| return secure_channel_->status(); |
| } |
| |
| void BleConnectionManager::ConnectionMetadata::StartConnectionAttemptTimer( |
| bool fail_immediately) { |
| DCHECK(!secure_channel_); |
| DCHECK(!connection_attempt_timeout_timer_->IsRunning()); |
| |
| int64_t timeout_millis = fail_immediately ? kFailImmediatelyTimeoutMillis |
| : kAdvertisingTimeoutMillis; |
| |
| connection_attempt_timeout_timer_->Start( |
| FROM_HERE, base::TimeDelta::FromMilliseconds(timeout_millis), |
| base::Bind(&ConnectionMetadata::OnConnectionAttemptTimeout, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void BleConnectionManager::ConnectionMetadata::StopConnectionAttemptTimer() { |
| DCHECK(!secure_channel_); |
| connection_attempt_timeout_timer_->Stop(); |
| } |
| |
| void BleConnectionManager::ConnectionMetadata::OnConnectionAttemptTimeout() { |
| manager_->OnConnectionAttemptTimeout(device_id_); |
| } |
| |
| bool BleConnectionManager::ConnectionMetadata::HasSecureChannel() { |
| return secure_channel_ != nullptr; |
| } |
| |
| void BleConnectionManager::ConnectionMetadata::SetSecureChannel( |
| std::unique_ptr<cryptauth::SecureChannel> secure_channel) { |
| DCHECK(!secure_channel_); |
| |
| // The connection has succeeded, so cancel the timeout. |
| connection_attempt_timeout_timer_->Stop(); |
| |
| secure_channel_ = std::move(secure_channel); |
| secure_channel_->AddObserver(this); |
| secure_channel_->Initialize(); |
| } |
| |
| int BleConnectionManager::ConnectionMetadata::SendMessage( |
| const std::string& payload) { |
| DCHECK(GetStatus() == cryptauth::SecureChannel::Status::AUTHENTICATED); |
| return secure_channel_->SendMessage(std::string(kTetherFeature), payload); |
| } |
| |
| void BleConnectionManager::ConnectionMetadata::Disconnect() { |
| DCHECK(HasSecureChannel()); |
| secure_channel_->Disconnect(); |
| } |
| |
| void BleConnectionManager::ConnectionMetadata::OnSecureChannelStatusChanged( |
| cryptauth::SecureChannel* secure_channel, |
| const cryptauth::SecureChannel::Status& old_status, |
| const cryptauth::SecureChannel::Status& new_status) { |
| DCHECK(secure_channel_.get() == secure_channel); |
| |
| if (new_status == cryptauth::SecureChannel::Status::CONNECTING) { |
| // BleConnectionManager already broadcasts "disconnected => connecting" |
| // status updates when a connection attempt begins, so there is no need to |
| // handle this case. |
| return; |
| } |
| |
| // Make a copy of the two statuses. If |secure_channel_.reset()| is called |
| // below, the SecureChannel instance will be destroyed and |old_status| and |
| // |new_status| may refer to memory which has been deleted. |
| const cryptauth::SecureChannel::Status old_status_copy = old_status; |
| const cryptauth::SecureChannel::Status new_status_copy = new_status; |
| |
| StateChangeDetail state_change_detail = |
| StateChangeDetail::STATE_CHANGE_DETAIL_NONE; |
| |
| if (new_status == cryptauth::SecureChannel::Status::DISCONNECTED) { |
| secure_channel_->RemoveObserver(this); |
| secure_channel_.reset(); |
| state_change_detail = |
| StateChangeDetail::STATE_CHANGE_DETAIL_GATT_CONNECTION_WAS_ATTEMPTED; |
| } |
| |
| manager_->OnSecureChannelStatusChanged(device_id_, old_status_copy, |
| new_status_copy, state_change_detail); |
| } |
| |
| void BleConnectionManager::ConnectionMetadata::OnMessageReceived( |
| cryptauth::SecureChannel* secure_channel, |
| const std::string& feature, |
| const std::string& payload) { |
| DCHECK(secure_channel_.get() == secure_channel); |
| if (feature != std::string(kTetherFeature)) { |
| // If the message received was not a tether feature, ignore it. |
| return; |
| } |
| |
| manager_->NotifyMessageReceived(device_id_, payload); |
| } |
| |
| void BleConnectionManager::ConnectionMetadata::OnMessageSent( |
| cryptauth::SecureChannel* secure_channel, |
| int sequence_number) { |
| DCHECK(secure_channel_.get() == secure_channel); |
| PA_LOG(INFO) << "Message sent successfully to device with ID \"" |
| << cryptauth::RemoteDeviceRef::TruncateDeviceIdForLogs( |
| device_id_) |
| << "\"; message sequence number: " << sequence_number; |
| manager_->NotifyMessageSent(sequence_number); |
| } |
| |
| BleConnectionManager::BleConnectionManager( |
| scoped_refptr<device::BluetoothAdapter> adapter, |
| BleAdvertisementDeviceQueue* ble_advertisement_device_queue, |
| BleAdvertiser* ble_advertiser, |
| BleScanner* ble_scanner) |
| : adapter_(adapter), |
| ble_advertisement_device_queue_(ble_advertisement_device_queue), |
| ble_advertiser_(ble_advertiser), |
| ble_scanner_(ble_scanner), |
| timer_factory_(std::make_unique<TimerFactory>()), |
| has_registered_observer_(false), |
| weak_ptr_factory_(this) {} |
| |
| BleConnectionManager::~BleConnectionManager() { |
| if (has_registered_observer_) { |
| ble_scanner_->RemoveObserver(this); |
| } |
| } |
| |
| void BleConnectionManager::RegisterRemoteDevice( |
| const std::string& device_id, |
| const base::UnguessableToken& request_id, |
| secure_channel::ConnectionPriority connection_priority) { |
| if (!has_registered_observer_) { |
| ble_scanner_->AddObserver(this); |
| } |
| has_registered_observer_ = true; |
| |
| PA_LOG(INFO) << "Register - Device ID: \"" |
| << cryptauth::RemoteDeviceRef::TruncateDeviceIdForLogs(device_id) |
| << "\", Request ID: " << request_id |
| << ", Priority: " << connection_priority; |
| |
| ConnectionMetadata* connection_metadata = GetConnectionMetadata(device_id); |
| if (!connection_metadata) |
| connection_metadata = AddMetadataForDevice(device_id); |
| |
| connection_metadata->RegisterConnectionRequest(request_id, |
| connection_priority); |
| UpdateConnectionAttempts(); |
| } |
| |
| void BleConnectionManager::UnregisterRemoteDevice( |
| const std::string& device_id, |
| const base::UnguessableToken& request_id) { |
| ConnectionMetadata* connection_metadata = GetConnectionMetadata(device_id); |
| if (!connection_metadata) { |
| PA_LOG(WARNING) << "Tried to unregister device, but was not registered - " |
| << "Device ID: \"" |
| << cryptauth::RemoteDeviceRef::TruncateDeviceIdForLogs( |
| device_id) |
| << "\", Request ID: " << request_id; |
| return; |
| } |
| |
| PA_LOG(INFO) << "Unregister - Device ID: \"" |
| << cryptauth::RemoteDeviceRef::TruncateDeviceIdForLogs(device_id) |
| << "\", Request ID: " << request_id; |
| |
| connection_metadata->UnregisterConnectionRequest(request_id); |
| if (!connection_metadata->HasPendingConnectionRequests()) { |
| if (connection_metadata->HasEstablishedConnection()) { |
| connection_metadata->Disconnect(); |
| } else { |
| // |device_id| references memory that will be deleted below; make a copy. |
| const std::string device_id_copy = device_id; |
| cryptauth::SecureChannel::Status status_before_erase = |
| connection_metadata->GetStatus(); |
| device_id_to_metadata_map_.erase(device_id_copy); |
| |
| if (status_before_erase == cryptauth::SecureChannel::Status::CONNECTING) { |
| StopConnectionAttemptAndMoveToEndOfQueue(device_id_copy); |
| NotifySecureChannelStatusChanged( |
| device_id_copy, cryptauth::SecureChannel::Status::CONNECTING, |
| cryptauth::SecureChannel::Status::DISCONNECTED, |
| StateChangeDetail::STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED); |
| } |
| } |
| } |
| |
| UpdateConnectionAttempts(); |
| } |
| |
| int BleConnectionManager::SendMessage(const std::string& device_id, |
| const std::string& message) { |
| ConnectionMetadata* connection_metadata = GetConnectionMetadata(device_id); |
| if (!connection_metadata || |
| connection_metadata->GetStatus() != |
| cryptauth::SecureChannel::Status::AUTHENTICATED) { |
| PA_LOG(ERROR) << "SendMessage(): Error - no authenticated channel. " |
| << "Device ID: \"" |
| << cryptauth::RemoteDeviceRef::TruncateDeviceIdForLogs( |
| device_id) |
| << "\", Message: \"" << message << "\""; |
| return -1; |
| } |
| |
| PA_LOG(INFO) << "SendMessage(): Device ID: \"" |
| << cryptauth::RemoteDeviceRef::TruncateDeviceIdForLogs(device_id) |
| << "\", Message: \"" << message << "\""; |
| return connection_metadata->SendMessage(message); |
| } |
| |
| bool BleConnectionManager::GetStatusForDevice( |
| const std::string& device_id, |
| cryptauth::SecureChannel::Status* status) const { |
| ConnectionMetadata* connection_metadata = GetConnectionMetadata(device_id); |
| if (!connection_metadata) |
| return false; |
| |
| *status = connection_metadata->GetStatus(); |
| return true; |
| } |
| |
| void BleConnectionManager::AddObserver(Observer* observer) { |
| observer_list_.AddObserver(observer); |
| } |
| |
| void BleConnectionManager::RemoveObserver(Observer* observer) { |
| observer_list_.RemoveObserver(observer); |
| } |
| |
| void BleConnectionManager::AddMetricsObserver(MetricsObserver* observer) { |
| metrics_observer_list_.AddObserver(observer); |
| } |
| |
| void BleConnectionManager::RemoveMetricsObserver(MetricsObserver* observer) { |
| metrics_observer_list_.RemoveObserver(observer); |
| } |
| |
| void BleConnectionManager::OnReceivedAdvertisementFromDevice( |
| cryptauth::RemoteDeviceRef remote_device, |
| device::BluetoothDevice* bluetooth_device, |
| bool is_background_advertisement) { |
| const std::string device_id = remote_device.GetDeviceId(); |
| |
| ConnectionMetadata* connection_metadata = GetConnectionMetadata(device_id); |
| if (!connection_metadata) { |
| // If an advertisement is received from a device that is not registered, |
| // ignore it. |
| PA_LOG(WARNING) << "Received an advertisement from a device which is not " |
| << "registered. Bluetooth address: " |
| << bluetooth_device->GetAddress() << ", Remote Device " |
| << "ID: \"" << remote_device.GetTruncatedDeviceIdForLogs() |
| << "\"."; |
| return; |
| } |
| |
| if (connection_metadata->HasSecureChannel()) { |
| PA_LOG(WARNING) << "Received another advertisement from a registered " |
| << "device which is already being actively communicated " |
| << "with. Bluetooth address: " |
| << bluetooth_device->GetAddress() << ", Remote Device " |
| << "ID: \"" << remote_device.GetTruncatedDeviceIdForLogs() |
| << "\"."; |
| return; |
| } |
| |
| PA_LOG(INFO) << "Received advertisement - Device ID: \"" |
| << remote_device.GetTruncatedDeviceIdForLogs() |
| << "\". Starting authentication handshake."; |
| |
| device_id_to_is_background_advertisement_map_[device_id] = |
| is_background_advertisement; |
| NotifyAdvertisementReceived(device_id, is_background_advertisement); |
| |
| // Stop trying to connect to that device, since it has been found. |
| StopConnectionAttemptAndMoveToEndOfQueue(device_id); |
| |
| // Create a connection to that device. |
| std::unique_ptr<cryptauth::Connection> connection = cryptauth::weave:: |
| BluetoothLowEnergyWeaveClientConnection::Factory::NewInstance( |
| remote_device, adapter_, |
| device::BluetoothUUID(secure_channel::kGattServerUuid), |
| bluetooth_device, false /* should_set_low_connection_latency */); |
| std::unique_ptr<cryptauth::SecureChannel> secure_channel = |
| cryptauth::SecureChannel::Factory::NewInstance(std::move(connection)); |
| connection_metadata->SetSecureChannel(std::move(secure_channel)); |
| |
| UpdateConnectionAttempts(); |
| } |
| |
| BleConnectionManager::ConnectionMetadata* |
| BleConnectionManager::GetConnectionMetadata( |
| const std::string& device_id) const { |
| const auto map_iter = device_id_to_metadata_map_.find(device_id); |
| if (map_iter == device_id_to_metadata_map_.end()) |
| return nullptr; |
| |
| return map_iter->second.get(); |
| } |
| |
| BleConnectionManager::ConnectionMetadata* |
| BleConnectionManager::AddMetadataForDevice(const std::string& device_id) { |
| ConnectionMetadata* existing_data = GetConnectionMetadata(device_id); |
| if (existing_data) |
| return existing_data; |
| |
| // Create the metadata. |
| std::unique_ptr<ConnectionMetadata> metadata = base::WrapUnique( |
| new ConnectionMetadata(device_id, timer_factory_->CreateOneShotTimer(), |
| weak_ptr_factory_.GetWeakPtr())); |
| ConnectionMetadata* metadata_raw_ptr = metadata.get(); |
| |
| // Add it to the map. |
| device_id_to_metadata_map_.emplace( |
| std::pair<std::string, std::unique_ptr<ConnectionMetadata>>( |
| device_id, std::move(metadata))); |
| |
| return metadata_raw_ptr; |
| } |
| |
| void BleConnectionManager::UpdateConnectionAttempts() { |
| UpdateAdvertisementQueue(); |
| |
| std::vector<std::string> should_advertise_to = |
| ble_advertisement_device_queue_->GetDeviceIdsToWhichToAdvertise(); |
| DCHECK(should_advertise_to.size() <= |
| secure_channel::kMaxConcurrentAdvertisements); |
| |
| // Generate a list of devices which are advertising but are not present in |
| // |should_advertise_to|. |
| std::vector<std::string> device_ids_to_stop; |
| for (const auto& map_entry : device_id_to_metadata_map_) { |
| if (map_entry.second->GetStatus() == |
| cryptauth::SecureChannel::Status::CONNECTING && |
| !map_entry.second->HasEstablishedConnection() && |
| !base::ContainsValue(should_advertise_to, map_entry.first)) { |
| device_ids_to_stop.push_back(map_entry.first); |
| } |
| } |
| |
| // For each device that should not be advertised to, end the connection |
| // attempt. Note that this is done outside of the map iteration above because |
| // it is possible that EndSuccessfulAttempt() will cause that map to be |
| // modified during iteration. |
| for (const auto& device_id_to_stop : device_ids_to_stop) { |
| PA_LOG(INFO) << "Connection attempt for device ID \"" |
| << cryptauth::RemoteDeviceRef::TruncateDeviceIdForLogs( |
| device_id_to_stop) |
| << "\" interrupted by higher-priority connection."; |
| EndUnsuccessfulAttempt( |
| device_id_to_stop, |
| StateChangeDetail::STATE_CHANGE_DETAIL_INTERRUPTED_BY_HIGHER_PRIORITY); |
| } |
| |
| for (const auto& device_id : should_advertise_to) { |
| ConnectionMetadata* associated_data = GetConnectionMetadata(device_id); |
| if (associated_data->GetStatus() != |
| cryptauth::SecureChannel::Status::CONNECTING) { |
| // If there is no active attempt to connect to a device at the front of |
| // the queue, start a connection attempt. |
| StartConnectionAttempt(device_id); |
| } |
| } |
| } |
| |
| void BleConnectionManager::UpdateAdvertisementQueue() { |
| std::vector<BleAdvertisementDeviceQueue::PrioritizedDeviceId> prioritized_ids; |
| for (const auto& map_entry : device_id_to_metadata_map_) { |
| if (map_entry.second->HasEstablishedConnection()) { |
| // If there is already an active connection to the device, there is no |
| // need to advertise to the device to bootstrap a connection. |
| continue; |
| } |
| |
| prioritized_ids.emplace_back(map_entry.first, |
| map_entry.second->GetConnectionPriority()); |
| } |
| |
| ble_advertisement_device_queue_->SetPrioritizedDeviceIds(prioritized_ids); |
| } |
| |
| void BleConnectionManager::StartConnectionAttempt( |
| const std::string& device_id) { |
| ConnectionMetadata* connection_metadata = GetConnectionMetadata(device_id); |
| DCHECK(connection_metadata); |
| |
| PA_LOG(INFO) << "Attempting connection - Device ID: \"" |
| << cryptauth::RemoteDeviceRef::TruncateDeviceIdForLogs(device_id) |
| << "\""; |
| |
| bool success = ble_scanner_->RegisterScanFilterForDevice(device_id) && |
| ble_advertiser_->StartAdvertisingToDevice(device_id); |
| |
| // Start a timer; if a connection is unable to be created before the timer |
| // fires, a timeout occurs. Note that if this class is unable to start both |
| // the scanner and advertiser successfully (i.e., |success| is |false|), a |
| // the connection fails immediately insetad of waiting for a timeout, which |
| // has the effect of quickly sending out "disconnected => connecting => |
| // disconnecting" status updates. The timer is used here instead of a special |
| // case in order to route all connection failures through the same code path. |
| connection_metadata->StartConnectionAttemptTimer( |
| !success /* fail_immediately */); |
| |
| // Send a "disconnected => connecting" update to alert clients that a |
| // connection attempt for |device_id| is underway. |
| NotifySecureChannelStatusChanged( |
| device_id, cryptauth::SecureChannel::Status::DISCONNECTED, |
| cryptauth::SecureChannel::Status::CONNECTING, |
| StateChangeDetail::STATE_CHANGE_DETAIL_NONE); |
| } |
| |
| void BleConnectionManager::EndUnsuccessfulAttempt( |
| const std::string& device_id, |
| StateChangeDetail state_change_detail) { |
| GetConnectionMetadata(device_id)->StopConnectionAttemptTimer(); |
| StopConnectionAttemptAndMoveToEndOfQueue(device_id); |
| |
| // Send a "connecting => disconnected" update to alert clients that a |
| // connection attempt for |device_id| has failed. |
| NotifySecureChannelStatusChanged( |
| device_id, cryptauth::SecureChannel::Status::CONNECTING, |
| cryptauth::SecureChannel::Status::DISCONNECTED, state_change_detail); |
| } |
| |
| void BleConnectionManager::StopConnectionAttemptAndMoveToEndOfQueue( |
| const std::string& device_id) { |
| ble_scanner_->UnregisterScanFilterForDevice(device_id); |
| ble_advertiser_->StopAdvertisingToDevice(device_id); |
| ble_advertisement_device_queue_->MoveDeviceToEnd(device_id); |
| } |
| |
| void BleConnectionManager::OnConnectionAttemptTimeout( |
| const std::string& device_id) { |
| PA_LOG(INFO) << "Connection attempt timeout - Device ID \"" |
| << cryptauth::RemoteDeviceRef::TruncateDeviceIdForLogs(device_id) |
| << "\"."; |
| EndUnsuccessfulAttempt( |
| device_id, |
| StateChangeDetail::STATE_CHANGE_DETAIL_COULD_NOT_ATTEMPT_CONNECTION); |
| UpdateConnectionAttempts(); |
| } |
| |
| void BleConnectionManager::OnSecureChannelStatusChanged( |
| const std::string& device_id, |
| const cryptauth::SecureChannel::Status& old_status, |
| const cryptauth::SecureChannel::Status& new_status, |
| StateChangeDetail state_change_detail) { |
| ConnectionMetadata* connection_metadata = GetConnectionMetadata(device_id); |
| DCHECK(connection_metadata); |
| |
| // Create copies of the references passed to this function. If the map entry |
| // is erased below, the references will point to deleted memory. |
| const std::string device_id_copy = device_id; |
| const cryptauth::SecureChannel::Status old_status_copy = old_status; |
| const cryptauth::SecureChannel::Status new_status_copy = new_status; |
| |
| if (!connection_metadata->HasPendingConnectionRequests() && |
| new_status == cryptauth::SecureChannel::Status::DISCONNECTED) { |
| device_id_to_metadata_map_.erase(device_id_copy); |
| state_change_detail = |
| StateChangeDetail::STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED; |
| } |
| |
| NotifySecureChannelStatusChanged(device_id_copy, old_status_copy, |
| new_status_copy, state_change_detail); |
| UpdateConnectionAttempts(); |
| } |
| |
| void BleConnectionManager::NotifyAdvertisementReceived( |
| const std::string& device_id, |
| bool is_background_advertisement) { |
| for (auto& observer : metrics_observer_list_) |
| observer.OnAdvertisementReceived(device_id, is_background_advertisement); |
| } |
| |
| void BleConnectionManager::NotifyMessageReceived(std::string device_id, |
| std::string payload) { |
| PA_LOG(INFO) << "Message received - Device ID: \"" |
| << cryptauth::RemoteDeviceRef::TruncateDeviceIdForLogs(device_id) |
| << "\", Message: \"" << payload << "\"."; |
| for (auto& observer : observer_list_) |
| observer.OnMessageReceived(device_id, payload); |
| } |
| |
| void BleConnectionManager::NotifySecureChannelStatusChanged( |
| std::string device_id, |
| cryptauth::SecureChannel::Status old_status, |
| cryptauth::SecureChannel::Status new_status, |
| StateChangeDetail state_change_detail) { |
| PA_LOG(INFO) << "Status change - Device ID: \"" |
| << cryptauth::RemoteDeviceRef::TruncateDeviceIdForLogs(device_id) |
| << "\": " << cryptauth::SecureChannel::StatusToString(old_status) |
| << " => " << cryptauth::SecureChannel::StatusToString(new_status) |
| << ", State change detail: " |
| << StateChangeDetailToString(state_change_detail); |
| |
| for (auto& observer : metrics_observer_list_) { |
| if (old_status == cryptauth::SecureChannel::Status::DISCONNECTED && |
| new_status == cryptauth::SecureChannel::Status::CONNECTING) { |
| observer.OnConnectionAttemptStarted(device_id); |
| } else if (new_status == cryptauth::SecureChannel::Status::CONNECTED) { |
| observer.OnConnection( |
| device_id, device_id_to_is_background_advertisement_map_[device_id]); |
| } else if (new_status == cryptauth::SecureChannel::Status::AUTHENTICATED) { |
| observer.OnSecureChannelCreated( |
| device_id, device_id_to_is_background_advertisement_map_[device_id]); |
| } else if (new_status == cryptauth::SecureChannel::Status::DISCONNECTED) { |
| observer.OnDeviceDisconnected( |
| device_id, state_change_detail, |
| device_id_to_is_background_advertisement_map_[device_id]); |
| } |
| } |
| |
| for (auto& observer : observer_list_) { |
| observer.OnSecureChannelStatusChanged(device_id, old_status, new_status, |
| state_change_detail); |
| } |
| } |
| |
| void BleConnectionManager::NotifyMessageSent(int sequence_number) { |
| for (auto& observer : observer_list_) |
| observer.OnMessageSent(sequence_number); |
| } |
| |
| void BleConnectionManager::SetTestTimerFactoryForTesting( |
| std::unique_ptr<TimerFactory> test_timer_factory) { |
| timer_factory_ = std::move(test_timer_factory); |
| } |
| |
| } // namespace tether |
| |
| } // namespace chromeos |