chromium/chromeos/ash/services/secure_channel/nearby_initiator_operation.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/services/secure_channel/nearby_initiator_operation.h"

#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/no_destructor.h"
#include "chromeos/ash/services/secure_channel/authenticated_channel.h"
#include "chromeos/ash/services/secure_channel/connection_metrics_logger.h"
#include "chromeos/ash/services/secure_channel/nearby_connection_manager.h"
#include "chromeos/ash/services/secure_channel/nearby_connection_metrics_recorder.h"
#include "chromeos/ash/services/secure_channel/public/mojom/nearby_connector.mojom-shared.h"
#include "chromeos/ash/services/secure_channel/public/mojom/secure_channel.mojom-shared.h"

namespace ash::secure_channel {

namespace {

NearbyInitiatorConnectionResult GetMetricsConnectionResult(
    NearbyInitiatorFailureType failure_type) {
  switch (failure_type) {
    case NearbyInitiatorFailureType::kConnectivityError:
      return NearbyInitiatorConnectionResult::kConnectivityError;
    case NearbyInitiatorFailureType::kAuthenticationError:
      return NearbyInitiatorConnectionResult::kAuthenticationError;
  }
}

void RecordConnectionMetrics(const DeviceIdPair& device_id_pair,
                             NearbyInitiatorConnectionResult result) {
  LogNearbyInitiatorConnectionResult(result);

  static base::NoDestructor<NearbyConnectionMetricsRecorder> recorder;
  if (result == NearbyInitiatorConnectionResult::kConnectionSuccess)
    recorder->HandleConnectionSuccess(device_id_pair);
  else
    recorder->HandleConnectionFailure(device_id_pair);
}

}  // namespace

// static
NearbyInitiatorOperation::Factory*
    NearbyInitiatorOperation::Factory::test_factory_ = nullptr;

// static
std::unique_ptr<ConnectToDeviceOperation<NearbyInitiatorFailureType>>
NearbyInitiatorOperation::Factory::Create(
    NearbyConnectionManager* nearby_connection_manager,
    ConnectToDeviceOperation<
        NearbyInitiatorFailureType>::ConnectionSuccessCallback success_callback,
    const ConnectToDeviceOperation<
        NearbyInitiatorFailureType>::ConnectionFailedCallback& failure_callback,
    const NearbyConnectionManager::BleDiscoveryStateChangeCallback&
        ble_discovery_state_changed_callback,
    const NearbyConnectionManager::NearbyConnectionStateChangeCallback&
        nearby_connection_state_changed_callback,
    const NearbyConnectionManager::SecureChannelStateChangeCallback&
        secure_channel_authentication_state_changed_callback,
    const DeviceIdPair& device_id_pair,
    ConnectionPriority connection_priority,
    scoped_refptr<base::TaskRunner> task_runner) {
  if (test_factory_) {
    return test_factory_->CreateInstance(
        nearby_connection_manager, std::move(success_callback),
        std::move(failure_callback),
        std::move(ble_discovery_state_changed_callback),
        std::move(nearby_connection_state_changed_callback),
        std::move(secure_channel_authentication_state_changed_callback),
        device_id_pair, connection_priority, std::move(task_runner));
  }

  return base::WrapUnique(new NearbyInitiatorOperation(
      nearby_connection_manager, std::move(success_callback),
      std::move(failure_callback),
      std::move(ble_discovery_state_changed_callback),
      std::move(nearby_connection_state_changed_callback),
      std::move(secure_channel_authentication_state_changed_callback),
      device_id_pair, connection_priority, std::move(task_runner)));
}

// static
void NearbyInitiatorOperation::Factory::SetFactoryForTesting(
    Factory* test_factory) {
  test_factory_ = test_factory;
}

NearbyInitiatorOperation::Factory::~Factory() = default;

NearbyInitiatorOperation::NearbyInitiatorOperation(
    NearbyConnectionManager* nearby_connection_manager,
    ConnectToDeviceOperation<
        NearbyInitiatorFailureType>::ConnectionSuccessCallback success_callback,
    const ConnectToDeviceOperation<
        NearbyInitiatorFailureType>::ConnectionFailedCallback& failure_callback,
    const NearbyConnectionManager::BleDiscoveryStateChangeCallback&
        ble_discovery_state_changed_callback,
    const NearbyConnectionManager::NearbyConnectionStateChangeCallback&
        nearby_connection_state_changed_callback,
    const NearbyConnectionManager::SecureChannelStateChangeCallback&
        secure_channel_authentication_state_changed_callback,
    const DeviceIdPair& device_id_pair,
    ConnectionPriority connection_priority,
    scoped_refptr<base::TaskRunner> task_runner)
    : ConnectToDeviceOperationBase<NearbyInitiatorFailureType>(
          std::move(success_callback),
          std::move(failure_callback),
          device_id_pair,
          connection_priority,
          task_runner),
      nearby_connection_manager_(nearby_connection_manager),
      ble_discovery_state_changed_callback_(
          ble_discovery_state_changed_callback),
      nearby_connection_state_changed_callback_(
          nearby_connection_state_changed_callback),
      secure_channel_authentication_state_changed_callback_(
          secure_channel_authentication_state_changed_callback) {}

NearbyInitiatorOperation::~NearbyInitiatorOperation() = default;

void NearbyInitiatorOperation::PerformAttemptConnectionToDevice(
    ConnectionPriority connection_priority) {
  nearby_connection_manager_->AttemptNearbyInitiatorConnection(
      device_id_pair(),
      base::BindRepeating(&NearbyInitiatorOperation::OnBleDiscoveryStateChanged,
                          weak_ptr_factory_.GetWeakPtr()),
      base::BindRepeating(
          &NearbyInitiatorOperation::OnNearbyConnectionStateChanged,
          weak_ptr_factory_.GetWeakPtr()),
      base::BindRepeating(
          &NearbyInitiatorOperation::OnSecureChannelAuthenticationStateChanged,
          weak_ptr_factory_.GetWeakPtr()),
      base::BindOnce(&NearbyInitiatorOperation::OnSuccessfulConnection,
                     weak_ptr_factory_.GetWeakPtr()),
      base::BindRepeating(&NearbyInitiatorOperation::OnConnectionFailure,
                          weak_ptr_factory_.GetWeakPtr()));
}

void NearbyInitiatorOperation::PerformCancellation() {
  nearby_connection_manager_->CancelNearbyInitiatorConnectionAttempt(
      device_id_pair());
}

void NearbyInitiatorOperation::PerformUpdateConnectionPriority(
    ConnectionPriority connection_priority) {
  // Note: Nearby Connections are not performed differently based on the
  // connection priority, so this function is intentionally empty.
}

void NearbyInitiatorOperation::OnSuccessfulConnection(
    std::unique_ptr<AuthenticatedChannel> authenticated_channel) {
  RecordConnectionMetrics(device_id_pair(),
                          NearbyInitiatorConnectionResult::kConnectionSuccess);
  OnSuccessfulConnectionAttempt(std::move(authenticated_channel));
}

void NearbyInitiatorOperation::OnConnectionFailure(
    NearbyInitiatorFailureType failure_type) {
  RecordConnectionMetrics(device_id_pair(),
                          GetMetricsConnectionResult(failure_type));
  OnFailedConnectionAttempt(failure_type);
}

void NearbyInitiatorOperation::OnBleDiscoveryStateChanged(
    mojom::DiscoveryResult discovery_result,
    std::optional<mojom::DiscoveryErrorCode> potential_error_code) {
  ble_discovery_state_changed_callback_.Run(discovery_result,
                                            potential_error_code);
}

void NearbyInitiatorOperation::OnNearbyConnectionStateChanged(
    mojom::NearbyConnectionStep step,
    mojom::NearbyConnectionStepResult result) {
  nearby_connection_state_changed_callback_.Run(step, result);
}

void NearbyInitiatorOperation::OnSecureChannelAuthenticationStateChanged(
    mojom::SecureChannelState secure_channel_state) {
  secure_channel_authentication_state_changed_callback_.Run(
      secure_channel_state);
}

}  // namespace ash::secure_channel