blob: 81acbcb0481f5437343239267500b570a78e216e [file] [log] [blame]
// Copyright 2016 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/initializer_impl.h"
#include "base/bind.h"
#include "chromeos/components/tether/active_host.h"
#include "chromeos/components/tether/active_host_network_state_updater.h"
#include "chromeos/components/tether/ble_advertisement_device_queue.h"
#include "chromeos/components/tether/ble_connection_manager.h"
#include "chromeos/components/tether/crash_recovery_manager.h"
#include "chromeos/components/tether/device_id_tether_network_guid_map.h"
#include "chromeos/components/tether/disconnect_tethering_request_sender.h"
#include "chromeos/components/tether/disconnect_tethering_request_sender_impl.h"
#include "chromeos/components/tether/host_connection_metrics_logger.h"
#include "chromeos/components/tether/host_scan_device_prioritizer_impl.h"
#include "chromeos/components/tether/host_scan_scheduler.h"
#include "chromeos/components/tether/host_scanner.h"
#include "chromeos/components/tether/keep_alive_scheduler.h"
#include "chromeos/components/tether/master_host_scan_cache.h"
#include "chromeos/components/tether/network_configuration_remover.h"
#include "chromeos/components/tether/network_connection_handler_tether_delegate.h"
#include "chromeos/components/tether/network_host_scan_cache.h"
#include "chromeos/components/tether/network_list_sorter.h"
#include "chromeos/components/tether/notification_presenter.h"
#include "chromeos/components/tether/notification_remover.h"
#include "chromeos/components/tether/persistent_host_scan_cache_impl.h"
#include "chromeos/components/tether/tether_connector_impl.h"
#include "chromeos/components/tether/tether_disconnector_impl.h"
#include "chromeos/components/tether/tether_host_fetcher.h"
#include "chromeos/components/tether/tether_host_response_recorder.h"
#include "chromeos/components/tether/tether_network_disconnection_handler.h"
#include "chromeos/components/tether/timer_factory.h"
#include "chromeos/components/tether/wifi_hotspot_connector.h"
#include "chromeos/components/tether/wifi_hotspot_disconnector_impl.h"
#include "chromeos/network/managed_network_configuration_handler.h"
#include "chromeos/network/network_connect.h"
#include "chromeos/network/network_connection_handler.h"
#include "chromeos/network/network_state_handler.h"
#include "components/cryptauth/cryptauth_service.h"
#include "components/cryptauth/local_device_data_provider.h"
#include "components/cryptauth/remote_beacon_seed_fetcher.h"
#include "components/prefs/pref_service.h"
#include "components/proximity_auth/logging/logging.h"
namespace chromeos {
namespace tether {
namespace {
void OnDisconnectErrorDuringShutdown(const std::string& error_name) {
PA_LOG(WARNING) << "Error disconnecting from Tether network during shutdown; "
<< "Error name: " << error_name;
}
} // namespace
// static
InitializerImpl::Factory* InitializerImpl::Factory::factory_instance_ = nullptr;
// static
std::unique_ptr<Initializer> InitializerImpl::Factory::NewInstance(
cryptauth::CryptAuthService* cryptauth_service,
NotificationPresenter* notification_presenter,
PrefService* pref_service,
NetworkStateHandler* network_state_handler,
ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
NetworkConnect* network_connect,
NetworkConnectionHandler* network_connection_handler,
scoped_refptr<device::BluetoothAdapter> adapter) {
if (!factory_instance_) {
factory_instance_ = new Factory();
}
return factory_instance_->BuildInstance(
cryptauth_service, notification_presenter, pref_service,
network_state_handler, managed_network_configuration_handler,
network_connect, network_connection_handler, adapter);
}
// static
void InitializerImpl::Factory::SetInstanceForTesting(Factory* factory) {
factory_instance_ = factory;
}
// static
void InitializerImpl::RegisterProfilePrefs(PrefRegistrySimple* registry) {
ActiveHost::RegisterPrefs(registry);
PersistentHostScanCacheImpl::RegisterPrefs(registry);
TetherHostResponseRecorder::RegisterPrefs(registry);
WifiHotspotDisconnectorImpl::RegisterPrefs(registry);
}
std::unique_ptr<Initializer> InitializerImpl::Factory::BuildInstance(
cryptauth::CryptAuthService* cryptauth_service,
NotificationPresenter* notification_presenter,
PrefService* pref_service,
NetworkStateHandler* network_state_handler,
ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
NetworkConnect* network_connect,
NetworkConnectionHandler* network_connection_handler,
scoped_refptr<device::BluetoothAdapter> adapter) {
return base::WrapUnique(new InitializerImpl(
cryptauth_service, notification_presenter, pref_service,
network_state_handler, managed_network_configuration_handler,
network_connect, network_connection_handler, adapter));
}
InitializerImpl::InitializerImpl(
cryptauth::CryptAuthService* cryptauth_service,
NotificationPresenter* notification_presenter,
PrefService* pref_service,
NetworkStateHandler* network_state_handler,
ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
NetworkConnect* network_connect,
NetworkConnectionHandler* network_connection_handler,
scoped_refptr<device::BluetoothAdapter> adapter)
: cryptauth_service_(cryptauth_service),
notification_presenter_(notification_presenter),
pref_service_(pref_service),
network_state_handler_(network_state_handler),
managed_network_configuration_handler_(
managed_network_configuration_handler),
network_connect_(network_connect),
network_connection_handler_(network_connection_handler),
adapter_(adapter),
weak_ptr_factory_(this) {
CreateComponent();
}
InitializerImpl::~InitializerImpl() {
network_state_handler_->set_tether_sort_delegate(nullptr);
if (disconnect_tethering_request_sender_)
disconnect_tethering_request_sender_->RemoveObserver(this);
}
// Note: The asynchronous shutdown flow does not scale well (see
// crbug.com/761532).
// TODO(khorimoto): Refactor this flow.
void InitializerImpl::RequestShutdown() {
// If shutdown has already happened, there is nothing else to do.
if (status() != Initializer::Status::ACTIVE)
return;
// If there is an active connection, it needs to be disconnected before the
// Tether component is shut down.
if (active_host_->GetActiveHostStatus() !=
ActiveHost::ActiveHostStatus::DISCONNECTED) {
PA_LOG(INFO) << "There was an active connection during Tether shutdown. "
<< "Initiating disconnection from device ID \""
<< cryptauth::RemoteDevice::TruncateDeviceIdForLogs(
active_host_->GetActiveHostDeviceId())
<< "\".";
tether_disconnector_->DisconnectFromNetwork(
active_host_->GetTetherNetworkGuid(), base::Bind(&base::DoNothing),
base::Bind(&OnDisconnectErrorDuringShutdown));
}
if (!IsAsyncShutdownRequired()) {
TransitionToStatus(Initializer::Status::SHUT_DOWN);
return;
}
TransitionToStatus(Initializer::Status::SHUTTING_DOWN);
StartAsynchronousShutdown();
}
void InitializerImpl::OnAllAdvertisementsUnregistered() {
FinishAsynchronousShutdownIfPossible();
}
void InitializerImpl::OnPendingDisconnectRequestsComplete() {
FinishAsynchronousShutdownIfPossible();
}
void InitializerImpl::OnDiscoverySessionStateChanged(
bool discovery_session_active) {
FinishAsynchronousShutdownIfPossible();
}
void InitializerImpl::CreateComponent() {
network_list_sorter_ = base::MakeUnique<NetworkListSorter>();
network_state_handler_->set_tether_sort_delegate(network_list_sorter_.get());
tether_host_fetcher_ =
base::MakeUnique<TetherHostFetcher>(cryptauth_service_);
local_device_data_provider_ =
base::MakeUnique<cryptauth::LocalDeviceDataProvider>(cryptauth_service_);
remote_beacon_seed_fetcher_ =
base::MakeUnique<cryptauth::RemoteBeaconSeedFetcher>(
cryptauth_service_->GetCryptAuthDeviceManager());
ble_advertisement_device_queue_ =
base::MakeUnique<BleAdvertisementDeviceQueue>();
ble_advertiser_ = base::MakeUnique<BleAdvertiser>(
adapter_, local_device_data_provider_.get(),
remote_beacon_seed_fetcher_.get());
ble_scanner_ =
base::MakeUnique<BleScanner>(adapter_, local_device_data_provider_.get());
ble_connection_manager_ = base::MakeUnique<BleConnectionManager>(
cryptauth_service_, adapter_, ble_advertisement_device_queue_.get(),
ble_advertiser_.get(), ble_scanner_.get());
disconnect_tethering_request_sender_ =
base::MakeUnique<DisconnectTetheringRequestSenderImpl>(
ble_connection_manager_.get(), tether_host_fetcher_.get());
tether_host_response_recorder_ =
base::MakeUnique<TetherHostResponseRecorder>(pref_service_);
device_id_tether_network_guid_map_ =
base::MakeUnique<DeviceIdTetherNetworkGuidMap>();
host_scan_device_prioritizer_ =
base::MakeUnique<HostScanDevicePrioritizerImpl>(
tether_host_response_recorder_.get());
wifi_hotspot_connector_ = base::MakeUnique<WifiHotspotConnector>(
network_state_handler_, network_connect_);
active_host_ =
base::MakeUnique<ActiveHost>(tether_host_fetcher_.get(), pref_service_);
active_host_network_state_updater_ =
base::MakeUnique<ActiveHostNetworkStateUpdater>(active_host_.get(),
network_state_handler_);
persistent_host_scan_cache_ =
base::MakeUnique<PersistentHostScanCacheImpl>(pref_service_);
network_host_scan_cache_ = base::MakeUnique<NetworkHostScanCache>(
network_state_handler_, tether_host_response_recorder_.get(),
device_id_tether_network_guid_map_.get());
master_host_scan_cache_ = base::MakeUnique<MasterHostScanCache>(
base::MakeUnique<TimerFactory>(), active_host_.get(),
network_host_scan_cache_.get(), persistent_host_scan_cache_.get());
notification_remover_ = base::MakeUnique<NotificationRemover>(
network_state_handler_, notification_presenter_,
master_host_scan_cache_.get(), active_host_.get());
keep_alive_scheduler_ = base::MakeUnique<KeepAliveScheduler>(
active_host_.get(), ble_connection_manager_.get(),
master_host_scan_cache_.get(), device_id_tether_network_guid_map_.get());
clock_ = base::MakeUnique<base::DefaultClock>();
host_scanner_ = base::MakeUnique<HostScanner>(
network_state_handler_, tether_host_fetcher_.get(),
ble_connection_manager_.get(), host_scan_device_prioritizer_.get(),
tether_host_response_recorder_.get(), notification_presenter_,
device_id_tether_network_guid_map_.get(), master_host_scan_cache_.get(),
clock_.get());
host_scan_scheduler_ = base::MakeUnique<HostScanScheduler>(
network_state_handler_, host_scanner_.get());
host_connection_metrics_logger_ =
base::MakeUnique<HostConnectionMetricsLogger>();
network_configuration_remover_ =
base::MakeUnique<NetworkConfigurationRemover>(
network_state_handler_, managed_network_configuration_handler_);
wifi_hotspot_disconnector_ = base::MakeUnique<WifiHotspotDisconnectorImpl>(
network_connection_handler_, network_state_handler_, pref_service_,
network_configuration_remover_.get());
tether_connector_ = base::MakeUnique<TetherConnectorImpl>(
network_state_handler_, wifi_hotspot_connector_.get(), active_host_.get(),
tether_host_fetcher_.get(), ble_connection_manager_.get(),
tether_host_response_recorder_.get(),
device_id_tether_network_guid_map_.get(), master_host_scan_cache_.get(),
notification_presenter_, host_connection_metrics_logger_.get(),
disconnect_tethering_request_sender_.get(),
wifi_hotspot_disconnector_.get());
tether_disconnector_ = base::MakeUnique<TetherDisconnectorImpl>(
active_host_.get(), wifi_hotspot_disconnector_.get(),
disconnect_tethering_request_sender_.get(), tether_connector_.get(),
device_id_tether_network_guid_map_.get());
tether_network_disconnection_handler_ =
base::MakeUnique<TetherNetworkDisconnectionHandler>(
active_host_.get(), network_state_handler_,
network_configuration_remover_.get(),
disconnect_tethering_request_sender_.get());
network_connection_handler_tether_delegate_ =
base::MakeUnique<NetworkConnectionHandlerTetherDelegate>(
network_connection_handler_, active_host_.get(),
tether_connector_.get(), tether_disconnector_.get());
crash_recovery_manager_ = base::MakeUnique<CrashRecoveryManager>(
network_state_handler_, active_host_.get(),
master_host_scan_cache_.get());
crash_recovery_manager_->RestorePreCrashStateIfNecessary(
base::Bind(&InitializerImpl::OnPreCrashStateRestored,
weak_ptr_factory_.GetWeakPtr()));
}
bool InitializerImpl::IsAsyncShutdownRequired() {
// All of the asynchronous shutdown procedures depend on Bluetooth. If
// Bluetooth is off, there is no way to complete these tasks.
if (!adapter_->IsPowered())
return false;
// If there are pending disconnection requests, they must be sent before the
// component shuts down.
if (disconnect_tethering_request_sender_ &&
disconnect_tethering_request_sender_->HasPendingRequests()) {
return true;
}
// The BLE scanner must shut down completely before the component shuts down.
if (ble_scanner_ && ble_scanner_->ShouldDiscoverySessionBeActive() !=
ble_scanner_->IsDiscoverySessionActive()) {
return true;
}
// The BLE advertiser must unregister all of its advertisements.
if (ble_advertiser_ && ble_advertiser_->AreAdvertisementsRegistered())
return true;
return false;
}
void InitializerImpl::OnPreCrashStateRestored() {
// |crash_recovery_manager_| is no longer needed since it has completed.
crash_recovery_manager_.reset();
// Start a scan now that the Tether module has started up.
host_scan_scheduler_->ScheduleScan();
}
void InitializerImpl::StartAsynchronousShutdown() {
DCHECK(status() == Initializer::Status::SHUTTING_DOWN);
DCHECK(disconnect_tethering_request_sender_->HasPendingRequests());
// |ble_scanner_| and |disconnect_tethering_request_sender_| require
// asynchronous shutdowns, so start observering these objects. Once they
// notify observers that they are finished shutting down, asynchronous
// shutdown will complete.
ble_advertiser_->AddObserver(this);
ble_scanner_->AddObserver(this);
disconnect_tethering_request_sender_->AddObserver(this);
// All objects which are not dependencies of |ble_scanner_| and
// |disconnect_tethering_request_sender_| are no longer needed, so delete
// them.
crash_recovery_manager_.reset();
network_connection_handler_tether_delegate_.reset();
tether_network_disconnection_handler_.reset();
tether_connector_.reset();
host_connection_metrics_logger_.reset();
host_scan_scheduler_.reset();
host_scanner_.reset();
clock_.reset();
keep_alive_scheduler_.reset();
notification_remover_.reset();
master_host_scan_cache_.reset();
network_host_scan_cache_.reset();
persistent_host_scan_cache_.reset();
active_host_network_state_updater_.reset();
active_host_.reset();
wifi_hotspot_connector_.reset();
host_scan_device_prioritizer_.reset();
device_id_tether_network_guid_map_.reset();
tether_host_response_recorder_.reset();
network_state_handler_->set_tether_sort_delegate(nullptr);
network_list_sorter_.reset();
}
void InitializerImpl::FinishAsynchronousShutdownIfPossible() {
DCHECK(status() == Initializer::Status::SHUTTING_DOWN);
// If the asynchronous shutdown is not yet complete (i.e., only some of the
// shutdown requirements are complete), do not shut down yet.
if (IsAsyncShutdownRequired())
return;
ble_advertiser_->RemoveObserver(this);
ble_scanner_->RemoveObserver(this);
disconnect_tethering_request_sender_->RemoveObserver(this);
// Shutdown has completed. It is now safe to delete the objects that were
// shutting down asynchronously.
wifi_hotspot_disconnector_.reset();
network_configuration_remover_.reset();
disconnect_tethering_request_sender_.reset();
ble_connection_manager_.reset();
ble_scanner_.reset();
ble_advertiser_.reset();
ble_advertisement_device_queue_.reset();
remote_beacon_seed_fetcher_.reset();
local_device_data_provider_.reset();
tether_host_fetcher_.reset();
TransitionToStatus(Initializer::Status::SHUT_DOWN);
}
} // namespace tether
} // namespace chromeos