blob: d6bdf44725b1e3fa3ee5bc6444a3c11fbc5e275e [file] [log] [blame]
// Copyright 2013 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/browser/sync/sync_startup_tracker.h"
#include <optional>
#include "base/functional/bind.h"
#include "base/notreached.h"
#include "components/sync/service/sync_service.h"
namespace {
constexpr base::TimeDelta kDefaultWaitTimeout = base::Seconds(10);
std::optional<base::TimeDelta> g_wait_timeout = kDefaultWaitTimeout;
} // namespace
SyncStartupTracker::SyncStartupTracker(syncer::SyncService* sync_service,
SyncStartupStateChangedCallback callback)
: sync_service_(sync_service),
sync_startup_status_changed_callback_(std::move(callback)) {
DCHECK(sync_service_);
sync_service_observation_.Observe(sync_service_);
if (g_wait_timeout.has_value()) {
timeout_waiter_.Start(FROM_HERE, g_wait_timeout.value(),
base::BindOnce(&SyncStartupTracker::OnStartupTimeout,
weak_factory_.GetWeakPtr()));
}
CheckServiceState();
}
SyncStartupTracker::~SyncStartupTracker() = default;
void SyncStartupTracker::OnStateChanged(syncer::SyncService* sync) {
CheckServiceState();
}
void SyncStartupTracker::OnStartupTimeout() {
is_timed_out_ = true;
CheckServiceState();
}
void SyncStartupTracker::CheckServiceState() {
ServiceStartupState state = GetServiceStartupState(sync_service_);
if (state == ServiceStartupState::kPending) {
if (is_timed_out_) {
state = ServiceStartupState::kTimeout;
} else {
// Do nothing - still waiting for sync to finish starting up.
return;
}
}
timeout_waiter_.Stop();
sync_service_observation_.Reset();
DCHECK(sync_startup_status_changed_callback_);
std::move(sync_startup_status_changed_callback_).Run(state);
}
// static
SyncStartupTracker::ServiceStartupState
SyncStartupTracker::GetServiceStartupState(syncer::SyncService* sync_service) {
// If no service exists or it can't be started, treat as a startup error.
if (!sync_service || !sync_service->CanSyncFeatureStart()) {
return ServiceStartupState::kError;
}
// Unrecoverable errors return false for CanSyncFeatureStart(), handled above.
DCHECK(!sync_service->HasUnrecoverableError());
switch (sync_service->GetTransportState()) {
case syncer::SyncService::TransportState::DISABLED:
NOTREACHED();
case syncer::SyncService::TransportState::START_DEFERRED:
case syncer::SyncService::TransportState::INITIALIZING:
// No error detected yet, but the sync engine hasn't started up yet, so
// we're in the pending state.
return ServiceStartupState::kPending;
case syncer::SyncService::TransportState::PAUSED:
// Persistent auth errors lead to sync pausing.
return ServiceStartupState::kError;
case syncer::SyncService::TransportState::PENDING_DESIRED_CONFIGURATION:
case syncer::SyncService::TransportState::CONFIGURING:
case syncer::SyncService::TransportState::ACTIVE:
DCHECK(sync_service->IsEngineInitialized());
return ServiceStartupState::kComplete;
}
NOTREACHED();
}
namespace testing {
ScopedSyncStartupTimeoutOverride::ScopedSyncStartupTimeoutOverride(
std::optional<base::TimeDelta> wait_timeout) {
old_wait_timeout_ = g_wait_timeout;
g_wait_timeout = wait_timeout;
}
ScopedSyncStartupTimeoutOverride::~ScopedSyncStartupTimeoutOverride() {
g_wait_timeout = old_wait_timeout_;
}
} // namespace testing