Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / glue / sync_backend_host_core.cc
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.
4
5 #include "chrome/browser/sync/glue/sync_backend_host_core.h"
6
7 #include "base/files/file_util.h"
8 #include "base/metrics/histogram.h"
9 #include "chrome/browser/sync/glue/invalidation_adapter.h"
10 #include "chrome/browser/sync/glue/local_device_info_provider_impl.h"
11 #include "chrome/browser/sync/glue/sync_backend_registrar.h"
12 #include "chrome/common/chrome_version_info.h"
13 #include "components/invalidation/invalidation_util.h"
14 #include "components/invalidation/object_id_invalidation_map.h"
15 #include "sync/internal_api/public/events/protocol_event.h"
16 #include "sync/internal_api/public/http_post_provider_factory.h"
17 #include "sync/internal_api/public/internal_components_factory.h"
18 #include "sync/internal_api/public/sessions/commit_counters.h"
19 #include "sync/internal_api/public/sessions/status_counters.h"
20 #include "sync/internal_api/public/sessions/sync_session_snapshot.h"
21 #include "sync/internal_api/public/sessions/update_counters.h"
22 #include "sync/internal_api/public/sync_context_proxy.h"
23 #include "sync/internal_api/public/sync_manager.h"
24 #include "sync/internal_api/public/sync_manager_factory.h"
25 #include "url/gurl.h"
26
27 // Helper macros to log with the syncer thread name; useful when there
28 // are multiple syncers involved.
29
30 #define SLOG(severity) LOG(severity) << name_ << ": "
31
32 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
33
34 static const int kSaveChangesIntervalSeconds = 10;
35
36 namespace syncer {
37 class InternalComponentsFactory;
38 }  // namespace syncer
39
40 namespace {
41
42 // Enums for UMAs.
43 enum SyncBackendInitState {
44     SETUP_COMPLETED_FOUND_RESTORED_TYPES = 0,
45     SETUP_COMPLETED_NO_RESTORED_TYPES,
46     FIRST_SETUP_NO_RESTORED_TYPES,
47     FIRST_SETUP_RESTORED_TYPES,
48     SYNC_BACKEND_INIT_STATE_COUNT
49 };
50
51 }  // namespace
52
53 namespace browser_sync {
54
55 DoInitializeOptions::DoInitializeOptions(
56     base::MessageLoop* sync_loop,
57     SyncBackendRegistrar* registrar,
58     const syncer::ModelSafeRoutingInfo& routing_info,
59     const std::vector<scoped_refptr<syncer::ModelSafeWorker> >& workers,
60     const scoped_refptr<syncer::ExtensionsActivity>& extensions_activity,
61     const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
62     const GURL& service_url,
63     scoped_ptr<syncer::HttpPostProviderFactory> http_bridge_factory,
64     const syncer::SyncCredentials& credentials,
65     const std::string& invalidator_client_id,
66     scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
67     bool delete_sync_data_folder,
68     const std::string& restored_key_for_bootstrapping,
69     const std::string& restored_keystore_key_for_bootstrapping,
70     scoped_ptr<syncer::InternalComponentsFactory> internal_components_factory,
71     scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
72     syncer::ReportUnrecoverableErrorFunction
73         report_unrecoverable_error_function)
74     : sync_loop(sync_loop),
75       registrar(registrar),
76       routing_info(routing_info),
77       workers(workers),
78       extensions_activity(extensions_activity),
79       event_handler(event_handler),
80       service_url(service_url),
81       http_bridge_factory(http_bridge_factory.Pass()),
82       credentials(credentials),
83       invalidator_client_id(invalidator_client_id),
84       sync_manager_factory(sync_manager_factory.Pass()),
85       delete_sync_data_folder(delete_sync_data_folder),
86       restored_key_for_bootstrapping(restored_key_for_bootstrapping),
87       restored_keystore_key_for_bootstrapping(
88           restored_keystore_key_for_bootstrapping),
89       internal_components_factory(internal_components_factory.Pass()),
90       unrecoverable_error_handler(unrecoverable_error_handler.Pass()),
91       report_unrecoverable_error_function(report_unrecoverable_error_function) {
92 }
93
94 DoInitializeOptions::~DoInitializeOptions() {}
95
96 DoConfigureSyncerTypes::DoConfigureSyncerTypes() {}
97
98 DoConfigureSyncerTypes::~DoConfigureSyncerTypes() {}
99
100 SyncBackendHostCore::SyncBackendHostCore(
101     const std::string& name,
102     const base::FilePath& sync_data_folder_path,
103     bool has_sync_setup_completed,
104     const base::WeakPtr<SyncBackendHostImpl>& backend)
105     : name_(name),
106       sync_data_folder_path_(sync_data_folder_path),
107       host_(backend),
108       sync_loop_(NULL),
109       registrar_(NULL),
110       has_sync_setup_completed_(has_sync_setup_completed),
111       forward_protocol_events_(false),
112       forward_type_info_(false),
113       weak_ptr_factory_(this) {
114   DCHECK(backend.get());
115 }
116
117 SyncBackendHostCore::~SyncBackendHostCore() {
118   DCHECK(!sync_manager_.get());
119 }
120
121 void SyncBackendHostCore::OnSyncCycleCompleted(
122     const syncer::sessions::SyncSessionSnapshot& snapshot) {
123   if (!sync_loop_)
124     return;
125   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
126
127   host_.Call(
128       FROM_HERE,
129       &SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop,
130       snapshot);
131 }
132
133 void SyncBackendHostCore::DoRefreshTypes(syncer::ModelTypeSet types) {
134   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
135   sync_manager_->RefreshTypes(types);
136 }
137
138 void SyncBackendHostCore::OnControlTypesDownloadRetry() {
139   host_.Call(FROM_HERE,
140              &SyncBackendHostImpl::HandleControlTypesDownloadRetry);
141 }
142
143 void SyncBackendHostCore::OnInitializationComplete(
144     const syncer::WeakHandle<syncer::JsBackend>& js_backend,
145     const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
146         debug_info_listener,
147     bool success,
148     const syncer::ModelTypeSet restored_types) {
149   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
150
151   if (!success) {
152     DoDestroySyncManager(syncer::STOP_SYNC);
153     host_.Call(FROM_HERE,
154                &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop);
155     return;
156   }
157
158   // Register for encryption related changes now. We have to do this before
159   // the initializing downloading control types or initializing the encryption
160   // handler in order to receive notifications triggered during encryption
161   // startup.
162   sync_manager_->GetEncryptionHandler()->AddObserver(this);
163
164   // Sync manager initialization is complete, so we can schedule recurring
165   // SaveChanges.
166   sync_loop_->PostTask(FROM_HERE,
167                        base::Bind(&SyncBackendHostCore::StartSavingChanges,
168                                   weak_ptr_factory_.GetWeakPtr()));
169
170   // Hang on to these for a while longer.  We're not ready to hand them back to
171   // the UI thread yet.
172   js_backend_ = js_backend;
173   debug_info_listener_ = debug_info_listener;
174
175   // Track whether or not sync DB and preferences were in sync.
176   SyncBackendInitState backend_init_state;
177   if (has_sync_setup_completed_ && !restored_types.Empty()) {
178     backend_init_state = SETUP_COMPLETED_FOUND_RESTORED_TYPES;
179   } else if (has_sync_setup_completed_ && restored_types.Empty()) {
180     backend_init_state = SETUP_COMPLETED_NO_RESTORED_TYPES;
181   } else if (!has_sync_setup_completed_ && restored_types.Empty()) {
182     backend_init_state = FIRST_SETUP_NO_RESTORED_TYPES;
183   } else { // (!has_sync_setup_completed_ && !restored_types.Empty())
184     backend_init_state = FIRST_SETUP_RESTORED_TYPES;
185   }
186
187   UMA_HISTOGRAM_ENUMERATION("Sync.BackendInitializeRestoreState",
188                             backend_init_state,
189                             SYNC_BACKEND_INIT_STATE_COUNT);
190
191   // Before proceeding any further, we need to download the control types and
192   // purge any partial data (ie. data downloaded for a type that was on its way
193   // to being initially synced, but didn't quite make it.).  The following
194   // configure cycle will take care of this.  It depends on the registrar state
195   // which we initialize below to ensure that we don't perform any downloads if
196   // all control types have already completed their initial sync.
197   registrar_->SetInitialTypes(restored_types);
198
199   syncer::ConfigureReason reason =
200       restored_types.Empty() ?
201        syncer::CONFIGURE_REASON_NEW_CLIENT :
202        syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
203
204   syncer::ModelTypeSet new_control_types = registrar_->ConfigureDataTypes(
205       syncer::ControlTypes(), syncer::ModelTypeSet());
206   syncer::ModelSafeRoutingInfo routing_info;
207   registrar_->GetModelSafeRoutingInfo(&routing_info);
208   SDVLOG(1) << "Control Types "
209             << syncer::ModelTypeSetToString(new_control_types)
210             << " added; calling ConfigureSyncer";
211
212   syncer::ModelTypeSet types_to_purge =
213       syncer::Difference(syncer::ModelTypeSet::All(),
214                          GetRoutingInfoTypes(routing_info));
215
216   sync_manager_->ConfigureSyncer(
217       reason,
218       new_control_types,
219       types_to_purge,
220       syncer::ModelTypeSet(),
221       syncer::ModelTypeSet(),
222       routing_info,
223       base::Bind(&SyncBackendHostCore::DoInitialProcessControlTypes,
224                  weak_ptr_factory_.GetWeakPtr()),
225       base::Bind(&SyncBackendHostCore::OnControlTypesDownloadRetry,
226                  weak_ptr_factory_.GetWeakPtr()));
227 }
228
229 void SyncBackendHostCore::OnConnectionStatusChange(
230     syncer::ConnectionStatus status) {
231   if (!sync_loop_)
232     return;
233   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
234   host_.Call(
235       FROM_HERE,
236       &SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop, status);
237 }
238
239 void SyncBackendHostCore::OnPassphraseRequired(
240     syncer::PassphraseRequiredReason reason,
241     const sync_pb::EncryptedData& pending_keys) {
242   if (!sync_loop_)
243     return;
244   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
245   host_.Call(
246       FROM_HERE,
247       &SyncBackendHostImpl::NotifyPassphraseRequired, reason, pending_keys);
248 }
249
250 void SyncBackendHostCore::OnPassphraseAccepted() {
251   if (!sync_loop_)
252     return;
253   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
254   host_.Call(
255       FROM_HERE,
256       &SyncBackendHostImpl::NotifyPassphraseAccepted);
257 }
258
259 void SyncBackendHostCore::OnBootstrapTokenUpdated(
260     const std::string& bootstrap_token,
261     syncer::BootstrapTokenType type) {
262   if (!sync_loop_)
263     return;
264   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
265   host_.Call(FROM_HERE,
266              &SyncBackendHostImpl::PersistEncryptionBootstrapToken,
267              bootstrap_token,
268              type);
269 }
270
271 void SyncBackendHostCore::OnEncryptedTypesChanged(
272     syncer::ModelTypeSet encrypted_types,
273     bool encrypt_everything) {
274   if (!sync_loop_)
275     return;
276   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
277   // NOTE: We're in a transaction.
278   host_.Call(
279       FROM_HERE,
280       &SyncBackendHostImpl::NotifyEncryptedTypesChanged,
281       encrypted_types, encrypt_everything);
282 }
283
284 void SyncBackendHostCore::OnEncryptionComplete() {
285   if (!sync_loop_)
286     return;
287   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
288   // NOTE: We're in a transaction.
289   host_.Call(
290       FROM_HERE,
291       &SyncBackendHostImpl::NotifyEncryptionComplete);
292 }
293
294 void SyncBackendHostCore::OnCryptographerStateChanged(
295     syncer::Cryptographer* cryptographer) {
296   // Do nothing.
297 }
298
299 void SyncBackendHostCore::OnPassphraseTypeChanged(
300     syncer::PassphraseType type, base::Time passphrase_time) {
301   host_.Call(
302       FROM_HERE,
303       &SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop,
304       type, passphrase_time);
305 }
306
307 void SyncBackendHostCore::OnCommitCountersUpdated(
308     syncer::ModelType type,
309     const syncer::CommitCounters& counters) {
310   host_.Call(
311       FROM_HERE,
312       &SyncBackendHostImpl::HandleDirectoryCommitCountersUpdatedOnFrontendLoop,
313       type, counters);
314 }
315
316 void SyncBackendHostCore::OnUpdateCountersUpdated(
317     syncer::ModelType type,
318     const syncer::UpdateCounters& counters) {
319   host_.Call(
320       FROM_HERE,
321       &SyncBackendHostImpl::HandleDirectoryUpdateCountersUpdatedOnFrontendLoop,
322       type, counters);
323 }
324
325 void SyncBackendHostCore::OnStatusCountersUpdated(
326     syncer::ModelType type,
327     const syncer::StatusCounters& counters) {
328   host_.Call(
329       FROM_HERE,
330       &SyncBackendHostImpl::HandleDirectoryStatusCountersUpdatedOnFrontendLoop,
331       type, counters);
332 }
333
334 void SyncBackendHostCore::OnActionableError(
335     const syncer::SyncProtocolError& sync_error) {
336   if (!sync_loop_)
337     return;
338   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
339   host_.Call(
340       FROM_HERE,
341       &SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop,
342       sync_error);
343 }
344
345 void SyncBackendHostCore::OnMigrationRequested(syncer::ModelTypeSet types) {
346   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
347   host_.Call(
348       FROM_HERE,
349       &SyncBackendHostImpl::HandleMigrationRequestedOnFrontendLoop,
350       types);
351 }
352
353 void SyncBackendHostCore::OnProtocolEvent(
354     const syncer::ProtocolEvent& event) {
355   // TODO(rlarocque): Find a way to pass event_clone as a scoped_ptr.
356   if (forward_protocol_events_) {
357     scoped_ptr<syncer::ProtocolEvent> event_clone(event.Clone());
358     host_.Call(
359         FROM_HERE,
360         &SyncBackendHostImpl::HandleProtocolEventOnFrontendLoop,
361         event_clone.release());
362   }
363 }
364
365 void SyncBackendHostCore::DoOnInvalidatorStateChange(
366     syncer::InvalidatorState state) {
367   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
368   sync_manager_->SetInvalidatorEnabled(state == syncer::INVALIDATIONS_ENABLED);
369 }
370
371 void SyncBackendHostCore::DoOnIncomingInvalidation(
372     const syncer::ObjectIdInvalidationMap& invalidation_map) {
373   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
374
375   syncer::ObjectIdSet ids = invalidation_map.GetObjectIds();
376   for (syncer::ObjectIdSet::const_iterator ids_it = ids.begin();
377        ids_it != ids.end();
378        ++ids_it) {
379     syncer::ModelType type;
380     if (!NotificationTypeToRealModelType(ids_it->name(), &type)) {
381       DLOG(WARNING) << "Notification has invalid id: "
382                     << syncer::ObjectIdToString(*ids_it);
383     } else {
384       syncer::SingleObjectInvalidationSet invalidation_set =
385           invalidation_map.ForObject(*ids_it);
386       for (syncer::SingleObjectInvalidationSet::const_iterator inv_it =
387                invalidation_set.begin();
388            inv_it != invalidation_set.end();
389            ++inv_it) {
390         scoped_ptr<syncer::InvalidationInterface> inv_adapter(
391             new InvalidationAdapter(*inv_it));
392         sync_manager_->OnIncomingInvalidation(type, inv_adapter.Pass());
393       }
394     }
395   }
396 }
397
398 void SyncBackendHostCore::DoInitialize(
399     scoped_ptr<DoInitializeOptions> options) {
400   DCHECK(!sync_loop_);
401   sync_loop_ = options->sync_loop;
402   DCHECK(sync_loop_);
403
404   // Finish initializing the HttpBridgeFactory.  We do this here because
405   // building the user agent may block on some platforms.
406   chrome::VersionInfo version_info;
407   options->http_bridge_factory->Init(
408       LocalDeviceInfoProviderImpl::MakeUserAgentForSyncApi(version_info));
409
410   // Blow away the partial or corrupt sync data folder before doing any more
411   // initialization, if necessary.
412   if (options->delete_sync_data_folder) {
413     DeleteSyncDataFolder();
414   }
415
416   // Make sure that the directory exists before initializing the backend.
417   // If it already exists, this will do no harm.
418   if (!base::CreateDirectory(sync_data_folder_path_)) {
419     DLOG(FATAL) << "Sync Data directory creation failed.";
420   }
421
422   DCHECK(!registrar_);
423   registrar_ = options->registrar;
424   DCHECK(registrar_);
425
426   sync_manager_ = options->sync_manager_factory->CreateSyncManager(name_);
427   sync_manager_->AddObserver(this);
428
429   syncer::SyncManager::InitArgs args;
430   args.database_location = sync_data_folder_path_;
431   args.event_handler = options->event_handler;
432   args.service_url = options->service_url;
433   args.post_factory = options->http_bridge_factory.Pass();
434   args.workers = options->workers;
435   args.extensions_activity = options->extensions_activity.get();
436   args.change_delegate = options->registrar;  // as SyncManager::ChangeDelegate
437   args.credentials = options->credentials;
438   args.invalidator_client_id = options->invalidator_client_id;
439   args.restored_key_for_bootstrapping = options->restored_key_for_bootstrapping;
440   args.restored_keystore_key_for_bootstrapping =
441       options->restored_keystore_key_for_bootstrapping;
442   args.internal_components_factory =
443       options->internal_components_factory.Pass();
444   args.encryptor = &encryptor_;
445   args.unrecoverable_error_handler =
446       options->unrecoverable_error_handler.Pass();
447   args.report_unrecoverable_error_function =
448       options->report_unrecoverable_error_function;
449   args.cancelation_signal = &stop_syncing_signal_;
450   sync_manager_->Init(&args);
451 }
452
453 void SyncBackendHostCore::DoUpdateCredentials(
454     const syncer::SyncCredentials& credentials) {
455   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
456   // UpdateCredentials can be called during backend initialization, possibly
457   // when backend initialization has failed but hasn't notified the UI thread
458   // yet. In that case, the sync manager may have been destroyed on the sync
459   // thread before this task was executed, so we do nothing.
460   if (sync_manager_) {
461     sync_manager_->UpdateCredentials(credentials);
462   }
463 }
464
465 void SyncBackendHostCore::DoStartSyncing(
466     const syncer::ModelSafeRoutingInfo& routing_info) {
467   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
468   sync_manager_->StartSyncingNormally(routing_info);
469 }
470
471 void SyncBackendHostCore::DoSetEncryptionPassphrase(
472     const std::string& passphrase,
473     bool is_explicit) {
474   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
475   sync_manager_->GetEncryptionHandler()->SetEncryptionPassphrase(
476       passphrase, is_explicit);
477 }
478
479 void SyncBackendHostCore::DoInitialProcessControlTypes() {
480   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
481
482   DVLOG(1) << "Initilalizing Control Types";
483
484   // Initialize encryption.
485   sync_manager_->GetEncryptionHandler()->Init();
486
487   // Note: experiments are currently handled via SBH::AddExperimentalTypes,
488   // which is called at the end of every sync cycle.
489   // TODO(zea): eventually add an experiment handler and initialize it here.
490
491   if (!sync_manager_->GetUserShare()) {  // NULL in some tests.
492     DVLOG(1) << "Skipping initialization of DeviceInfo";
493     host_.Call(
494         FROM_HERE,
495         &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop);
496     return;
497   }
498
499   if (!sync_manager_->InitialSyncEndedTypes().HasAll(syncer::ControlTypes())) {
500     LOG(ERROR) << "Failed to download control types";
501     host_.Call(
502         FROM_HERE,
503         &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop);
504     return;
505   }
506
507   host_.Call(FROM_HERE,
508              &SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop,
509              js_backend_,
510              debug_info_listener_,
511              sync_manager_->GetSyncContextProxy(),
512              sync_manager_->cache_guid());
513
514   js_backend_.Reset();
515   debug_info_listener_.Reset();
516 }
517
518 void SyncBackendHostCore::DoSetDecryptionPassphrase(
519     const std::string& passphrase) {
520   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
521   sync_manager_->GetEncryptionHandler()->SetDecryptionPassphrase(
522       passphrase);
523 }
524
525 void SyncBackendHostCore::DoEnableEncryptEverything() {
526   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
527   sync_manager_->GetEncryptionHandler()->EnableEncryptEverything();
528 }
529
530 void SyncBackendHostCore::ShutdownOnUIThread() {
531   // This will cut short any blocking network tasks, cut short any in-progress
532   // sync cycles, and prevent the creation of new blocking network tasks and new
533   // sync cycles.  If there was an in-progress network request, it would have
534   // had a reference to the RequestContextGetter.  This reference will be
535   // dropped by the time this function returns.
536   //
537   // It is safe to call this even if Sync's backend classes have not been
538   // initialized yet.  Those classes will receive the message when the sync
539   // thread finally getes around to constructing them.
540   stop_syncing_signal_.Signal();
541
542   // This will drop the HttpBridgeFactory's reference to the
543   // RequestContextGetter.  Once this has been called, the HttpBridgeFactory can
544   // no longer be used to create new HttpBridge instances.  We can get away with
545   // this because the stop_syncing_signal_ has already been signalled, which
546   // guarantees that the ServerConnectionManager will no longer attempt to
547   // create new connections.
548   release_request_context_signal_.Signal();
549 }
550
551 void SyncBackendHostCore::DoShutdown(syncer::ShutdownReason reason) {
552   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
553
554   DoDestroySyncManager(reason);
555
556   registrar_ = NULL;
557
558   if (reason == syncer::DISABLE_SYNC)
559     DeleteSyncDataFolder();
560
561   host_.Reset();
562   weak_ptr_factory_.InvalidateWeakPtrs();
563 }
564
565 void SyncBackendHostCore::DoDestroySyncManager(syncer::ShutdownReason reason) {
566   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
567   if (sync_manager_) {
568     DisableDirectoryTypeDebugInfoForwarding();
569     save_changes_timer_.reset();
570     sync_manager_->RemoveObserver(this);
571     sync_manager_->ShutdownOnSyncThread(reason);
572     sync_manager_.reset();
573   }
574 }
575
576 void SyncBackendHostCore::DoConfigureSyncer(
577     syncer::ConfigureReason reason,
578     const DoConfigureSyncerTypes& config_types,
579     const syncer::ModelSafeRoutingInfo routing_info,
580     const base::Callback<void(syncer::ModelTypeSet,
581                               syncer::ModelTypeSet)>& ready_task,
582     const base::Closure& retry_callback) {
583   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
584   DCHECK(!ready_task.is_null());
585   DCHECK(!retry_callback.is_null());
586   base::Closure chained_ready_task(
587       base::Bind(&SyncBackendHostCore::DoFinishConfigureDataTypes,
588                  weak_ptr_factory_.GetWeakPtr(),
589                  config_types.to_download,
590                  ready_task));
591   base::Closure chained_retry_task(
592       base::Bind(&SyncBackendHostCore::DoRetryConfiguration,
593                  weak_ptr_factory_.GetWeakPtr(),
594                  retry_callback));
595   sync_manager_->ConfigureSyncer(reason,
596                                  config_types.to_download,
597                                  config_types.to_purge,
598                                  config_types.to_journal,
599                                  config_types.to_unapply,
600                                  routing_info,
601                                  chained_ready_task,
602                                  chained_retry_task);
603 }
604
605 void SyncBackendHostCore::DoFinishConfigureDataTypes(
606     syncer::ModelTypeSet types_to_config,
607     const base::Callback<void(syncer::ModelTypeSet,
608                               syncer::ModelTypeSet)>& ready_task) {
609   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
610
611   // Update the enabled types for the bridge and sync manager.
612   syncer::ModelSafeRoutingInfo routing_info;
613   registrar_->GetModelSafeRoutingInfo(&routing_info);
614   syncer::ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
615   enabled_types.RemoveAll(syncer::ProxyTypes());
616
617   const syncer::ModelTypeSet failed_configuration_types =
618       Difference(types_to_config, sync_manager_->InitialSyncEndedTypes());
619   const syncer::ModelTypeSet succeeded_configuration_types =
620       Difference(types_to_config, failed_configuration_types);
621   host_.Call(FROM_HERE,
622              &SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop,
623              enabled_types,
624              succeeded_configuration_types,
625              failed_configuration_types,
626              ready_task);
627 }
628
629 void SyncBackendHostCore::DoRetryConfiguration(
630     const base::Closure& retry_callback) {
631   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
632   host_.Call(FROM_HERE,
633              &SyncBackendHostImpl::RetryConfigurationOnFrontendLoop,
634              retry_callback);
635 }
636
637 void SyncBackendHostCore::SendBufferedProtocolEventsAndEnableForwarding() {
638   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
639   forward_protocol_events_ = true;
640
641   if (sync_manager_) {
642     // Grab our own copy of the buffered events.
643     // The buffer is not modified by this operation.
644     std::vector<syncer::ProtocolEvent*> buffered_events;
645     sync_manager_->GetBufferedProtocolEvents().release(&buffered_events);
646
647     // Send them all over the fence to the host.
648     for (std::vector<syncer::ProtocolEvent*>::iterator it =
649          buffered_events.begin(); it != buffered_events.end(); ++it) {
650       // TODO(rlarocque): Make it explicit that host_ takes ownership.
651       host_.Call(
652           FROM_HERE,
653           &SyncBackendHostImpl::HandleProtocolEventOnFrontendLoop,
654           *it);
655     }
656   }
657 }
658
659 void SyncBackendHostCore::DisableProtocolEventForwarding() {
660   forward_protocol_events_ = false;
661 }
662
663 void SyncBackendHostCore::EnableDirectoryTypeDebugInfoForwarding() {
664   DCHECK(sync_manager_);
665
666   forward_type_info_ = true;
667
668   if (!sync_manager_->HasDirectoryTypeDebugInfoObserver(this))
669     sync_manager_->RegisterDirectoryTypeDebugInfoObserver(this);
670   sync_manager_->RequestEmitDebugInfo();
671 }
672
673 void SyncBackendHostCore::DisableDirectoryTypeDebugInfoForwarding() {
674   DCHECK(sync_manager_);
675
676   if (!forward_type_info_)
677     return;
678
679   forward_type_info_ = false;
680
681   if (sync_manager_->HasDirectoryTypeDebugInfoObserver(this))
682     sync_manager_->UnregisterDirectoryTypeDebugInfoObserver(this);
683 }
684
685 void SyncBackendHostCore::DeleteSyncDataFolder() {
686   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
687   if (base::DirectoryExists(sync_data_folder_path_)) {
688     if (!base::DeleteFile(sync_data_folder_path_, true))
689       SLOG(DFATAL) << "Could not delete the Sync Data folder.";
690   }
691 }
692
693 void SyncBackendHostCore::GetAllNodesForTypes(
694     syncer::ModelTypeSet types,
695     scoped_refptr<base::SequencedTaskRunner> task_runner,
696     base::Callback<void(const std::vector<syncer::ModelType>& type,
697                         ScopedVector<base::ListValue>)> callback) {
698   std::vector<syncer::ModelType> types_vector;
699   ScopedVector<base::ListValue> node_lists;
700
701   syncer::ModelSafeRoutingInfo routes;
702   registrar_->GetModelSafeRoutingInfo(&routes);
703   syncer::ModelTypeSet enabled_types = GetRoutingInfoTypes(routes);
704
705   for (syncer::ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
706     types_vector.push_back(it.Get());
707     if (!enabled_types.Has(it.Get())) {
708       node_lists.push_back(new base::ListValue());
709     } else {
710       node_lists.push_back(
711           sync_manager_->GetAllNodesForType(it.Get()).release());
712     }
713   }
714
715   task_runner->PostTask(
716       FROM_HERE,
717       base::Bind(callback, types_vector, base::Passed(&node_lists)));
718 }
719
720 void SyncBackendHostCore::StartSavingChanges() {
721   // We may already be shut down.
722   if (!sync_loop_)
723     return;
724   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
725   DCHECK(!save_changes_timer_.get());
726   save_changes_timer_.reset(new base::RepeatingTimer<SyncBackendHostCore>());
727   save_changes_timer_->Start(FROM_HERE,
728       base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds),
729       this, &SyncBackendHostCore::SaveChanges);
730 }
731
732 void SyncBackendHostCore::SaveChanges() {
733   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
734   sync_manager_->SaveChanges();
735 }
736
737 }  // namespace browser_sync