// 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/wifi_hotspot_disconnector_impl.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.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/network_configuration_remover.h"
#include "chromeos/ash/components/tether/pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
namespace ash {
namespace tether {
// static
void WifiHotspotDisconnectorImpl::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterStringPref(prefs::kDisconnectingWifiNetworkPath,
std::string());
}
WifiHotspotDisconnectorImpl::WifiHotspotDisconnectorImpl(
NetworkConnectionHandler* network_connection_handler,
NetworkStateHandler* network_state_handler,
PrefService* pref_service,
NetworkConfigurationRemover* network_configuration_remover)
: network_connection_handler_(network_connection_handler),
network_state_handler_(network_state_handler),
pref_service_(pref_service),
network_configuration_remover_(network_configuration_remover) {
std::string disconnecting_wifi_path_from_previous_session =
pref_service_->GetString(prefs::kDisconnectingWifiNetworkPath);
if (disconnecting_wifi_path_from_previous_session.empty())
return;
// If a previous disconnection attempt was aborted before it could be fully
// completed, clean up the leftover network configuration.
network_configuration_remover_->RemoveNetworkConfigurationByPath(
disconnecting_wifi_path_from_previous_session);
pref_service_->ClearPref(prefs::kDisconnectingWifiNetworkPath);
}
WifiHotspotDisconnectorImpl::~WifiHotspotDisconnectorImpl() = default;
void WifiHotspotDisconnectorImpl::DisconnectFromWifiHotspot(
const std::string& wifi_network_guid,
base::OnceClosure success_callback,
StringErrorCallback error_callback) {
const NetworkState* wifi_network_state =
network_state_handler_->GetNetworkStateFromGuid(wifi_network_guid);
if (!wifi_network_state) {
PA_LOG(ERROR) << "Wi-Fi NetworkState for GUID " << wifi_network_guid << " "
<< "does not exist. Cannot disconnect.";
std::move(error_callback).Run(NetworkConnectionHandler::kErrorNotFound);
return;
}
if (!wifi_network_state->IsConnectedState()) {
PA_LOG(ERROR) << "Wi-Fi NetworkState for GUID " << wifi_network_guid << " "
<< "is not connected. Cannot disconnect.";
std::move(error_callback).Run(NetworkConnectionHandler::kErrorNotConnected);
return;
}
const std::string wifi_network_path = wifi_network_state->path();
DCHECK(!wifi_network_path.empty());
// Before starting disconnection, log the disconnecting Wi-Fi GUID to prefs.
// Under normal circumstances, the GUID will be cleared as part of
// CleanUpAfterWifiDisconnection(). However, when the user logs out,
// this WifiHotspotDisconnectorImpl instance will be deleted before one of the
// callbacks passed below to DisconnectNetwork() can be called, and the
// GUID will remain in prefs until the next time the user logs in, at which
// time the associated network configuration can be removed.
pref_service_->Set(prefs::kDisconnectingWifiNetworkPath,
base::Value(wifi_network_path));
auto split_callback = base::SplitOnceCallback(std::move(error_callback));
network_connection_handler_->DisconnectNetwork(
wifi_network_path,
base::BindOnce(&WifiHotspotDisconnectorImpl::OnSuccessfulWifiDisconnect,
weak_ptr_factory_.GetWeakPtr(), wifi_network_guid,
wifi_network_path, std::move(success_callback),
std::move(split_callback.first)),
base::BindOnce(&WifiHotspotDisconnectorImpl::OnFailedWifiDisconnect,
weak_ptr_factory_.GetWeakPtr(), wifi_network_guid,
wifi_network_path, std::move(split_callback.second)));
}
void WifiHotspotDisconnectorImpl::OnSuccessfulWifiDisconnect(
const std::string& wifi_network_guid,
const std::string& wifi_network_path,
base::OnceClosure success_callback,
StringErrorCallback error_callback) {
PA_LOG(VERBOSE) << "Successfully disconnected from Wi-Fi network with GUID "
<< wifi_network_guid << ".";
CleanUpAfterWifiDisconnection(wifi_network_path, std::move(success_callback),
std::move(error_callback));
}
void WifiHotspotDisconnectorImpl::OnFailedWifiDisconnect(
const std::string& wifi_network_guid,
const std::string& wifi_network_path,
StringErrorCallback error_callback,
const std::string& error_name) {
PA_LOG(ERROR) << "Failed to disconnect from Wi-Fi network with GUID "
<< wifi_network_guid << ". Error name: " << error_name;
CleanUpAfterWifiDisconnection(wifi_network_path, base::OnceClosure(),
std::move(error_callback));
}
void WifiHotspotDisconnectorImpl::CleanUpAfterWifiDisconnection(
const std::string& wifi_network_path,
base::OnceClosure success_callback,
StringErrorCallback error_callback) {
network_configuration_remover_->RemoveNetworkConfigurationByPath(
wifi_network_path);
pref_service_->ClearPref(prefs::kDisconnectingWifiNetworkPath);
if (success_callback)
std::move(success_callback).Run();
else
std::move(error_callback)
.Run(NetworkConnectionHandler::kErrorDisconnectFailed);
}
} // namespace tether
} // namespace ash