// Copyright 2017 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/components/tether/tether_disconnector_impl.h"
#include "base/metrics/histogram_macros.h"
#include "base/values.h"
#include "chromeos/ash/components/multidevice/logging/logging.h"
#include "chromeos/ash/components/network/network_connection_handler.h"
#include "chromeos/ash/components/network/network_state.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/components/tether/active_host.h"
#include "chromeos/ash/components/tether/device_id_tether_network_guid_map.h"
#include "chromeos/ash/components/tether/disconnect_tethering_request_sender.h"
#include "chromeos/ash/components/tether/network_configuration_remover.h"
#include "chromeos/ash/components/tether/tether_connector.h"
#include "chromeos/ash/components/tether/wifi_hotspot_disconnector.h"
namespace ash {
namespace tether {
TetherDisconnectorImpl::TetherDisconnectorImpl(
ActiveHost* active_host,
WifiHotspotDisconnector* wifi_hotspot_disconnector,
DisconnectTetheringRequestSender* disconnect_tethering_request_sender,
TetherConnector* tether_connector,
DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map,
TetherSessionCompletionLogger* tether_session_completion_logger)
: active_host_(active_host),
wifi_hotspot_disconnector_(wifi_hotspot_disconnector),
disconnect_tethering_request_sender_(disconnect_tethering_request_sender),
tether_connector_(tether_connector),
device_id_tether_network_guid_map_(device_id_tether_network_guid_map),
tether_session_completion_logger_(tether_session_completion_logger) {}
TetherDisconnectorImpl::~TetherDisconnectorImpl() = default;
void TetherDisconnectorImpl::DisconnectFromNetwork(
const std::string& tether_network_guid,
base::OnceClosure success_callback,
StringErrorCallback error_callback,
const TetherSessionCompletionLogger::SessionCompletionReason&
session_completion_reason) {
DCHECK(!tether_network_guid.empty());
ActiveHost::ActiveHostStatus status = active_host_->GetActiveHostStatus();
std::string active_tether_network_guid = active_host_->GetTetherNetworkGuid();
std::string active_wifi_network_guid = active_host_->GetWifiNetworkGuid();
if (status == ActiveHost::ActiveHostStatus::DISCONNECTED) {
PA_LOG(ERROR) << "Disconnect requested for Tether network with GUID "
<< tether_network_guid << ", but no device is connected.";
std::move(error_callback).Run(NetworkConnectionHandler::kErrorNotConnected);
return;
}
if (tether_network_guid != active_tether_network_guid) {
PA_LOG(ERROR) << "Disconnect requested for Tether network with GUID "
<< tether_network_guid << ", but that device is not the "
<< "active host.";
std::move(error_callback).Run(NetworkConnectionHandler::kErrorNotConnected);
return;
}
if (status == ActiveHost::ActiveHostStatus::CONNECTING) {
// Note: CancelConnectionAttempt() disconnects the active host.
if (tether_connector_->CancelConnectionAttempt(tether_network_guid)) {
PA_LOG(VERBOSE) << "Disconnect requested for Tether network with GUID "
<< tether_network_guid
<< ", which had not yet connected. "
<< "Canceled in-progress connection attempt.";
std::move(success_callback).Run();
return;
}
PA_LOG(ERROR) << "Disconnect requested for Tether network with GUID "
<< tether_network_guid << " (not yet connected), but "
<< "canceling connection attempt failed.";
std::move(error_callback)
.Run(NetworkConnectionHandler::kErrorDisconnectFailed);
return;
}
DCHECK(!active_wifi_network_guid.empty());
DisconnectActiveWifiConnection(tether_network_guid, active_wifi_network_guid,
std::move(success_callback),
std::move(error_callback));
tether_session_completion_logger_->RecordTetherSessionCompletion(
session_completion_reason);
}
void TetherDisconnectorImpl::DisconnectActiveWifiConnection(
const std::string& tether_network_guid,
const std::string& wifi_network_guid,
base::OnceClosure success_callback,
StringErrorCallback error_callback) {
// First, disconnect the active host so that the user gets visual indication
// that the disconnection is in progress as quickly as possible.
active_host_->SetActiveHostDisconnected();
// Disconnect from the Wi-Fi hotspot. This transfers responsibility for
// invoking the success or error callbacks to |wifi_hotspot_disconnector_|.
wifi_hotspot_disconnector_->DisconnectFromWifiHotspot(
wifi_network_guid, std::move(success_callback),
std::move(error_callback));
// In addition to disconnecting from the Wi-Fi network, this device must also
// send a DisconnectTetheringRequest to the tether host so that it can shut
// down its Wi-Fi hotspot if it is no longer in use.
const std::string device_id =
device_id_tether_network_guid_map_->GetDeviceIdForTetherNetworkGuid(
tether_network_guid);
disconnect_tethering_request_sender_->SendDisconnectRequestToDevice(
device_id);
}
} // namespace tether
} // namespace ash