1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
// 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/crash_recovery_manager_impl.h"
#include <memory>
#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/ash/components/multidevice/logging/logging.h"
#include "chromeos/ash/components/multidevice/remote_device_ref.h"
#include "chromeos/ash/components/network/network_state.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/components/tether/host_scan_cache.h"
namespace ash {
namespace tether {
// static
CrashRecoveryManagerImpl::Factory*
CrashRecoveryManagerImpl::Factory::factory_instance_ = nullptr;
// static
std::unique_ptr<CrashRecoveryManager> CrashRecoveryManagerImpl::Factory::Create(
NetworkStateHandler* network_state_handler,
ActiveHost* active_host,
HostScanCache* host_scan_cache) {
if (factory_instance_) {
return factory_instance_->CreateInstance(network_state_handler, active_host,
host_scan_cache);
}
return base::WrapUnique(new CrashRecoveryManagerImpl(
network_state_handler, active_host, host_scan_cache));
}
// static
void CrashRecoveryManagerImpl::Factory::SetFactoryForTesting(Factory* factory) {
factory_instance_ = factory;
}
CrashRecoveryManagerImpl::Factory::~Factory() = default;
CrashRecoveryManagerImpl::CrashRecoveryManagerImpl(
NetworkStateHandler* network_state_handler,
ActiveHost* active_host,
HostScanCache* host_scan_cache)
: network_state_handler_(network_state_handler),
active_host_(active_host),
host_scan_cache_(host_scan_cache) {}
CrashRecoveryManagerImpl::~CrashRecoveryManagerImpl() = default;
void CrashRecoveryManagerImpl::RestorePreCrashStateIfNecessary(
base::OnceClosure on_restoration_finished) {
ActiveHost::ActiveHostStatus status = active_host_->GetActiveHostStatus();
std::string active_host_device_id = active_host_->GetActiveHostDeviceId();
std::string wifi_network_guid = active_host_->GetWifiNetworkGuid();
std::string tether_network_guid = active_host_->GetTetherNetworkGuid();
if (status == ActiveHost::ActiveHostStatus::DISCONNECTED) {
// There was no active Tether session, so either the last TetherComponent
// shutdown occurred normally (i.e., without a crash), or it occurred due
// to a crash and there was no active host at the time of the crash.
std::move(on_restoration_finished).Run();
return;
}
if (status == ActiveHost::ActiveHostStatus::CONNECTING) {
// If a connection attempt was in progress when the crash occurred, abandon
// the connection attempt. Set ActiveHost back to DISCONNECTED; the user can
// attempt another connection if desired.
// TODO(khorimoto): Explore whether we should attempt to restore an
// in-progress connection attempt. This is a low-priority edge case which is
// difficult to solve.
PA_LOG(WARNING) << "Browser crashed while Tether connection attempt was in "
<< "progress. Abandoning connection attempt.";
active_host_->SetActiveHostDisconnected();
std::move(on_restoration_finished).Run();
return;
}
RestoreConnectedState(std::move(on_restoration_finished),
active_host_device_id, tether_network_guid,
wifi_network_guid);
}
void CrashRecoveryManagerImpl::RestoreConnectedState(
base::OnceClosure on_restoration_finished,
const std::string& active_host_device_id,
const std::string& tether_network_guid,
const std::string& wifi_network_guid) {
// Since the host was connected, both a Wi-Fi and Tether network GUID are
// expected to be present.
DCHECK(!wifi_network_guid.empty() && !tether_network_guid.empty());
if (!host_scan_cache_->ExistsInCache(tether_network_guid)) {
// If a crash occurred, HostScanCache is expected to have restored its state
// via its persistent scan results. If that did not happen correctly, there
// is no way to restore the active host, so abandon the connection. Note
// that this is not an expected error condition.
PA_LOG(ERROR)
<< "Browser crashed while a Tether connection was active, "
<< "but the scan result for the active host was lost. Setting "
<< "the active host to DISCONNECTED.";
active_host_->SetActiveHostDisconnected();
std::move(on_restoration_finished).Run();
return;
}
// Since the associated scan result exists in the cache, it is expected to be
// present in the network stack.
const NetworkState* tether_state =
network_state_handler_->GetNetworkStateFromGuid(tether_network_guid);
DCHECK(tether_state);
const NetworkState* wifi_state =
network_state_handler_->GetNetworkStateFromGuid(wifi_network_guid);
if (!wifi_state || !wifi_state->IsConnectedState()) {
// If the Wi-Fi network corresponding to the Tether hotspot is not present
// or is no longer connected, then this device is no longer truly connected
// to the active host.
PA_LOG(ERROR) << "Browser crashed while a Tether connection was active, "
<< "but underlying Wi-Fi network corresponding to the Tether "
<< "connection is no longer present. Setting the active host "
<< "to DISCONNECTED.";
active_host_->SetActiveHostDisconnected();
std::move(on_restoration_finished).Run();
return;
}
// Because the NetworkState object representing the Wi-Fi network was lost
// during the crash, the association between it and the Tether NetworkState
// has been broken. Restore it now.
DCHECK(wifi_state->tether_guid().empty());
network_state_handler_->AssociateTetherNetworkStateWithWifiNetwork(
tether_network_guid, wifi_network_guid);
active_host_->GetActiveHost(base::BindOnce(
&CrashRecoveryManagerImpl::OnActiveHostFetched,
weak_ptr_factory_.GetWeakPtr(), std::move(on_restoration_finished)));
}
void CrashRecoveryManagerImpl::OnActiveHostFetched(
base::OnceClosure on_restoration_finished,
ActiveHost::ActiveHostStatus active_host_status,
std::optional<multidevice::RemoteDeviceRef> active_host,
const std::string& tether_network_guid,
const std::string& wifi_network_guid) {
DCHECK(ActiveHost::ActiveHostStatus::CONNECTED == active_host_status);
DCHECK(active_host_);
// Even though the active host has not actually changed, fire an active host
// changed update so that classes listening on ActiveHost (e.g.,
// ActiveHostNetworkStateUpdater and KeepAliveScheduler) will be notified
// that there is an active connection.
//
// Note: SendActiveHostChangedUpdate() is a protected function of ActiveHost
// which is only invoked here because CrashRecoveryManagerImpl is a friend
// class.
// It is invoked directly here because we are sending out a "fake" change
// event which has equal old and new values.
active_host_->SendActiveHostChangedUpdate(
ActiveHost::ActiveHostStatus::CONNECTED /* old_status */,
active_host ? active_host->GetDeviceId()
: std::string() /* old_active_host_id */,
tether_network_guid /* old_tether_network_guid */,
wifi_network_guid /* old_wifi_network_guid */,
ActiveHost::ActiveHostStatus::CONNECTED /* new_status */,
active_host /* new_active_host */,
tether_network_guid /* new_tether_network_guid */,
wifi_network_guid /* new_wifi_network_guid */);
std::move(on_restoration_finished).Run();
}
} // namespace tether
} // namespace ash
|