1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/sync/glue/sync_backend_host_core.h"
7 #include "base/command_line.h"
8 #include "base/file_util.h"
9 #include "base/metrics/histogram.h"
10 #include "chrome/browser/sync/glue/device_info.h"
11 #include "chrome/browser/sync/glue/sync_backend_registrar.h"
12 #include "chrome/browser/sync/glue/synced_device_tracker.h"
13 #include "chrome/common/chrome_switches.h"
14 #include "chrome/common/chrome_version_info.h"
15 #include "sync/internal_api/public/http_post_provider_factory.h"
16 #include "sync/internal_api/public/internal_components_factory.h"
17 #include "sync/internal_api/public/sessions/sync_session_snapshot.h"
18 #include "sync/internal_api/public/sync_manager.h"
19 #include "sync/internal_api/public/sync_manager_factory.h"
21 // Helper macros to log with the syncer thread name; useful when there
22 // are multiple syncers involved.
24 #define SLOG(severity) LOG(severity) << name_ << ": "
26 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
28 static const int kSaveChangesIntervalSeconds
= 10;
31 class InternalComponentsFactory
;
37 enum SyncBackendInitState
{
38 SETUP_COMPLETED_FOUND_RESTORED_TYPES
= 0,
39 SETUP_COMPLETED_NO_RESTORED_TYPES
,
40 FIRST_SETUP_NO_RESTORED_TYPES
,
41 FIRST_SETUP_RESTORED_TYPES
,
42 SYNC_BACKEND_INIT_STATE_COUNT
47 namespace browser_sync
{
49 DoInitializeOptions::DoInitializeOptions(
50 base::MessageLoop
* sync_loop
,
51 SyncBackendRegistrar
* registrar
,
52 const syncer::ModelSafeRoutingInfo
& routing_info
,
53 const std::vector
<scoped_refptr
<syncer::ModelSafeWorker
> >& workers
,
54 const scoped_refptr
<syncer::ExtensionsActivity
>& extensions_activity
,
55 const syncer::WeakHandle
<syncer::JsEventHandler
>& event_handler
,
56 const GURL
& service_url
,
57 scoped_ptr
<syncer::HttpPostProviderFactory
> http_bridge_factory
,
58 const syncer::SyncCredentials
& credentials
,
59 const std::string
& invalidator_client_id
,
60 scoped_ptr
<syncer::SyncManagerFactory
> sync_manager_factory
,
61 bool delete_sync_data_folder
,
62 const std::string
& restored_key_for_bootstrapping
,
63 const std::string
& restored_keystore_key_for_bootstrapping
,
64 scoped_ptr
<syncer::InternalComponentsFactory
> internal_components_factory
,
65 scoped_ptr
<syncer::UnrecoverableErrorHandler
> unrecoverable_error_handler
,
66 syncer::ReportUnrecoverableErrorFunction
67 report_unrecoverable_error_function
)
68 : sync_loop(sync_loop
),
70 routing_info(routing_info
),
72 extensions_activity(extensions_activity
),
73 event_handler(event_handler
),
74 service_url(service_url
),
75 http_bridge_factory(http_bridge_factory
.Pass()),
76 credentials(credentials
),
77 invalidator_client_id(invalidator_client_id
),
78 sync_manager_factory(sync_manager_factory
.Pass()),
79 delete_sync_data_folder(delete_sync_data_folder
),
80 restored_key_for_bootstrapping(restored_key_for_bootstrapping
),
81 restored_keystore_key_for_bootstrapping(
82 restored_keystore_key_for_bootstrapping
),
83 internal_components_factory(internal_components_factory
.Pass()),
84 unrecoverable_error_handler(unrecoverable_error_handler
.Pass()),
85 report_unrecoverable_error_function(
86 report_unrecoverable_error_function
) {
89 DoInitializeOptions::~DoInitializeOptions() {}
91 DoConfigureSyncerTypes::DoConfigureSyncerTypes() {}
93 DoConfigureSyncerTypes::~DoConfigureSyncerTypes() {}
95 SyncBackendHostCore::SyncBackendHostCore(
96 const std::string
& name
,
97 const base::FilePath
& sync_data_folder_path
,
98 bool has_sync_setup_completed
,
99 const base::WeakPtr
<SyncBackendHostImpl
>& backend
)
101 sync_data_folder_path_(sync_data_folder_path
),
105 has_sync_setup_completed_(has_sync_setup_completed
),
106 weak_ptr_factory_(this) {
107 DCHECK(backend
.get());
110 SyncBackendHostCore::~SyncBackendHostCore() {
111 DCHECK(!sync_manager_
.get());
114 void SyncBackendHostCore::OnSyncCycleCompleted(
115 const syncer::sessions::SyncSessionSnapshot
& snapshot
) {
118 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
122 &SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop
,
126 void SyncBackendHostCore::DoRefreshTypes(syncer::ModelTypeSet types
) {
127 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
128 sync_manager_
->RefreshTypes(types
);
131 void SyncBackendHostCore::OnControlTypesDownloadRetry() {
132 host_
.Call(FROM_HERE
,
133 &SyncBackendHostImpl::HandleControlTypesDownloadRetry
);
136 void SyncBackendHostCore::OnInitializationComplete(
137 const syncer::WeakHandle
<syncer::JsBackend
>& js_backend
,
138 const syncer::WeakHandle
<syncer::DataTypeDebugInfoListener
>&
141 const syncer::ModelTypeSet restored_types
) {
142 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
145 DoDestroySyncManager();
146 host_
.Call(FROM_HERE
,
147 &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop
);
151 // Register for encryption related changes now. We have to do this before
152 // the initializing downloading control types or initializing the encryption
153 // handler in order to receive notifications triggered during encryption
155 sync_manager_
->GetEncryptionHandler()->AddObserver(this);
157 // Sync manager initialization is complete, so we can schedule recurring
159 sync_loop_
->PostTask(FROM_HERE
,
160 base::Bind(&SyncBackendHostCore::StartSavingChanges
,
161 weak_ptr_factory_
.GetWeakPtr()));
163 // Hang on to these for a while longer. We're not ready to hand them back to
164 // the UI thread yet.
165 js_backend_
= js_backend
;
166 debug_info_listener_
= debug_info_listener
;
168 // Track whether or not sync DB and preferences were in sync.
169 SyncBackendInitState backend_init_state
;
170 if (has_sync_setup_completed_
&& !restored_types
.Empty()) {
171 backend_init_state
= SETUP_COMPLETED_FOUND_RESTORED_TYPES
;
172 } else if (has_sync_setup_completed_
&& restored_types
.Empty()) {
173 backend_init_state
= SETUP_COMPLETED_NO_RESTORED_TYPES
;
174 } else if (!has_sync_setup_completed_
&& restored_types
.Empty()) {
175 backend_init_state
= FIRST_SETUP_NO_RESTORED_TYPES
;
176 } else { // (!has_sync_setup_completed_ && !restored_types.Empty())
177 backend_init_state
= FIRST_SETUP_RESTORED_TYPES
;
180 UMA_HISTOGRAM_ENUMERATION("Sync.BackendInitializeRestoreState",
182 SYNC_BACKEND_INIT_STATE_COUNT
);
184 // Before proceeding any further, we need to download the control types and
185 // purge any partial data (ie. data downloaded for a type that was on its way
186 // to being initially synced, but didn't quite make it.). The following
187 // configure cycle will take care of this. It depends on the registrar state
188 // which we initialize below to ensure that we don't perform any downloads if
189 // all control types have already completed their initial sync.
190 registrar_
->SetInitialTypes(restored_types
);
192 syncer::ConfigureReason reason
=
193 restored_types
.Empty() ?
194 syncer::CONFIGURE_REASON_NEW_CLIENT
:
195 syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE
;
197 syncer::ModelTypeSet new_control_types
= registrar_
->ConfigureDataTypes(
198 syncer::ControlTypes(), syncer::ModelTypeSet());
199 syncer::ModelSafeRoutingInfo routing_info
;
200 registrar_
->GetModelSafeRoutingInfo(&routing_info
);
201 SDVLOG(1) << "Control Types "
202 << syncer::ModelTypeSetToString(new_control_types
)
203 << " added; calling ConfigureSyncer";
205 syncer::ModelTypeSet types_to_purge
=
206 syncer::Difference(syncer::ModelTypeSet::All(),
207 GetRoutingInfoTypes(routing_info
));
209 sync_manager_
->ConfigureSyncer(
213 syncer::ModelTypeSet(),
214 syncer::ModelTypeSet(),
216 base::Bind(&SyncBackendHostCore::DoInitialProcessControlTypes
,
217 weak_ptr_factory_
.GetWeakPtr()),
218 base::Bind(&SyncBackendHostCore::OnControlTypesDownloadRetry
,
219 weak_ptr_factory_
.GetWeakPtr()));
222 void SyncBackendHostCore::OnConnectionStatusChange(
223 syncer::ConnectionStatus status
) {
226 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
229 &SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop
, status
);
232 void SyncBackendHostCore::OnPassphraseRequired(
233 syncer::PassphraseRequiredReason reason
,
234 const sync_pb::EncryptedData
& pending_keys
) {
237 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
240 &SyncBackendHostImpl::NotifyPassphraseRequired
, reason
, pending_keys
);
243 void SyncBackendHostCore::OnPassphraseAccepted() {
246 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
249 &SyncBackendHostImpl::NotifyPassphraseAccepted
);
252 void SyncBackendHostCore::OnBootstrapTokenUpdated(
253 const std::string
& bootstrap_token
,
254 syncer::BootstrapTokenType type
) {
257 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
258 host_
.Call(FROM_HERE
,
259 &SyncBackendHostImpl::PersistEncryptionBootstrapToken
,
264 void SyncBackendHostCore::OnStopSyncingPermanently() {
267 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
270 &SyncBackendHostImpl::HandleStopSyncingPermanentlyOnFrontendLoop
);
273 void SyncBackendHostCore::OnEncryptedTypesChanged(
274 syncer::ModelTypeSet encrypted_types
,
275 bool encrypt_everything
) {
278 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
279 // NOTE: We're in a transaction.
282 &SyncBackendHostImpl::NotifyEncryptedTypesChanged
,
283 encrypted_types
, encrypt_everything
);
286 void SyncBackendHostCore::OnEncryptionComplete() {
289 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
290 // NOTE: We're in a transaction.
293 &SyncBackendHostImpl::NotifyEncryptionComplete
);
296 void SyncBackendHostCore::OnCryptographerStateChanged(
297 syncer::Cryptographer
* cryptographer
) {
301 void SyncBackendHostCore::OnPassphraseTypeChanged(
302 syncer::PassphraseType type
, base::Time passphrase_time
) {
305 &SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop
,
306 type
, passphrase_time
);
309 void SyncBackendHostCore::OnActionableError(
310 const syncer::SyncProtocolError
& sync_error
) {
313 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
316 &SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop
,
320 void SyncBackendHostCore::DoOnInvalidatorStateChange(
321 syncer::InvalidatorState state
) {
322 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
323 sync_manager_
->OnInvalidatorStateChange(state
);
326 void SyncBackendHostCore::DoOnIncomingInvalidation(
327 const syncer::ObjectIdInvalidationMap
& invalidation_map
) {
328 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
329 sync_manager_
->OnIncomingInvalidation(invalidation_map
);
332 void SyncBackendHostCore::DoInitialize(
333 scoped_ptr
<DoInitializeOptions
> options
) {
335 sync_loop_
= options
->sync_loop
;
338 // Finish initializing the HttpBridgeFactory. We do this here because
339 // building the user agent may block on some platforms.
340 chrome::VersionInfo version_info
;
341 options
->http_bridge_factory
->Init(
342 DeviceInfo::MakeUserAgentForSyncApi(version_info
));
344 // Blow away the partial or corrupt sync data folder before doing any more
345 // initialization, if necessary.
346 if (options
->delete_sync_data_folder
) {
347 DeleteSyncDataFolder();
350 // Make sure that the directory exists before initializing the backend.
351 // If it already exists, this will do no harm.
352 if (!base::CreateDirectory(sync_data_folder_path_
)) {
353 DLOG(FATAL
) << "Sync Data directory creation failed.";
357 registrar_
= options
->registrar
;
360 sync_manager_
= options
->sync_manager_factory
->CreateSyncManager(name_
);
361 sync_manager_
->AddObserver(this);
362 sync_manager_
->Init(sync_data_folder_path_
,
363 options
->event_handler
,
364 options
->service_url
.host() + options
->service_url
.path(),
365 options
->service_url
.EffectiveIntPort(),
366 options
->service_url
.SchemeIsSecure(),
367 options
->http_bridge_factory
.Pass(),
369 options
->extensions_activity
,
370 options
->registrar
/* as SyncManager::ChangeDelegate */,
371 options
->credentials
,
372 options
->invalidator_client_id
,
373 options
->restored_key_for_bootstrapping
,
374 options
->restored_keystore_key_for_bootstrapping
,
375 options
->internal_components_factory
.get(),
377 options
->unrecoverable_error_handler
.Pass(),
378 options
->report_unrecoverable_error_function
,
379 &stop_syncing_signal_
);
381 // |sync_manager_| may end up being NULL here in tests (in
382 // synchronous initialization mode).
384 // TODO(akalin): Fix this behavior (see http://crbug.com/140354).
386 // Now check the command line to see if we need to simulate an
387 // unrecoverable error for testing purpose. Note the error is thrown
388 // only if the initialization succeeded. Also it makes sense to use this
389 // flag only when restarting the browser with an account already setup. If
390 // you use this before setting up the setup would not succeed as an error
391 // would be encountered.
392 if (CommandLine::ForCurrentProcess()->HasSwitch(
393 switches::kSyncThrowUnrecoverableError
)) {
394 sync_manager_
->ThrowUnrecoverableError();
399 void SyncBackendHostCore::DoUpdateCredentials(
400 const syncer::SyncCredentials
& credentials
) {
401 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
402 // UpdateCredentials can be called during backend initialization, possibly
403 // when backend initialization has failed but hasn't notified the UI thread
404 // yet. In that case, the sync manager may have been destroyed on the sync
405 // thread before this task was executed, so we do nothing.
407 sync_manager_
->UpdateCredentials(credentials
);
411 void SyncBackendHostCore::DoStartSyncing(
412 const syncer::ModelSafeRoutingInfo
& routing_info
) {
413 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
414 sync_manager_
->StartSyncingNormally(routing_info
);
417 void SyncBackendHostCore::DoSetEncryptionPassphrase(
418 const std::string
& passphrase
,
420 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
421 sync_manager_
->GetEncryptionHandler()->SetEncryptionPassphrase(
422 passphrase
, is_explicit
);
425 void SyncBackendHostCore::DoInitialProcessControlTypes() {
426 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
428 DVLOG(1) << "Initilalizing Control Types";
430 // Initialize encryption.
431 sync_manager_
->GetEncryptionHandler()->Init();
433 // Note: experiments are currently handled via SBH::AddExperimentalTypes,
434 // which is called at the end of every sync cycle.
435 // TODO(zea): eventually add an experiment handler and initialize it here.
437 if (!sync_manager_
->GetUserShare()) { // NULL in some tests.
438 DVLOG(1) << "Skipping initialization of DeviceInfo";
441 &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop
);
445 if (!sync_manager_
->InitialSyncEndedTypes().HasAll(syncer::ControlTypes())) {
446 LOG(ERROR
) << "Failed to download control types";
449 &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop
);
453 // Initialize device info. This is asynchronous on some platforms, so we
454 // provide a callback for when it finishes.
455 synced_device_tracker_
.reset(
456 new SyncedDeviceTracker(sync_manager_
->GetUserShare(),
457 sync_manager_
->cache_guid()));
458 synced_device_tracker_
->InitLocalDeviceInfo(
459 base::Bind(&SyncBackendHostCore::DoFinishInitialProcessControlTypes
,
460 weak_ptr_factory_
.GetWeakPtr()));
463 void SyncBackendHostCore::DoFinishInitialProcessControlTypes() {
464 registrar_
->ActivateDataType(syncer::DEVICE_INFO
,
465 syncer::GROUP_PASSIVE
,
466 synced_device_tracker_
.get(),
467 sync_manager_
->GetUserShare());
471 &SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop
,
473 debug_info_listener_
);
476 debug_info_listener_
.Reset();
479 void SyncBackendHostCore::DoSetDecryptionPassphrase(
480 const std::string
& passphrase
) {
481 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
482 sync_manager_
->GetEncryptionHandler()->SetDecryptionPassphrase(
486 void SyncBackendHostCore::DoEnableEncryptEverything() {
487 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
488 sync_manager_
->GetEncryptionHandler()->EnableEncryptEverything();
491 void SyncBackendHostCore::ShutdownOnUIThread() {
492 // This will cut short any blocking network tasks, cut short any in-progress
493 // sync cycles, and prevent the creation of new blocking network tasks and new
494 // sync cycles. If there was an in-progress network request, it would have
495 // had a reference to the RequestContextGetter. This reference will be
496 // dropped by the time this function returns.
498 // It is safe to call this even if Sync's backend classes have not been
499 // initialized yet. Those classes will receive the message when the sync
500 // thread finally getes around to constructing them.
501 stop_syncing_signal_
.Signal();
503 // This will drop the HttpBridgeFactory's reference to the
504 // RequestContextGetter. Once this has been called, the HttpBridgeFactory can
505 // no longer be used to create new HttpBridge instances. We can get away with
506 // this because the stop_syncing_signal_ has already been signalled, which
507 // guarantees that the ServerConnectionManager will no longer attempt to
508 // create new connections.
509 release_request_context_signal_
.Signal();
512 void SyncBackendHostCore::DoShutdown(bool sync_disabled
) {
513 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
515 // It's safe to do this even if the type was never activated.
516 registrar_
->DeactivateDataType(syncer::DEVICE_INFO
);
517 synced_device_tracker_
.reset();
519 DoDestroySyncManager();
524 DeleteSyncDataFolder();
527 weak_ptr_factory_
.InvalidateWeakPtrs();
530 void SyncBackendHostCore::DoDestroySyncManager() {
531 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
533 save_changes_timer_
.reset();
534 sync_manager_
->RemoveObserver(this);
535 sync_manager_
->ShutdownOnSyncThread();
536 sync_manager_
.reset();
540 void SyncBackendHostCore::DoConfigureSyncer(
541 syncer::ConfigureReason reason
,
542 const DoConfigureSyncerTypes
& config_types
,
543 const syncer::ModelSafeRoutingInfo routing_info
,
544 const base::Callback
<void(syncer::ModelTypeSet
,
545 syncer::ModelTypeSet
)>& ready_task
,
546 const base::Closure
& retry_callback
) {
547 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
548 sync_manager_
->ConfigureSyncer(
550 config_types
.to_download
,
551 config_types
.to_purge
,
552 config_types
.to_journal
,
553 config_types
.to_unapply
,
555 base::Bind(&SyncBackendHostCore::DoFinishConfigureDataTypes
,
556 weak_ptr_factory_
.GetWeakPtr(),
557 config_types
.to_download
,
559 base::Bind(&SyncBackendHostCore::DoRetryConfiguration
,
560 weak_ptr_factory_
.GetWeakPtr(),
564 void SyncBackendHostCore::DoFinishConfigureDataTypes(
565 syncer::ModelTypeSet types_to_config
,
566 const base::Callback
<void(syncer::ModelTypeSet
,
567 syncer::ModelTypeSet
)>& ready_task
) {
568 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
570 // Update the enabled types for the bridge and sync manager.
571 syncer::ModelSafeRoutingInfo routing_info
;
572 registrar_
->GetModelSafeRoutingInfo(&routing_info
);
573 syncer::ModelTypeSet enabled_types
= GetRoutingInfoTypes(routing_info
);
574 enabled_types
.RemoveAll(syncer::ProxyTypes());
576 const syncer::ModelTypeSet failed_configuration_types
=
577 Difference(types_to_config
, sync_manager_
->InitialSyncEndedTypes());
578 const syncer::ModelTypeSet succeeded_configuration_types
=
579 Difference(types_to_config
, failed_configuration_types
);
580 host_
.Call(FROM_HERE
,
581 &SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop
,
583 succeeded_configuration_types
,
584 failed_configuration_types
,
588 void SyncBackendHostCore::DoRetryConfiguration(
589 const base::Closure
& retry_callback
) {
590 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
591 host_
.Call(FROM_HERE
,
592 &SyncBackendHostImpl::RetryConfigurationOnFrontendLoop
,
596 void SyncBackendHostCore::DeleteSyncDataFolder() {
597 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
598 if (base::DirectoryExists(sync_data_folder_path_
)) {
599 if (!base::DeleteFile(sync_data_folder_path_
, true))
600 SLOG(DFATAL
) << "Could not delete the Sync Data folder.";
604 void SyncBackendHostCore::StartSavingChanges() {
605 // We may already be shut down.
608 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
609 DCHECK(!save_changes_timer_
.get());
610 save_changes_timer_
.reset(new base::RepeatingTimer
<SyncBackendHostCore
>());
611 save_changes_timer_
->Start(FROM_HERE
,
612 base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds
),
613 this, &SyncBackendHostCore::SaveChanges
);
616 void SyncBackendHostCore::SaveChanges() {
617 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
618 sync_manager_
->SaveChanges();
621 } // namespace browser_sync