chromium/chrome/services/sharing/sharing_impl.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 "chrome/services/sharing/sharing_impl.h"

#include <utility>

#include "base/functional/callback.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/sequenced_task_runner.h"
#include "chrome/services/sharing/nearby/decoder/nearby_decoder.h"
#include "chrome/services/sharing/nearby/nearby_connections.h"
#include "chrome/services/sharing/nearby/nearby_presence.h"
#include "chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.h"
#include "chromeos/ash/services/nearby/public/mojom/nearby_decoder.mojom.h"
#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder.mojom.h"

namespace sharing {

SharingImpl::SharingImpl(
    mojo::PendingReceiver<mojom::Sharing> receiver,
    scoped_refptr<base::SequencedTaskRunner> io_task_runner)
    : receiver_(this, std::move(receiver)),
      io_task_runner_(std::move(io_task_runner)) {}

SharingImpl::~SharingImpl() {
  // No need to call DoShutDown() from the destructor because SharingImpl should
  // only be destroyed after SharingImpl::ShutDown() has been called.
  CHECK(!nearby_connections_ && !nearby_presence_ && !nearby_decoder_);
}

void SharingImpl::Connect(
    NearbyDependenciesPtr deps,
    mojo::PendingReceiver<NearbyConnectionsMojom> connections_receiver,
    mojo::PendingReceiver<NearbyPresenceMojom> presence_receiver,
    mojo::PendingReceiver<::sharing::mojom::NearbySharingDecoder>
        decoder_receiver,
    mojo::PendingReceiver<ash::quick_start::mojom::QuickStartDecoder>
        quick_start_decoder_receiver) {
  CHECK(!nearby_connections_);
  CHECK(!nearby_presence_);
  CHECK(!nearby_decoder_);

  nearby::api::LogMessage::Severity min_log_severity = deps->min_log_severity;

  InitializeNearbySharedRemotes(std::move(deps));

  nearby_presence_ = std::make_unique<NearbyPresence>(
      std::move(presence_receiver),
      base::BindOnce(&SharingImpl::OnDisconnect, weak_ptr_factory_.GetWeakPtr(),
                     MojoDependencyName::kNearbyPresence));

  nearby_connections_ = std::make_unique<NearbyConnections>(
      std::move(connections_receiver),
      nearby_presence_->GetLocalDeviceProvider(), min_log_severity,
      base::BindOnce(&SharingImpl::OnDisconnect, weak_ptr_factory_.GetWeakPtr(),
                     MojoDependencyName::kNearbyConnections));

  nearby_decoder_ = std::make_unique<NearbySharingDecoder>(
      std::move(decoder_receiver),
      base::BindOnce(&SharingImpl::OnDisconnect, weak_ptr_factory_.GetWeakPtr(),
                     MojoDependencyName::kNearbyShareDecoder));

  quick_start_decoder_ = std::make_unique<ash::quick_start::QuickStartDecoder>(
      std::move(quick_start_decoder_receiver),
      base::BindOnce(&SharingImpl::OnDisconnect, weak_ptr_factory_.GetWeakPtr(),
                     MojoDependencyName::kQuickStartDecoder));
}

void SharingImpl::ShutDown(ShutDownCallback callback) {
  DoShutDown(/*is_expected=*/true);
  std::move(callback).Run();
}

void SharingImpl::DoShutDown(bool is_expected) {
  nearby::NearbySharedRemotes::SetInstance(nullptr);

  if (!nearby_connections_ && !nearby_presence_ && !nearby_decoder_) {
    return;
  }

  nearby_connections_.reset();
  nearby_presence_.reset();
  nearby_decoder_.reset();

  // Leave |receiver_| valid. Its disconnection is reserved as a signal that the
  // Sharing utility process has crashed.
}

void SharingImpl::OnDisconnect(MojoDependencyName mojo_dependency_name) {
  LOG(WARNING) << "The utility process has detected that the browser process "
                  "has disconnected from a mojo pipe: ["
               << GetMojoDependencyName(mojo_dependency_name) << "]";
  base::UmaHistogramEnumeration(
      "Nearby.Connections.UtilityProcessShutdownReason."
      "DisconnectedMojoDependency",
      mojo_dependency_name);

  LOG(ERROR) << "A Sharing process dependency has unexpectedly disconnected.";
  DoShutDown(/*is_expected=*/false);
}

void SharingImpl::InitializeNearbySharedRemotes(NearbyDependenciesPtr deps) {
  nearby_shared_remotes_ = std::make_unique<nearby::NearbySharedRemotes>();
  nearby::NearbySharedRemotes::SetInstance(nearby_shared_remotes_.get());

  if (deps->bluetooth_adapter) {
    nearby_shared_remotes_->bluetooth_adapter.Bind(
        std::move(deps->bluetooth_adapter), io_task_runner_);
    nearby_shared_remotes_->bluetooth_adapter.set_disconnect_handler(
        base::BindOnce(&SharingImpl::OnDisconnect,
                       weak_ptr_factory_.GetWeakPtr(),
                       MojoDependencyName::kBluetoothAdapter),
        base::SequencedTaskRunner::GetCurrentDefault());
  }

  if (deps->nearby_presence_credential_storage) {
    nearby_shared_remotes_->nearby_presence_credential_storage.Bind(
        std::move(deps->nearby_presence_credential_storage), io_task_runner_);
    nearby_shared_remotes_->nearby_presence_credential_storage
        .set_disconnect_handler(
            base::BindOnce(
                &SharingImpl::OnDisconnect, weak_ptr_factory_.GetWeakPtr(),
                MojoDependencyName::kNearbyPresenceCredentialStorage),
            base::SequencedTaskRunner::GetCurrentDefault());
  }

  nearby_shared_remotes_->socket_manager.Bind(
      std::move(deps->webrtc_dependencies->socket_manager), io_task_runner_);
  nearby_shared_remotes_->socket_manager.set_disconnect_handler(
      base::BindOnce(&SharingImpl::OnDisconnect, weak_ptr_factory_.GetWeakPtr(),
                     MojoDependencyName::kSocketManager),
      base::SequencedTaskRunner::GetCurrentDefault());

  nearby_shared_remotes_->mdns_responder_factory.Bind(
      std::move(deps->webrtc_dependencies->mdns_responder_factory),
      io_task_runner_);
  nearby_shared_remotes_->mdns_responder_factory.set_disconnect_handler(
      base::BindOnce(&SharingImpl::OnDisconnect, weak_ptr_factory_.GetWeakPtr(),
                     MojoDependencyName::kMdnsResponder),
      base::SequencedTaskRunner::GetCurrentDefault());

  nearby_shared_remotes_->ice_config_fetcher.Bind(
      std::move(deps->webrtc_dependencies->ice_config_fetcher),
      io_task_runner_);
  nearby_shared_remotes_->ice_config_fetcher.set_disconnect_handler(
      base::BindOnce(&SharingImpl::OnDisconnect, weak_ptr_factory_.GetWeakPtr(),
                     MojoDependencyName::kIceConfigFetcher),
      base::SequencedTaskRunner::GetCurrentDefault());

  nearby_shared_remotes_->webrtc_signaling_messenger.Bind(
      std::move(deps->webrtc_dependencies->messenger), io_task_runner_);
  nearby_shared_remotes_->webrtc_signaling_messenger.set_disconnect_handler(
      base::BindOnce(&SharingImpl::OnDisconnect, weak_ptr_factory_.GetWeakPtr(),
                     MojoDependencyName::kWebRtcSignalingMessenger),
      base::SequencedTaskRunner::GetCurrentDefault());

  // TODO(https://crbug.com/1261238): This should always be true when the
  // WifiLan feature flag is enabled. Remove when flag is enabled by default.
  if (deps->wifilan_dependencies) {
    nearby_shared_remotes_->cros_network_config.Bind(
        std::move(deps->wifilan_dependencies->cros_network_config),
        io_task_runner_);
    nearby_shared_remotes_->cros_network_config.set_disconnect_handler(
        base::BindOnce(&SharingImpl::OnDisconnect,
                       weak_ptr_factory_.GetWeakPtr(),
                       MojoDependencyName::kCrosNetworkConfig),
        base::SequencedTaskRunner::GetCurrentDefault());

    nearby_shared_remotes_->firewall_hole_factory.Bind(
        std::move(deps->wifilan_dependencies->firewall_hole_factory),
        io_task_runner_);
    nearby_shared_remotes_->firewall_hole_factory.set_disconnect_handler(
        base::BindOnce(&SharingImpl::OnDisconnect,
                       weak_ptr_factory_.GetWeakPtr(),
                       MojoDependencyName::kFirewallHoleFactory),
        base::SequencedTaskRunner::GetCurrentDefault());

    nearby_shared_remotes_->tcp_socket_factory.Bind(
        std::move(deps->wifilan_dependencies->tcp_socket_factory),
        io_task_runner_);
    nearby_shared_remotes_->tcp_socket_factory.set_disconnect_handler(
        base::BindOnce(&SharingImpl::OnDisconnect,
                       weak_ptr_factory_.GetWeakPtr(),
                       MojoDependencyName::kTcpSocketFactory),
        base::SequencedTaskRunner::GetCurrentDefault());

    if (deps->wifilan_dependencies->mdns_manager) {
      nearby_shared_remotes_->mdns_manager.Bind(
          std::move(deps->wifilan_dependencies->mdns_manager), io_task_runner_);
      nearby_shared_remotes_->mdns_manager.set_disconnect_handler(
          base::BindOnce(&SharingImpl::OnDisconnect,
                         weak_ptr_factory_.GetWeakPtr(),
                         MojoDependencyName::kMdnsManager),
          base::SequencedTaskRunner::GetCurrentDefault());
    }
  }

  if (deps->wifidirect_dependencies) {
    nearby_shared_remotes_->wifi_direct_firewall_hole_factory.Bind(
        std::move(deps->wifidirect_dependencies->firewall_hole_factory),
        io_task_runner_);
    nearby_shared_remotes_->wifi_direct_firewall_hole_factory
        .set_disconnect_handler(
            base::BindOnce(&SharingImpl::OnDisconnect,
                           weak_ptr_factory_.GetWeakPtr(),
                           MojoDependencyName::kFirewallHoleFactory),
            base::SequencedTaskRunner::GetCurrentDefault());

    nearby_shared_remotes_->wifi_direct_manager.Bind(
        std::move(deps->wifidirect_dependencies->wifi_direct_manager),
        io_task_runner_);
    nearby_shared_remotes_->wifi_direct_manager.set_disconnect_handler(
        base::BindOnce(&SharingImpl::OnDisconnect,
                       weak_ptr_factory_.GetWeakPtr(),
                       MojoDependencyName::kWifiDirectManager),
        base::SequencedTaskRunner::GetCurrentDefault());
  }
}

std::string SharingImpl::GetMojoDependencyName(
    MojoDependencyName dependency_name) {
  switch (dependency_name) {
    case MojoDependencyName::kNearbyConnections:
      return "Nearby Connections";
    case MojoDependencyName::kBluetoothAdapter:
      return "Bluetooth Adapter";
    case MojoDependencyName::kSocketManager:
      return "Socket Manager";
    case MojoDependencyName::kMdnsResponder:
      return "MDNS Responder";
    case MojoDependencyName::kIceConfigFetcher:
      return "ICE Config Fetcher";
    case MojoDependencyName::kWebRtcSignalingMessenger:
      return "WebRTC Signaling Messenger";
    case MojoDependencyName::kCrosNetworkConfig:
      return "CrOS Network Config";
    case MojoDependencyName::kFirewallHoleFactory:
      return "Firewall Hole Factory";
    case MojoDependencyName::kTcpSocketFactory:
      return "TCP socket Factory";
    case MojoDependencyName::kNearbyPresence:
      return "Nearby Presence";
    case MojoDependencyName::kNearbyShareDecoder:
      return "Decoder";
    case MojoDependencyName::kQuickStartDecoder:
      return "Quick Start Decoder";
    case MojoDependencyName::kNearbyPresenceCredentialStorage:
      return "Nearby Presence Credential Storage";
    case MojoDependencyName::kWifiDirectManager:
      return "WiFi Direct Manager";
    case MojoDependencyName::kMdnsManager:
      return "mDNS Manager";
  }
}

}  // namespace sharing