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