Chromium Code Reviews| 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(); |