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_impl.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/signin/chrome_signin_client_factory.h"
13 #include "chrome/browser/sync/glue/invalidation_helper.h"
14 #include "chrome/browser/sync/glue/sync_backend_host_core.h"
15 #include "chrome/browser/sync/glue/sync_backend_registrar.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "components/invalidation/invalidation_service.h"
18 #include "components/invalidation/object_id_invalidation_map.h"
19 #include "components/network_time/network_time_tracker.h"
20 #include "components/signin/core/browser/signin_client.h"
21 #include "components/sync_driver/sync_frontend.h"
22 #include "components/sync_driver/sync_prefs.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/notification_details.h"
25 #include "content/public/browser/notification_source.h"
26 #include "sync/internal_api/public/base_transaction.h"
27 #include "sync/internal_api/public/events/protocol_event.h"
28 #include "sync/internal_api/public/http_bridge.h"
29 #include "sync/internal_api/public/internal_components_factory.h"
30 #include "sync/internal_api/public/internal_components_factory_impl.h"
31 #include "sync/internal_api/public/network_resources.h"
32 #include "sync/internal_api/public/sync_manager.h"
33 #include "sync/internal_api/public/sync_manager_factory.h"
34 #include "sync/internal_api/public/util/experiments.h"
35 #include "sync/internal_api/public/util/sync_string_conversions.h"
37 // Helper macros to log with the syncer thread name; useful when there
38 // are multiple syncers involved.
40 #define SLOG(severity) LOG(severity) << name_ << ": "
42 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
44 using syncer::InternalComponentsFactory;
46 namespace browser_sync {
50 void UpdateNetworkTimeOnUIThread(base::Time network_time,
51 base::TimeDelta resolution,
52 base::TimeDelta latency,
53 base::TimeTicks post_time) {
54 g_browser_process->network_time_tracker()->UpdateNetworkTime(
55 network_time, resolution, latency, post_time);
58 void UpdateNetworkTime(const base::Time& network_time,
59 const base::TimeDelta& resolution,
60 const base::TimeDelta& latency) {
61 content::BrowserThread::PostTask(
62 content::BrowserThread::UI,
64 base::Bind(&UpdateNetworkTimeOnUIThread,
65 network_time, resolution, latency, base::TimeTicks::Now()));
70 SyncBackendHostImpl::SyncBackendHostImpl(
71 const std::string& name,
73 invalidation::InvalidationService* invalidator,
74 const base::WeakPtr<sync_driver::SyncPrefs>& sync_prefs,
75 const base::FilePath& sync_folder)
76 : frontend_loop_(base::MessageLoop::current()),
80 sync_prefs_(sync_prefs),
82 cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE),
83 invalidator_(invalidator),
84 invalidation_handler_registered_(false),
85 weak_ptr_factory_(this) {
86 core_ = new SyncBackendHostCore(
88 profile_->GetPath().Append(sync_folder),
89 sync_prefs_->HasSyncSetupCompleted(),
90 weak_ptr_factory_.GetWeakPtr());
93 SyncBackendHostImpl::~SyncBackendHostImpl() {
94 DCHECK(!core_.get() && !frontend_) << "Must call Shutdown before destructor.";
95 DCHECK(!registrar_.get());
98 void SyncBackendHostImpl::Initialize(
99 sync_driver::SyncFrontend* frontend,
100 scoped_ptr<base::Thread> sync_thread,
101 const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
102 const GURL& sync_service_url,
103 const syncer::SyncCredentials& credentials,
104 bool delete_sync_data_folder,
105 scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
106 scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
107 syncer::ReportUnrecoverableErrorFunction
108 report_unrecoverable_error_function,
109 syncer::NetworkResources* network_resources) {
110 registrar_.reset(new browser_sync::SyncBackendRegistrar(name_,
112 sync_thread.Pass()));
113 CHECK(registrar_->sync_thread());
115 frontend_ = frontend;
118 syncer::ModelSafeRoutingInfo routing_info;
119 std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers;
120 registrar_->GetModelSafeRoutingInfo(&routing_info);
121 registrar_->GetWorkers(&workers);
123 InternalComponentsFactory::Switches factory_switches = {
124 InternalComponentsFactory::ENCRYPTION_KEYSTORE,
125 InternalComponentsFactory::BACKOFF_NORMAL
128 CommandLine* cl = CommandLine::ForCurrentProcess();
129 if (cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) {
130 factory_switches.backoff_override =
131 InternalComponentsFactory::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE;
133 if (cl->HasSwitch(switches::kSyncEnableGetUpdateAvoidance)) {
134 factory_switches.pre_commit_updates_policy =
135 InternalComponentsFactory::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE;
138 scoped_ptr<DoInitializeOptions> init_opts(new DoInitializeOptions(
139 registrar_->sync_thread()->message_loop(),
143 extensions_activity_monitor_.GetExtensionsActivity(),
146 network_resources->GetHttpPostProviderFactory(
147 make_scoped_refptr(profile_->GetRequestContext()),
148 base::Bind(&UpdateNetworkTime),
149 core_->GetRequestContextCancelationSignal()),
151 invalidator_ ? invalidator_->GetInvalidatorClientId() : "",
152 sync_manager_factory.Pass(),
153 delete_sync_data_folder,
154 sync_prefs_->GetEncryptionBootstrapToken(),
155 sync_prefs_->GetKeystoreEncryptionBootstrapToken(),
156 scoped_ptr<InternalComponentsFactory>(
157 new syncer::InternalComponentsFactoryImpl(factory_switches)).Pass(),
158 unrecoverable_error_handler.Pass(),
159 report_unrecoverable_error_function));
160 InitCore(init_opts.Pass());
163 void SyncBackendHostImpl::UpdateCredentials(
164 const syncer::SyncCredentials& credentials) {
165 DCHECK(registrar_->sync_thread()->IsRunning());
166 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
167 base::Bind(&SyncBackendHostCore::DoUpdateCredentials,
172 void SyncBackendHostImpl::StartSyncingWithServer() {
173 SDVLOG(1) << "SyncBackendHostImpl::StartSyncingWithServer called.";
175 syncer::ModelSafeRoutingInfo routing_info;
176 registrar_->GetModelSafeRoutingInfo(&routing_info);
178 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
179 base::Bind(&SyncBackendHostCore::DoStartSyncing,
180 core_.get(), routing_info));
183 void SyncBackendHostImpl::SetEncryptionPassphrase(const std::string& passphrase,
185 DCHECK(registrar_->sync_thread()->IsRunning());
186 if (!IsNigoriEnabled()) {
187 NOTREACHED() << "SetEncryptionPassphrase must never be called when nigori"
192 // We should never be called with an empty passphrase.
193 DCHECK(!passphrase.empty());
195 // This should only be called by the frontend.
196 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
198 // SetEncryptionPassphrase should never be called if we are currently
199 // encrypted with an explicit passphrase.
200 DCHECK(cached_passphrase_type_ == syncer::KEYSTORE_PASSPHRASE ||
201 cached_passphrase_type_ == syncer::IMPLICIT_PASSPHRASE);
203 // Post an encryption task on the syncer thread.
204 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
205 base::Bind(&SyncBackendHostCore::DoSetEncryptionPassphrase,
207 passphrase, is_explicit));
210 bool SyncBackendHostImpl::SetDecryptionPassphrase(
211 const std::string& passphrase) {
212 if (!IsNigoriEnabled()) {
213 NOTREACHED() << "SetDecryptionPassphrase must never be called when nigori"
218 // We should never be called with an empty passphrase.
219 DCHECK(!passphrase.empty());
221 // This should only be called by the frontend.
222 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
224 // This should only be called when we have cached pending keys.
225 DCHECK(cached_pending_keys_.has_blob());
227 // Check the passphrase that was provided against our local cache of the
228 // cryptographer's pending keys. If this was unsuccessful, the UI layer can
229 // immediately call OnPassphraseRequired without showing the user a spinner.
230 if (!CheckPassphraseAgainstCachedPendingKeys(passphrase))
233 // Post a decryption task on the syncer thread.
234 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
235 base::Bind(&SyncBackendHostCore::DoSetDecryptionPassphrase,
239 // Since we were able to decrypt the cached pending keys with the passphrase
240 // provided, we immediately alert the UI layer that the passphrase was
241 // accepted. This will avoid the situation where a user enters a passphrase,
242 // clicks OK, immediately reopens the advanced settings dialog, and gets an
243 // unnecessary prompt for a passphrase.
244 // Note: It is not guaranteed that the passphrase will be accepted by the
245 // syncer thread, since we could receive a new nigori node while the task is
246 // pending. This scenario is a valid race, and SetDecryptionPassphrase can
247 // trigger a new OnPassphraseRequired if it needs to.
248 NotifyPassphraseAccepted();
252 void SyncBackendHostImpl::StopSyncingForShutdown() {
253 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
255 // Immediately stop sending messages to the frontend.
258 // Stop listening for and forwarding locally-triggered sync refresh requests.
259 notification_registrar_.RemoveAll();
261 // Stop non-blocking sync types from sending any more requests to the syncer.
262 sync_context_proxy_.reset();
264 DCHECK(registrar_->sync_thread()->IsRunning());
266 registrar_->RequestWorkerStopOnUIThread();
268 core_->ShutdownOnUIThread();
271 scoped_ptr<base::Thread> SyncBackendHostImpl::Shutdown(
272 syncer::ShutdownReason reason) {
273 // StopSyncingForShutdown() (which nulls out |frontend_|) should be
276 DCHECK(registrar_->sync_thread()->IsRunning());
278 bool sync_thread_claimed = (reason != syncer::BROWSER_SHUTDOWN);
280 if (invalidation_handler_registered_) {
281 if (reason == syncer::DISABLE_SYNC) {
282 UnregisterInvalidationIds();
284 invalidator_->UnregisterInvalidationHandler(this);
287 invalidation_handler_registered_ = false;
289 // Shut down and destroy sync manager.
290 registrar_->sync_thread()->message_loop()->PostTask(
292 base::Bind(&SyncBackendHostCore::DoShutdown,
293 core_.get(), reason));
297 SyncBackendRegistrar* detached_registrar = registrar_.release();
298 detached_registrar->sync_thread()->message_loop()->PostTask(
300 base::Bind(&SyncBackendRegistrar::Shutdown,
301 base::Unretained(detached_registrar)));
303 if (sync_thread_claimed)
304 return detached_registrar->ReleaseSyncThread();
306 return scoped_ptr<base::Thread>();
309 void SyncBackendHostImpl::UnregisterInvalidationIds() {
310 if (invalidation_handler_registered_) {
311 invalidator_->UpdateRegisteredInvalidationIds(
313 syncer::ObjectIdSet());
317 void SyncBackendHostImpl::ConfigureDataTypes(
318 syncer::ConfigureReason reason,
319 const DataTypeConfigStateMap& config_state_map,
320 const base::Callback<void(syncer::ModelTypeSet,
321 syncer::ModelTypeSet)>& ready_task,
322 const base::Callback<void()>& retry_callback) {
323 // Only one configure is allowed at a time. This is guaranteed by our
324 // callers. The SyncBackendHostImpl requests one configure as the backend is
325 // initializing and waits for it to complete. After initialization, all
326 // configurations will pass through the DataTypeManager, which is careful to
327 // never send a new configure request until the current request succeeds.
329 // The SyncBackendRegistrar's routing info will be updated by adding the
330 // types_to_add to the list then removing types_to_remove. Any types which
331 // are not in either of those sets will remain untouched.
333 // Types which were not in the list previously are not fully downloaded, so we
334 // must ask the syncer to download them. Any newly supported datatypes will
335 // not have been in that routing info list, so they will be among the types
336 // downloaded if they are enabled.
338 // The SyncBackendRegistrar's state was initially derived from the types
339 // detected to have been downloaded in the database. Afterwards it is
340 // modified only by this function. We expect it to remain in sync with the
341 // backend because configuration requests are never aborted; they are retried
342 // until they succeed or the backend is shut down.
344 syncer::ModelTypeSet disabled_types =
345 GetDataTypesInState(DISABLED, config_state_map);
346 syncer::ModelTypeSet fatal_types =
347 GetDataTypesInState(FATAL, config_state_map);
348 syncer::ModelTypeSet crypto_types =
349 GetDataTypesInState(CRYPTO, config_state_map);
350 syncer::ModelTypeSet unready_types =
351 GetDataTypesInState(UNREADY, config_state_map);
353 disabled_types.PutAll(fatal_types);
354 disabled_types.PutAll(crypto_types);
355 disabled_types.PutAll(unready_types);
357 syncer::ModelTypeSet active_types =
358 GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map);
359 syncer::ModelTypeSet clean_first_types =
360 GetDataTypesInState(CONFIGURE_CLEAN, config_state_map);
361 syncer::ModelTypeSet types_to_download = registrar_->ConfigureDataTypes(
362 syncer::Union(active_types, clean_first_types),
364 types_to_download.PutAll(clean_first_types);
365 types_to_download.RemoveAll(syncer::ProxyTypes());
366 if (!types_to_download.Empty())
367 types_to_download.Put(syncer::NIGORI);
369 // TODO(sync): crbug.com/137550.
370 // It's dangerous to configure types that have progress markers. Types with
371 // progress markers can trigger a MIGRATION_DONE response. We are not
372 // prepared to handle a migration during a configure, so we must ensure that
373 // all our types_to_download actually contain no data before we sync them.
375 // One common way to end up in this situation used to be types which
376 // downloaded some or all of their data but have not applied it yet. We avoid
377 // problems with those types by purging the data of any such partially synced
378 // types soon after we load the directory.
380 // Another possible scenario is that we have newly supported or newly enabled
381 // data types being downloaded here but the nigori type, which is always
382 // included in any GetUpdates request, requires migration. The server has
383 // code to detect this scenario based on the configure reason, the fact that
384 // the nigori type is the only requested type which requires migration, and
385 // that the requested types list includes at least one non-nigori type. It
386 // will not send a MIGRATION_DONE response in that case. We still need to be
387 // careful to not send progress markers for non-nigori types, though. If a
388 // non-nigori type in the request requires migration, a MIGRATION_DONE
389 // response will be sent.
391 syncer::ModelSafeRoutingInfo routing_info;
392 registrar_->GetModelSafeRoutingInfo(&routing_info);
394 syncer::ModelTypeSet current_types = registrar_->GetLastConfiguredTypes();
395 syncer::ModelTypeSet types_to_purge =
396 syncer::Difference(syncer::ModelTypeSet::All(), current_types);
397 syncer::ModelTypeSet inactive_types =
398 GetDataTypesInState(CONFIGURE_INACTIVE, config_state_map);
399 types_to_purge.RemoveAll(inactive_types);
400 types_to_purge.RemoveAll(unready_types);
402 // If a type has already been disabled and unapplied or journaled, it will
403 // not be part of the |types_to_purge| set, and therefore does not need
404 // to be acted on again.
405 fatal_types.RetainAll(types_to_purge);
406 syncer::ModelTypeSet unapply_types =
407 syncer::Union(crypto_types, clean_first_types);
408 unapply_types.RetainAll(types_to_purge);
410 DCHECK(syncer::Intersection(current_types, fatal_types).Empty());
411 DCHECK(syncer::Intersection(current_types, crypto_types).Empty());
412 DCHECK(current_types.HasAll(types_to_download));
414 SDVLOG(1) << "Types "
415 << syncer::ModelTypeSetToString(types_to_download)
416 << " added; calling DoConfigureSyncer";
417 // Divide up the types into their corresponding actions (each is mutually
419 // - Types which have just been added to the routing info (types_to_download):
421 // - Types which have encountered a fatal error (fatal_types) are deleted
422 // from the directory and journaled in the delete journal.
423 // - Types which have encountered a cryptographer error (crypto_types) are
424 // unapplied (local state is purged but sync state is not).
425 // - All other types not in the routing info (types just disabled) are deleted
426 // from the directory.
427 // - Everything else (enabled types and already disabled types) is not
429 RequestConfigureSyncer(reason,
440 void SyncBackendHostImpl::EnableEncryptEverything() {
441 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
442 base::Bind(&SyncBackendHostCore::DoEnableEncryptEverything,
446 void SyncBackendHostImpl::ActivateDataType(
447 syncer::ModelType type, syncer::ModelSafeGroup group,
448 sync_driver::ChangeProcessor* change_processor) {
449 registrar_->ActivateDataType(type, group, change_processor, GetUserShare());
452 void SyncBackendHostImpl::DeactivateDataType(syncer::ModelType type) {
453 registrar_->DeactivateDataType(type);
456 syncer::UserShare* SyncBackendHostImpl::GetUserShare() const {
457 return core_->sync_manager()->GetUserShare();
460 scoped_ptr<syncer::SyncContextProxy>
461 SyncBackendHostImpl::GetSyncContextProxy() {
462 return sync_context_proxy_.get() ? scoped_ptr<syncer::SyncContextProxy>(
463 sync_context_proxy_->Clone())
464 : scoped_ptr<syncer::SyncContextProxy>();
467 SyncBackendHostImpl::Status SyncBackendHostImpl::GetDetailedStatus() {
468 DCHECK(initialized());
469 return core_->sync_manager()->GetDetailedStatus();
472 syncer::sessions::SyncSessionSnapshot
473 SyncBackendHostImpl::GetLastSessionSnapshot() const {
474 return last_snapshot_;
477 bool SyncBackendHostImpl::HasUnsyncedItems() const {
478 DCHECK(initialized());
479 return core_->sync_manager()->HasUnsyncedItems();
482 bool SyncBackendHostImpl::IsNigoriEnabled() const {
483 return registrar_.get() && registrar_->IsNigoriEnabled();
486 syncer::PassphraseType SyncBackendHostImpl::GetPassphraseType() const {
487 return cached_passphrase_type_;
490 base::Time SyncBackendHostImpl::GetExplicitPassphraseTime() const {
491 return cached_explicit_passphrase_time_;
494 bool SyncBackendHostImpl::IsCryptographerReady(
495 const syncer::BaseTransaction* trans) const {
496 return initialized() && trans->GetCryptographer() &&
497 trans->GetCryptographer()->is_ready();
500 void SyncBackendHostImpl::GetModelSafeRoutingInfo(
501 syncer::ModelSafeRoutingInfo* out) const {
503 CHECK(registrar_.get());
504 registrar_->GetModelSafeRoutingInfo(out);
510 void SyncBackendHostImpl::RequestBufferedProtocolEventsAndEnableForwarding() {
511 registrar_->sync_thread()->message_loop()->PostTask(
514 &SyncBackendHostCore::SendBufferedProtocolEventsAndEnableForwarding,
518 void SyncBackendHostImpl::DisableProtocolEventForwarding() {
519 registrar_->sync_thread()->message_loop()->PostTask(
522 &SyncBackendHostCore::DisableProtocolEventForwarding,
526 void SyncBackendHostImpl::EnableDirectoryTypeDebugInfoForwarding() {
527 DCHECK(initialized());
528 registrar_->sync_thread()->message_loop()->PostTask(
531 &SyncBackendHostCore::EnableDirectoryTypeDebugInfoForwarding,
535 void SyncBackendHostImpl::DisableDirectoryTypeDebugInfoForwarding() {
536 DCHECK(initialized());
537 registrar_->sync_thread()->message_loop()->PostTask(
540 &SyncBackendHostCore::DisableDirectoryTypeDebugInfoForwarding,
544 void SyncBackendHostImpl::GetAllNodesForTypes(
545 syncer::ModelTypeSet types,
546 base::Callback<void(const std::vector<syncer::ModelType>&,
547 ScopedVector<base::ListValue>)> callback) {
548 DCHECK(initialized());
549 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
551 &SyncBackendHostCore::GetAllNodesForTypes,
554 frontend_loop_->message_loop_proxy(),
558 void SyncBackendHostImpl::InitCore(scoped_ptr<DoInitializeOptions> options) {
559 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
560 base::Bind(&SyncBackendHostCore::DoInitialize,
561 core_.get(), base::Passed(&options)));
564 void SyncBackendHostImpl::RequestConfigureSyncer(
565 syncer::ConfigureReason reason,
566 syncer::ModelTypeSet to_download,
567 syncer::ModelTypeSet to_purge,
568 syncer::ModelTypeSet to_journal,
569 syncer::ModelTypeSet to_unapply,
570 syncer::ModelTypeSet to_ignore,
571 const syncer::ModelSafeRoutingInfo& routing_info,
572 const base::Callback<void(syncer::ModelTypeSet,
573 syncer::ModelTypeSet)>& ready_task,
574 const base::Closure& retry_callback) {
575 DoConfigureSyncerTypes config_types;
576 config_types.to_download = to_download;
577 config_types.to_purge = to_purge;
578 config_types.to_journal = to_journal;
579 config_types.to_unapply = to_unapply;
580 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
581 base::Bind(&SyncBackendHostCore::DoConfigureSyncer,
590 void SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop(
591 const syncer::ModelTypeSet enabled_types,
592 const syncer::ModelTypeSet succeeded_configuration_types,
593 const syncer::ModelTypeSet failed_configuration_types,
594 const base::Callback<void(syncer::ModelTypeSet,
595 syncer::ModelTypeSet)>& ready_task) {
600 invalidator_->UpdateRegisteredInvalidationIds(
602 ModelTypeSetToObjectIdSet(enabled_types));
605 if (!ready_task.is_null())
606 ready_task.Run(succeeded_configuration_types, failed_configuration_types);
609 void SyncBackendHostImpl::Observe(
611 const content::NotificationSource& source,
612 const content::NotificationDetails& details) {
613 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
614 DCHECK_EQ(type, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL);
616 content::Details<const syncer::ModelTypeSet> state_details(details);
617 const syncer::ModelTypeSet& types = *(state_details.ptr());
618 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
619 base::Bind(&SyncBackendHostCore::DoRefreshTypes, core_.get(), types));
622 void SyncBackendHostImpl::AddExperimentalTypes() {
623 CHECK(initialized());
624 syncer::Experiments experiments;
625 if (core_->sync_manager()->ReceivedExperiment(&experiments))
626 frontend_->OnExperimentsChanged(experiments);
629 void SyncBackendHostImpl::HandleControlTypesDownloadRetry() {
630 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
634 frontend_->OnSyncConfigureRetry();
637 void SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop(
638 const syncer::WeakHandle<syncer::JsBackend> js_backend,
639 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>
641 syncer::SyncContextProxy* sync_context_proxy,
642 const std::string& cache_guid) {
643 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
645 if (sync_context_proxy)
646 sync_context_proxy_ = sync_context_proxy->Clone();
654 invalidator_->RegisterInvalidationHandler(this);
655 invalidation_handler_registered_ = true;
657 // Fake a state change to initialize the SyncManager's cached invalidator
659 OnInvalidatorStateChange(invalidator_->GetInvalidatorState());
662 // Start forwarding refresh requests to the SyncManager
663 notification_registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
664 content::Source<Profile>(profile_));
666 // Now that we've downloaded the control types, we can see if there are any
667 // experimental types to enable. This should be done before we inform
668 // the frontend to ensure they're visible in the customize screen.
669 AddExperimentalTypes();
670 frontend_->OnBackendInitialized(js_backend,
676 void SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop() {
677 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
681 frontend_->OnBackendInitialized(
682 syncer::WeakHandle<syncer::JsBackend>(),
683 syncer::WeakHandle<syncer::DataTypeDebugInfoListener>(),
688 void SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop(
689 const syncer::sessions::SyncSessionSnapshot& snapshot) {
692 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
694 last_snapshot_ = snapshot;
696 SDVLOG(1) << "Got snapshot " << snapshot.ToString();
698 // Process any changes to the datatypes we're syncing.
699 // TODO(sync): add support for removing types.
701 AddExperimentalTypes();
704 frontend_->OnSyncCycleCompleted();
707 void SyncBackendHostImpl::RetryConfigurationOnFrontendLoop(
708 const base::Closure& retry_callback) {
709 SDVLOG(1) << "Failed to complete configuration, informing of retry.";
710 retry_callback.Run();
713 void SyncBackendHostImpl::PersistEncryptionBootstrapToken(
714 const std::string& token,
715 syncer::BootstrapTokenType token_type) {
716 CHECK(sync_prefs_.get());
717 DCHECK(!token.empty());
718 if (token_type == syncer::PASSPHRASE_BOOTSTRAP_TOKEN)
719 sync_prefs_->SetEncryptionBootstrapToken(token);
721 sync_prefs_->SetKeystoreEncryptionBootstrapToken(token);
724 void SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop(
725 const syncer::SyncProtocolError& sync_error) {
728 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
729 frontend_->OnActionableError(sync_error);
732 void SyncBackendHostImpl::HandleMigrationRequestedOnFrontendLoop(
733 syncer::ModelTypeSet types) {
736 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
737 frontend_->OnMigrationNeededForTypes(types);
740 void SyncBackendHostImpl::OnInvalidatorStateChange(
741 syncer::InvalidatorState state) {
742 registrar_->sync_thread()->message_loop()->PostTask(
744 base::Bind(&SyncBackendHostCore::DoOnInvalidatorStateChange,
749 void SyncBackendHostImpl::OnIncomingInvalidation(
750 const syncer::ObjectIdInvalidationMap& invalidation_map) {
751 registrar_->sync_thread()->message_loop()->PostTask(
753 base::Bind(&SyncBackendHostCore::DoOnIncomingInvalidation,
758 std::string SyncBackendHostImpl::GetOwnerName() const {
759 return "SyncBackendHostImpl";
762 bool SyncBackendHostImpl::CheckPassphraseAgainstCachedPendingKeys(
763 const std::string& passphrase) const {
764 DCHECK(cached_pending_keys_.has_blob());
765 DCHECK(!passphrase.empty());
766 syncer::Nigori nigori;
767 nigori.InitByDerivation("localhost", "dummy", passphrase);
768 std::string plaintext;
769 bool result = nigori.Decrypt(cached_pending_keys_.blob(), &plaintext);
770 DVLOG_IF(1, result) << "Passphrase failed to decrypt pending keys.";
774 void SyncBackendHostImpl::NotifyPassphraseRequired(
775 syncer::PassphraseRequiredReason reason,
776 sync_pb::EncryptedData pending_keys) {
780 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
782 // Update our cache of the cryptographer's pending keys.
783 cached_pending_keys_ = pending_keys;
785 frontend_->OnPassphraseRequired(reason, pending_keys);
788 void SyncBackendHostImpl::NotifyPassphraseAccepted() {
792 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
794 // Clear our cache of the cryptographer's pending keys.
795 cached_pending_keys_.clear_blob();
796 frontend_->OnPassphraseAccepted();
799 void SyncBackendHostImpl::NotifyEncryptedTypesChanged(
800 syncer::ModelTypeSet encrypted_types,
801 bool encrypt_everything) {
805 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
806 frontend_->OnEncryptedTypesChanged(
807 encrypted_types, encrypt_everything);
810 void SyncBackendHostImpl::NotifyEncryptionComplete() {
814 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
815 frontend_->OnEncryptionComplete();
818 void SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop(
819 syncer::PassphraseType type,
820 base::Time explicit_passphrase_time) {
821 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
822 DVLOG(1) << "Passphrase type changed to "
823 << syncer::PassphraseTypeToString(type);
824 cached_passphrase_type_ = type;
825 cached_explicit_passphrase_time_ = explicit_passphrase_time;
828 void SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop(
829 syncer::ConnectionStatus status) {
833 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
835 DVLOG(1) << "Connection status changed: "
836 << syncer::ConnectionStatusToString(status);
837 frontend_->OnConnectionStatusChange(status);
840 void SyncBackendHostImpl::HandleProtocolEventOnFrontendLoop(
841 syncer::ProtocolEvent* event) {
842 scoped_ptr<syncer::ProtocolEvent> scoped_event(event);
845 frontend_->OnProtocolEvent(*scoped_event);
848 void SyncBackendHostImpl::HandleDirectoryCommitCountersUpdatedOnFrontendLoop(
849 syncer::ModelType type,
850 const syncer::CommitCounters& counters) {
853 frontend_->OnDirectoryTypeCommitCounterUpdated(type, counters);
856 void SyncBackendHostImpl::HandleDirectoryUpdateCountersUpdatedOnFrontendLoop(
857 syncer::ModelType type,
858 const syncer::UpdateCounters& counters) {
861 frontend_->OnDirectoryTypeUpdateCounterUpdated(type, counters);
864 void SyncBackendHostImpl::HandleDirectoryStatusCountersUpdatedOnFrontendLoop(
865 syncer::ModelType type,
866 const syncer::StatusCounters& counters) {
869 frontend_->OnDirectoryTypeStatusCounterUpdated(type, counters);
872 base::MessageLoop* SyncBackendHostImpl::GetSyncLoopForTesting() {
873 return registrar_->sync_thread()->message_loop();
876 } // namespace browser_sync