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

Unified Diff: chrome/browser/sync/glue/sync_backend_host.cc

Issue 23717047: Retry: sync: Gracefully handle early shutdown (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Minor comment and style improvements Created 7 years, 3 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/glue/sync_backend_host.cc
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index 2f91728d69096ca2a55838b0e751a67550093421..5648350c58c786e369ca1801f69433bc8ba10d70 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -198,12 +198,13 @@ class SyncBackendHost::Core
void DoFinishInitialProcessControlTypes();
// The shutdown order is a bit complicated:
- // 1) Call DoStopSyncManagerForShutdown() from |frontend_loop_| to request
- // sync manager to stop as soon as possible.
+ // 1) Call the SyncManagerStopHandle's RequestStop() from |frontend_loop_| to
+ // request sync manager to stop as soon as possible.
// 2) Post DoShutdown() to sync loop to clean up backend state, save
// directory and destroy sync manager.
- void DoStopSyncManagerForShutdown();
- void DoShutdown(bool sync_disabled);
+ void DoShutdown(bool sync_disabled,
+ scoped_ptr<syncer::CancelationSignal> signal1,
tim (not reviewing) 2013/09/16 18:30:11 Explain here why we pass ownership of these signal
rlarocque 2013/09/16 18:39:09 It's explained in a comment near where this functi
+ scoped_ptr<syncer::CancelationSignal> signal2);
void DoDestroySyncManager();
// Configuration methods that must execute on sync loop.
@@ -305,7 +306,9 @@ SyncBackendHost::SyncBackendHost(
cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE),
invalidator_(
invalidation::InvalidationServiceFactory::GetForProfile(profile)),
- invalidation_handler_registered_(false) {
+ invalidation_handler_registered_(false),
+ factory_cancelation_signal_(new syncer::CancelationSignal()),
+ scm_cancelation_signal_(new syncer::CancelationSignal()) {
}
SyncBackendHost::SyncBackendHost(Profile* profile)
@@ -324,21 +327,6 @@ SyncBackendHost::~SyncBackendHost() {
DCHECK(!registrar_.get());
}
-namespace {
-
-scoped_ptr<syncer::HttpPostProviderFactory> MakeHttpBridgeFactory(
- const scoped_refptr<net::URLRequestContextGetter>& getter,
- const NetworkTimeTracker::UpdateCallback& update_callback) {
- chrome::VersionInfo version_info;
- return scoped_ptr<syncer::HttpPostProviderFactory>(
- new syncer::HttpBridgeFactory(
- getter.get(),
- DeviceInfo::MakeUserAgentForSyncApi(version_info),
- update_callback));
-}
-
-} // namespace
-
void SyncBackendHost::Initialize(
SyncFrontend* frontend,
scoped_ptr<base::Thread> sync_thread,
@@ -388,9 +376,11 @@ void SyncBackendHost::Initialize(
extensions_activity_monitor_.GetExtensionsActivity(),
event_handler,
sync_service_url,
- base::Bind(&MakeHttpBridgeFactory,
- make_scoped_refptr(profile_->GetRequestContext()),
- NetworkTimeTracker::BuildNotifierUpdateCallback()),
+ scoped_ptr<syncer::HttpPostProviderFactory>(
+ new syncer::HttpBridgeFactory(
+ make_scoped_refptr(profile_->GetRequestContext()),
+ NetworkTimeTracker::BuildNotifierUpdateCallback(),
+ factory_cancelation_signal_.get())),
credentials,
invalidator_->GetInvalidatorClientId(),
sync_manager_factory.Pass(),
@@ -401,7 +391,8 @@ void SyncBackendHost::Initialize(
new InternalComponentsFactoryImpl(factory_switches)).Pass(),
unrecoverable_error_handler.Pass(),
report_unrecoverable_error_function,
- !cl->HasSwitch(switches::kSyncDisableOAuth2Token)));
+ !cl->HasSwitch(switches::kSyncDisableOAuth2Token),
+ scm_cancelation_signal_.get()));
InitCore(init_opts.Pass());
}
@@ -492,24 +483,9 @@ bool SyncBackendHost::SetDecryptionPassphrase(const std::string& passphrase) {
return true;
}
-void SyncBackendHost::StopSyncManagerForShutdown() {
- DCHECK_GT(initialization_state_, NOT_ATTEMPTED);
- if (initialization_state_ == CREATING_SYNC_MANAGER) {
- // We post here to implicitly wait for the SyncManager to be created,
- // if needed. We have to wait, since we need to shutdown immediately,
- // and we need to tell the SyncManager so it can abort any activity
- // (net I/O, data application).
- DCHECK(registrar_->sync_thread()->IsRunning());
- registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
- base::Bind(&SyncBackendHost::Core::DoStopSyncManagerForShutdown,
- core_.get()));
- } else {
- core_->DoStopSyncManagerForShutdown();
- }
-}
-
void SyncBackendHost::StopSyncingForShutdown() {
DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
+ DCHECK_GT(initialization_state_, NOT_ATTEMPTED);
// Immediately stop sending messages to the frontend.
frontend_ = NULL;
@@ -521,7 +497,24 @@ void SyncBackendHost::StopSyncingForShutdown() {
registrar_->RequestWorkerStopOnUIThread();
- StopSyncManagerForShutdown();
+ // This will cut short any blocking network tasks, cut short any in-progress
+ // sync cycles, and prevent the creation of new blocking network tasks and new
+ // sync cycles. If there was an in-progress network request, it would have
+ // had a reference to the RequestContextGetter. This reference will be
+ // dropped by the time this function returns.
+ //
+ // It is safe to call this even if Sync's backend classes have not been
+ // initialized yet. Those classes will receive the message when the sync
+ // thread finally getes around to constructing them.
+ scm_cancelation_signal_->RequestStop();
+
+ // This will drop the HttpBridgeFactory's reference to the
+ // RequestContextGetter. Once this has been called, the HttpBridgeFactory can
+ // no longer be used to create new HttpBridge instances. We can get away with
+ // this because the scm_cancelation_signal_ has already been signalled, which
+ // guarantees that the ServerConnectionManager will no longer attempt to
+ // create new connections.
+ factory_cancelation_signal_->RequestStop();
}
scoped_ptr<base::Thread> SyncBackendHost::Shutdown(ShutdownOption option) {
@@ -544,10 +537,23 @@ scoped_ptr<base::Thread> SyncBackendHost::Shutdown(ShutdownOption option) {
invalidation_handler_registered_ = false;
// Shut down and destroy sync manager.
+ //
+ // We're about to drop our reference to the |core_|. The only thing keeping
+ // it alive will be the reference that lives inside this closure we're about
+ // to post to the sync thread. If this closure doesn't run right away, it's
+ // possible that our Core will outlive us.
+ //
+ // This is a problem for the CancelationSignals, which must outlive the
+ // classes that reference them. In this case, it is safe to destroy them only
+ // after the call to DoDestroySyncManager completes. The SyncBackendHost
+ // might not live that long, but this closure will. We pass ownership of the
+ // CancelationSignals to this closure to keep them alive.
registrar_->sync_thread()->message_loop()->PostTask(
FROM_HERE,
base::Bind(&SyncBackendHost::Core::DoShutdown,
- core_.get(), sync_disabled));
+ core_.get(), sync_disabled,
+ base::Passed(&factory_cancelation_signal_),
+ base::Passed(&scm_cancelation_signal_)));
core_ = NULL;
// Worker cleanup.
@@ -872,7 +878,7 @@ SyncBackendHost::DoInitializeOptions::DoInitializeOptions(
const scoped_refptr<syncer::ExtensionsActivity>& extensions_activity,
const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
const GURL& service_url,
- MakeHttpBridgeFactoryFn make_http_bridge_factory_fn,
+ scoped_ptr<syncer::HttpPostProviderFactory> http_bridge_factory,
const syncer::SyncCredentials& credentials,
const std::string& invalidator_client_id,
scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
@@ -883,7 +889,8 @@ SyncBackendHost::DoInitializeOptions::DoInitializeOptions(
scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
syncer::ReportUnrecoverableErrorFunction
report_unrecoverable_error_function,
- bool use_oauth2_token)
+ bool use_oauth2_token,
+ syncer::CancelationSignal* const scm_cancelation_signal)
: sync_loop(sync_loop),
registrar(registrar),
routing_info(routing_info),
@@ -891,7 +898,7 @@ SyncBackendHost::DoInitializeOptions::DoInitializeOptions(
extensions_activity(extensions_activity),
event_handler(event_handler),
service_url(service_url),
- make_http_bridge_factory_fn(make_http_bridge_factory_fn),
+ http_bridge_factory(http_bridge_factory.Pass()),
credentials(credentials),
invalidator_client_id(invalidator_client_id),
sync_manager_factory(sync_manager_factory.Pass()),
@@ -903,7 +910,8 @@ SyncBackendHost::DoInitializeOptions::DoInitializeOptions(
unrecoverable_error_handler(unrecoverable_error_handler.Pass()),
report_unrecoverable_error_function(
report_unrecoverable_error_function),
- use_oauth2_token(use_oauth2_token) {
+ use_oauth2_token(use_oauth2_token),
+ scm_cancelation_signal(scm_cancelation_signal) {
}
SyncBackendHost::DoInitializeOptions::~DoInitializeOptions() {}
@@ -1133,6 +1141,12 @@ void SyncBackendHost::Core::DoInitialize(
sync_loop_ = options->sync_loop;
DCHECK(sync_loop_);
+ // Finish initializing the HttpBridgeFactory. We do this here because
+ // building the user agent may block on some platforms.
+ chrome::VersionInfo version_info;
+ options->http_bridge_factory->Init(
+ DeviceInfo::MakeUserAgentForSyncApi(version_info));
+
// Blow away the partial or corrupt sync data folder before doing any more
// initialization, if necessary.
if (options->delete_sync_data_folder) {
@@ -1156,7 +1170,7 @@ void SyncBackendHost::Core::DoInitialize(
options->service_url.host() + options->service_url.path(),
options->service_url.EffectiveIntPort(),
options->service_url.SchemeIsSecure(),
- options->make_http_bridge_factory_fn.Run().Pass(),
+ options->http_bridge_factory.Pass(),
options->workers,
options->extensions_activity,
options->registrar /* as SyncManager::ChangeDelegate */,
@@ -1168,7 +1182,8 @@ void SyncBackendHost::Core::DoInitialize(
&encryptor_,
options->unrecoverable_error_handler.Pass(),
options->report_unrecoverable_error_function,
- options->use_oauth2_token);
+ options->use_oauth2_token,
+ options->scm_cancelation_signal);
// |sync_manager_| may end up being NULL here in tests (in
// synchronous initialization mode).
@@ -1278,13 +1293,12 @@ void SyncBackendHost::Core::DoEnableEncryptEverything() {
sync_manager_->GetEncryptionHandler()->EnableEncryptEverything();
}
-void SyncBackendHost::Core::DoStopSyncManagerForShutdown() {
- if (sync_manager_)
- sync_manager_->StopSyncingForShutdown();
-}
-
-void SyncBackendHost::Core::DoShutdown(bool sync_disabled) {
+void SyncBackendHost::Core::DoShutdown(
+ bool sync_disabled,
+ scoped_ptr<syncer::CancelationSignal> signal1,
+ scoped_ptr<syncer::CancelationSignal> signal2) {
DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
+
// It's safe to do this even if the type was never activated.
registrar_->DeactivateDataType(syncer::DEVICE_INFO);
synced_device_tracker_.reset();

Powered by Google App Engine
This is Rietveld 408576698