Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Unified Diff: chrome/browser/sync/startup_controller.cc

Issue 162443004: sync: final pieces to sync deferred initialization (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix test leak Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/sync/startup_controller.cc
diff --git a/chrome/browser/sync/startup_controller.cc b/chrome/browser/sync/startup_controller.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8cb35acb5684dc0ffd1f1e5eefacc8e1f5ed5b7e
--- /dev/null
+++ b/chrome/browser/sync/startup_controller.cc
@@ -0,0 +1,202 @@
+// Copyright 2014 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 "chrome/browser/sync/startup_controller.h"
+
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "chrome/browser/managed_mode/managed_user_signin_manager_wrapper.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/sync/sync_prefs.h"
+#include "chrome/common/chrome_switches.h"
+
+namespace browser_sync {
+
+namespace {
+
+// The amount of time we'll wait to initialize sync if no data type triggers
+// initialization via a StartSyncFlare.
+const int kDeferredInitFallbackSeconds = 10;
+
+// Enum (for UMA, primarily) defining different events that cause us to
+// exit the "deferred" state of initialization and invoke start_backend.
+enum DeferredInitTrigger {
+ // We have received a signal from a SyncableService requesting that sync
+ // starts as soon as possible.
+ TRIGGER_DATA_TYPE_REQUEST,
+ // No data type requested sync to start and our fallback timer expired.
+ TRIGGER_FALLBACK_TIMER,
+ MAX_TRIGGER_VALUE
+};
+
+} // namespace
+
+StartupController::StartupController(
+ ProfileSyncServiceStartBehavior start_behavior,
+ ProfileOAuth2TokenService* token_service,
+ const browser_sync::SyncPrefs* sync_prefs,
+ const ManagedUserSigninManagerWrapper* signin,
+ base::Closure start_backend)
+ : received_start_request_(false),
+ setup_in_progress_(false),
+ auto_start_enabled_(start_behavior == AUTO_START),
+ sync_prefs_(sync_prefs),
+ token_service_(token_service),
+ signin_(signin),
+ start_backend_(start_backend),
+ fallback_timeout_(
+ base::TimeDelta::FromSeconds(kDeferredInitFallbackSeconds)),
+ weak_factory_(this) {}
+
+StartupController::~StartupController() {}
+
+void StartupController::Reset() {
+ received_start_request_ = false;
+ setup_in_progress_ = false;
+ start_up_time_ = base::Time();
+ start_backend_time_ = base::Time();
+ // Don't let previous timers affect us post-reset.
+ weak_factory_.InvalidateWeakPtrs();
+}
+
+void StartupController::set_setup_in_progress(bool in_progress) {
+ setup_in_progress_ = in_progress;
+}
+
+void StartupController::StartUp(StartUpDeferredOption deferred_option) {
+ const bool first_start = start_up_time_.is_null();
+ if (first_start)
+ start_up_time_ = base::Time::Now();
+
+ if (deferred_option == STARTUP_BACKEND_DEFERRED &&
haitaol1 2014/02/20 00:01:06 I think the code can be simplified if this block i
tim (not reviewing) 2014/02/20 22:52:52 I played around with this and it gets a little mes
haitaol1 2014/02/25 00:53:01 fair enough On 2014/02/20 22:52:52, timsteele wro
+ CommandLine::ForCurrentProcess()->
+ HasSwitch(switches::kSyncEnableDeferredStartup)) {
+ if (first_start) {
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&StartupController::OnFallbackStartupTimerExpired,
+ weak_factory_.GetWeakPtr()), fallback_timeout_);
+ }
+ return;
+ }
+
+ start_backend_time_ = base::Time::Now();
+ start_backend_.Run();
+}
+
+void StartupController::OverrideFallbackTimeoutForTest(
+ const base::TimeDelta& timeout) {
+ fallback_timeout_ = timeout;
+}
+
+void StartupController::TryStart() {
haitaol1 2014/02/20 00:01:06 can you return a bool to indicate whether the cond
tim (not reviewing) 2014/02/20 22:52:52 Done.
+ if (sync_prefs_->IsManaged())
+ return;
+
+ if (sync_prefs_->IsStartSuppressed())
+ return;
+
+ if (signin_->GetEffectiveUsername().empty())
+ return;
+
+ if (!token_service_)
+ return;
+
+ if (!token_service_->RefreshTokenIsAvailable(
+ signin_->GetAccountIdToUse())) {
+ return;
+ }
+
+ // TODO(tim): Seems wrong to always record this histogram here...
+ // If we got here then tokens are loaded and user logged in and sync is
+ // enabled. If OAuth refresh token is not available then something is wrong.
+ // When PSS requests access token, OAuth2TokenService will return error and
+ // PSS will show error to user asking to reauthenticate.
+ UMA_HISTOGRAM_BOOLEAN("Sync.RefreshTokenAvailable", true);
+
+ // If sync setup has completed we always start the backend. If the user is in
+ // the process of setting up now, we should start the backend to download
+ // account control state / encryption information). If autostart is enabled,
+ // but we haven't completed sync setup, we try to start sync anyway, since
+ // it's possible we crashed/shutdown after logging in but before the backend
+ // finished initializing the last time.
+ //
+ // However, the only time we actually need to start sync _immediately_ is if
+ // we haven't completed sync setup and the user is in the process of setting
+ // up - either they just signed in (for the first time) on an auto-start
+ // platform or they explicitly kicked off sync setup, and e.g we need to
+ // fetch account details like encryption state to populate UI. Otherwise,
+ // for performance reasons and maximizing parallelism at chrome startup, we
+ // defer the heavy lifting for sync init until things have calmed down.
+ if (sync_prefs_->HasSyncSetupCompleted()) {
+ if (!received_start_request_)
+ StartUp(STARTUP_BACKEND_DEFERRED);
+ else
+ StartUp(STARTUP_IMMEDIATE);
+ } else if (setup_in_progress_ || auto_start_enabled_) {
+ // We haven't completed sync setup. Start immediately if the user explicitly
+ // kicked this off or we're supposed to automatically start syncing.
+ StartUp(STARTUP_IMMEDIATE);
+ }
+}
+
+void StartupController::OnFallbackStartupTimerExpired() {
+ DCHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSyncEnableDeferredStartup));
+
+ if (!start_backend_time_.is_null())
+ return;
+
+ DVLOG(2) << "Sync deferred init fallback timer expired, starting backend.";
+ DCHECK(!start_up_time_.is_null());
+ base::TimeDelta time_deferred = base::Time::Now() - start_up_time_;
+ UMA_HISTOGRAM_TIMES("Sync.Startup.TimeDeferred", time_deferred);
+ UMA_HISTOGRAM_ENUMERATION("Sync.Startup.DeferredInitTrigger",
+ TRIGGER_FALLBACK_TIMER,
+ MAX_TRIGGER_VALUE);
+ received_start_request_ = true;
+ TryStart();
haitaol1 2014/02/20 00:01:06 can you call StartUp() here?
tim (not reviewing) 2014/02/20 22:52:52 The current model and one I'd like to stick to is
+}
+
+std::string StartupController::GetBackendInitializationStateString() const {
+ if (!start_backend_time_.is_null())
+ return "Started";
+ else if (!start_up_time_.is_null())
+ return "Deferred";
+ else
+ return "Not started";
+}
+
+void StartupController::OnDataTypeRequestsSyncStartup(syncer::ModelType type) {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSyncEnableDeferredStartup)) {
+ DVLOG(2) << "Ignoring data type request for sync startup: "
+ << syncer::ModelTypeToString(type);
+ return;
+ }
+
+ if (!start_backend_time_.is_null())
+ return;
+
+ DVLOG(2) << "Data type requesting sync startup: "
+ << syncer::ModelTypeToString(type);
+ // Measure the time spent waiting for init and the type that triggered it.
+ // We could measure the time spent deferred on a per-datatype basis, but
+ // for now this is probably sufficient.
+ if (!start_up_time_.is_null()) {
+ base::TimeDelta time_deferred = base::Time::Now() - start_up_time_;
+ UMA_HISTOGRAM_TIMES("Sync.Startup.TimeDeferred", time_deferred);
+ UMA_HISTOGRAM_ENUMERATION("Sync.Startup.TypeTriggeringInit",
haitaol1 2014/02/20 00:01:06 This UMA and the one below don't have to be in if{
tim (not reviewing) 2014/02/20 22:52:52 That data-type filtering is handled by the caller.
haitaol1 2014/02/25 00:53:01 I'm more concerned that backend is started by disa
tim (not reviewing) 2014/02/25 01:17:44 No, I don't believe so, because the caller (PSS) i
+ ModelTypeToHistogramInt(type),
+ syncer::MODEL_TYPE_COUNT);
+ UMA_HISTOGRAM_ENUMERATION("Sync.Startup.DeferredInitTrigger",
+ TRIGGER_DATA_TYPE_REQUEST,
+ MAX_TRIGGER_VALUE);
+ }
+ received_start_request_ = true;
+ TryStart();
+}
+
+} // namespace browser_sync

Powered by Google App Engine
This is Rietveld 408576698