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/chrome_notification_types.h"
10 #include "chrome/browser/invalidation/invalidation_service_factory.h"
11 #include "chrome/browser/network_time/network_time_tracker.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/sync/glue/sync_backend_host_core.h"
14 #include "chrome/browser/sync/glue/sync_backend_registrar.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "components/invalidation/invalidation_service.h"
17 #include "components/sync_driver/sync_frontend.h"
18 #include "components/sync_driver/sync_prefs.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/notification_details.h"
21 #include "content/public/browser/notification_source.h"
22 #include "sync/internal_api/public/base_transaction.h"
23 #include "sync/internal_api/public/events/protocol_event.h"
24 #include "sync/internal_api/public/http_bridge.h"
25 #include "sync/internal_api/public/internal_components_factory.h"
26 #include "sync/internal_api/public/internal_components_factory_impl.h"
27 #include "sync/internal_api/public/network_resources.h"
28 #include "sync/internal_api/public/sync_manager.h"
29 #include "sync/internal_api/public/sync_manager_factory.h"
30 #include "sync/internal_api/public/util/experiments.h"
31 #include "sync/internal_api/public/util/sync_string_conversions.h"
32 #include "sync/notifier/object_id_invalidation_map.h"
34 // Helper macros to log with the syncer thread name; useful when there
35 // are multiple syncers involved.
37 #define SLOG(severity) LOG(severity) << name_ << ": "
39 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
41 using syncer::InternalComponentsFactory;
43 static const base::FilePath::CharType kSyncDataFolderName[] =
44 FILE_PATH_LITERAL("Sync Data");
46 namespace browser_sync {
48 SyncBackendHostImpl::SyncBackendHostImpl(
49 const std::string& name,
51 const base::WeakPtr<sync_driver::SyncPrefs>& sync_prefs)
52 : frontend_loop_(base::MessageLoop::current()),
56 sync_prefs_(sync_prefs),
58 cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE),
60 invalidation::InvalidationServiceFactory::GetForProfile(profile)),
61 invalidation_handler_registered_(false),
62 weak_ptr_factory_(this) {
64 core_ = new SyncBackendHostCore(
66 profile_->GetPath().Append(kSyncDataFolderName),
67 sync_prefs_->HasSyncSetupCompleted(),
68 weak_ptr_factory_.GetWeakPtr());
71 SyncBackendHostImpl::~SyncBackendHostImpl() {
72 DCHECK(!core_.get() && !frontend_) << "Must call Shutdown before destructor.";
73 DCHECK(!registrar_.get());
76 void SyncBackendHostImpl::Initialize(
77 SyncFrontend* frontend,
78 scoped_ptr<base::Thread> sync_thread,
79 const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
80 const GURL& sync_service_url,
81 const syncer::SyncCredentials& credentials,
82 bool delete_sync_data_folder,
83 scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
84 scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
85 syncer::ReportUnrecoverableErrorFunction
86 report_unrecoverable_error_function,
87 syncer::NetworkResources* network_resources) {
88 registrar_.reset(new browser_sync::SyncBackendRegistrar(name_,
91 CHECK(registrar_->sync_thread());
96 syncer::ModelSafeRoutingInfo routing_info;
97 std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers;
98 registrar_->GetModelSafeRoutingInfo(&routing_info);
99 registrar_->GetWorkers(&workers);
101 InternalComponentsFactory::Switches factory_switches = {
102 InternalComponentsFactory::ENCRYPTION_KEYSTORE,
103 InternalComponentsFactory::BACKOFF_NORMAL
106 CommandLine* cl = CommandLine::ForCurrentProcess();
107 if (cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) {
108 factory_switches.backoff_override =
109 InternalComponentsFactory::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE;
111 if (cl->HasSwitch(switches::kSyncEnableGetUpdateAvoidance)) {
112 factory_switches.pre_commit_updates_policy =
113 InternalComponentsFactory::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE;
116 scoped_ptr<DoInitializeOptions> init_opts(new DoInitializeOptions(
117 registrar_->sync_thread()->message_loop(),
121 extensions_activity_monitor_.GetExtensionsActivity(),
124 network_resources->GetHttpPostProviderFactory(
125 make_scoped_refptr(profile_->GetRequestContext()),
126 NetworkTimeTracker::BuildNotifierUpdateCallback(),
127 core_->GetRequestContextCancelationSignal()),
129 invalidator_->GetInvalidatorClientId(),
130 sync_manager_factory.Pass(),
131 delete_sync_data_folder,
132 sync_prefs_->GetEncryptionBootstrapToken(),
133 sync_prefs_->GetKeystoreEncryptionBootstrapToken(),
134 scoped_ptr<InternalComponentsFactory>(
135 new syncer::InternalComponentsFactoryImpl(factory_switches)).Pass(),
136 unrecoverable_error_handler.Pass(),
137 report_unrecoverable_error_function));
138 InitCore(init_opts.Pass());
141 void SyncBackendHostImpl::UpdateCredentials(
142 const syncer::SyncCredentials& credentials) {
143 DCHECK(registrar_->sync_thread()->IsRunning());
144 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
145 base::Bind(&SyncBackendHostCore::DoUpdateCredentials,
150 void SyncBackendHostImpl::StartSyncingWithServer() {
151 SDVLOG(1) << "SyncBackendHostImpl::StartSyncingWithServer called.";
153 syncer::ModelSafeRoutingInfo routing_info;
154 registrar_->GetModelSafeRoutingInfo(&routing_info);
156 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
157 base::Bind(&SyncBackendHostCore::DoStartSyncing,
158 core_.get(), routing_info));
161 void SyncBackendHostImpl::SetEncryptionPassphrase(const std::string& passphrase,
163 DCHECK(registrar_->sync_thread()->IsRunning());
164 if (!IsNigoriEnabled()) {
165 NOTREACHED() << "SetEncryptionPassphrase must never be called when nigori"
170 // We should never be called with an empty passphrase.
171 DCHECK(!passphrase.empty());
173 // This should only be called by the frontend.
174 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
176 // SetEncryptionPassphrase should never be called if we are currently
177 // encrypted with an explicit passphrase.
178 DCHECK(cached_passphrase_type_ == syncer::KEYSTORE_PASSPHRASE ||
179 cached_passphrase_type_ == syncer::IMPLICIT_PASSPHRASE);
181 // Post an encryption task on the syncer thread.
182 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
183 base::Bind(&SyncBackendHostCore::DoSetEncryptionPassphrase,
185 passphrase, is_explicit));
188 bool SyncBackendHostImpl::SetDecryptionPassphrase(
189 const std::string& passphrase) {
190 if (!IsNigoriEnabled()) {
191 NOTREACHED() << "SetDecryptionPassphrase must never be called when nigori"
196 // We should never be called with an empty passphrase.
197 DCHECK(!passphrase.empty());
199 // This should only be called by the frontend.
200 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
202 // This should only be called when we have cached pending keys.
203 DCHECK(cached_pending_keys_.has_blob());
205 // Check the passphrase that was provided against our local cache of the
206 // cryptographer's pending keys. If this was unsuccessful, the UI layer can
207 // immediately call OnPassphraseRequired without showing the user a spinner.
208 if (!CheckPassphraseAgainstCachedPendingKeys(passphrase))
211 // Post a decryption task on the syncer thread.
212 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
213 base::Bind(&SyncBackendHostCore::DoSetDecryptionPassphrase,
217 // Since we were able to decrypt the cached pending keys with the passphrase
218 // provided, we immediately alert the UI layer that the passphrase was
219 // accepted. This will avoid the situation where a user enters a passphrase,
220 // clicks OK, immediately reopens the advanced settings dialog, and gets an
221 // unnecessary prompt for a passphrase.
222 // Note: It is not guaranteed that the passphrase will be accepted by the
223 // syncer thread, since we could receive a new nigori node while the task is
224 // pending. This scenario is a valid race, and SetDecryptionPassphrase can
225 // trigger a new OnPassphraseRequired if it needs to.
226 NotifyPassphraseAccepted();
230 void SyncBackendHostImpl::StopSyncingForShutdown() {
231 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
233 // Immediately stop sending messages to the frontend.
236 // Stop listening for and forwarding locally-triggered sync refresh requests.
237 notification_registrar_.RemoveAll();
239 // Stop non-blocking sync types from sending any more requests to the syncer.
240 sync_core_proxy_.reset();
242 DCHECK(registrar_->sync_thread()->IsRunning());
244 registrar_->RequestWorkerStopOnUIThread();
246 core_->ShutdownOnUIThread();
249 scoped_ptr<base::Thread> SyncBackendHostImpl::Shutdown(ShutdownOption option) {
250 // StopSyncingForShutdown() (which nulls out |frontend_|) should be
253 DCHECK(registrar_->sync_thread()->IsRunning());
255 bool sync_disabled = (option == DISABLE_AND_CLAIM_THREAD);
256 bool sync_thread_claimed =
257 (option == DISABLE_AND_CLAIM_THREAD || option == STOP_AND_CLAIM_THREAD);
259 if (invalidation_handler_registered_) {
261 UnregisterInvalidationIds();
263 invalidator_->UnregisterInvalidationHandler(this);
266 invalidation_handler_registered_ = false;
268 // Shut down and destroy sync manager.
269 registrar_->sync_thread()->message_loop()->PostTask(
271 base::Bind(&SyncBackendHostCore::DoShutdown,
272 core_.get(), sync_disabled));
276 SyncBackendRegistrar* detached_registrar = registrar_.release();
277 detached_registrar->sync_thread()->message_loop()->PostTask(
279 base::Bind(&SyncBackendRegistrar::Shutdown,
280 base::Unretained(detached_registrar)));
282 if (sync_thread_claimed)
283 return detached_registrar->ReleaseSyncThread();
285 return scoped_ptr<base::Thread>();
288 void SyncBackendHostImpl::UnregisterInvalidationIds() {
289 if (invalidation_handler_registered_) {
290 invalidator_->UpdateRegisteredInvalidationIds(
292 syncer::ObjectIdSet());
296 void SyncBackendHostImpl::ConfigureDataTypes(
297 syncer::ConfigureReason reason,
298 const DataTypeConfigStateMap& config_state_map,
299 const base::Callback<void(syncer::ModelTypeSet,
300 syncer::ModelTypeSet)>& ready_task,
301 const base::Callback<void()>& retry_callback) {
302 // Only one configure is allowed at a time. This is guaranteed by our
303 // callers. The SyncBackendHostImpl requests one configure as the backend is
304 // initializing and waits for it to complete. After initialization, all
305 // configurations will pass through the DataTypeManager, which is careful to
306 // never send a new configure request until the current request succeeds.
308 // The SyncBackendRegistrar's routing info will be updated by adding the
309 // types_to_add to the list then removing types_to_remove. Any types which
310 // are not in either of those sets will remain untouched.
312 // Types which were not in the list previously are not fully downloaded, so we
313 // must ask the syncer to download them. Any newly supported datatypes will
314 // not have been in that routing info list, so they will be among the types
315 // downloaded if they are enabled.
317 // The SyncBackendRegistrar's state was initially derived from the types
318 // detected to have been downloaded in the database. Afterwards it is
319 // modified only by this function. We expect it to remain in sync with the
320 // backend because configuration requests are never aborted; they are retried
321 // until they succeed or the backend is shut down.
323 syncer::ModelTypeSet previous_types = registrar_->GetLastConfiguredTypes();
325 syncer::ModelTypeSet disabled_types =
326 GetDataTypesInState(DISABLED, config_state_map);
327 syncer::ModelTypeSet fatal_types =
328 GetDataTypesInState(FATAL, config_state_map);
329 syncer::ModelTypeSet crypto_types =
330 GetDataTypesInState(CRYPTO, config_state_map);
331 disabled_types.PutAll(fatal_types);
332 disabled_types.PutAll(crypto_types);
333 syncer::ModelTypeSet active_types =
334 GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map);
335 syncer::ModelTypeSet clean_first_types =
336 GetDataTypesInState(CONFIGURE_CLEAN, config_state_map);
337 syncer::ModelTypeSet types_to_download = registrar_->ConfigureDataTypes(
338 syncer::Union(active_types, clean_first_types),
340 types_to_download.PutAll(clean_first_types);
341 types_to_download.RemoveAll(syncer::ProxyTypes());
342 if (!types_to_download.Empty())
343 types_to_download.Put(syncer::NIGORI);
345 // TODO(sync): crbug.com/137550.
346 // It's dangerous to configure types that have progress markers. Types with
347 // progress markers can trigger a MIGRATION_DONE response. We are not
348 // prepared to handle a migration during a configure, so we must ensure that
349 // all our types_to_download actually contain no data before we sync them.
351 // One common way to end up in this situation used to be types which
352 // downloaded some or all of their data but have not applied it yet. We avoid
353 // problems with those types by purging the data of any such partially synced
354 // types soon after we load the directory.
356 // Another possible scenario is that we have newly supported or newly enabled
357 // data types being downloaded here but the nigori type, which is always
358 // included in any GetUpdates request, requires migration. The server has
359 // code to detect this scenario based on the configure reason, the fact that
360 // the nigori type is the only requested type which requires migration, and
361 // that the requested types list includes at least one non-nigori type. It
362 // will not send a MIGRATION_DONE response in that case. We still need to be
363 // careful to not send progress markers for non-nigori types, though. If a
364 // non-nigori type in the request requires migration, a MIGRATION_DONE
365 // response will be sent.
367 syncer::ModelSafeRoutingInfo routing_info;
368 registrar_->GetModelSafeRoutingInfo(&routing_info);
370 syncer::ModelTypeSet current_types = registrar_->GetLastConfiguredTypes();
371 syncer::ModelTypeSet types_to_purge =
372 syncer::Difference(previous_types, current_types);
373 syncer::ModelTypeSet inactive_types =
374 GetDataTypesInState(CONFIGURE_INACTIVE, config_state_map);
375 types_to_purge.RemoveAll(inactive_types);
377 // If a type has already been disabled and unapplied or journaled, it will
378 // not be part of the |types_to_purge| set, and therefore does not need
379 // to be acted on again.
380 fatal_types.RetainAll(types_to_purge);
381 syncer::ModelTypeSet unapply_types =
382 syncer::Union(crypto_types, clean_first_types);
383 unapply_types.RetainAll(types_to_purge);
385 DCHECK(syncer::Intersection(current_types, fatal_types).Empty());
386 DCHECK(syncer::Intersection(current_types, crypto_types).Empty());
387 DCHECK(current_types.HasAll(types_to_download));
389 SDVLOG(1) << "Types "
390 << syncer::ModelTypeSetToString(types_to_download)
391 << " added; calling DoConfigureSyncer";
392 // Divide up the types into their corresponding actions (each is mutually
394 // - Types which have just been added to the routing info (types_to_download):
396 // - Types which have encountered a fatal error (fatal_types) are deleted
397 // from the directory and journaled in the delete journal.
398 // - Types which have encountered a cryptographer error (crypto_types) are
399 // unapplied (local state is purged but sync state is not).
400 // - All other types not in the routing info (types just disabled) are deleted
401 // from the directory.
402 // - Everything else (enabled types and already disabled types) is not
404 RequestConfigureSyncer(reason,
415 void SyncBackendHostImpl::EnableEncryptEverything() {
416 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
417 base::Bind(&SyncBackendHostCore::DoEnableEncryptEverything,
421 void SyncBackendHostImpl::ActivateDataType(
422 syncer::ModelType type, syncer::ModelSafeGroup group,
423 ChangeProcessor* change_processor) {
424 registrar_->ActivateDataType(type, group, change_processor, GetUserShare());
427 void SyncBackendHostImpl::DeactivateDataType(syncer::ModelType type) {
428 registrar_->DeactivateDataType(type);
431 syncer::UserShare* SyncBackendHostImpl::GetUserShare() const {
432 return core_->sync_manager()->GetUserShare();
435 scoped_ptr<syncer::SyncCoreProxy> SyncBackendHostImpl::GetSyncCoreProxy() {
436 return scoped_ptr<syncer::SyncCoreProxy>(sync_core_proxy_->Clone());
439 SyncBackendHostImpl::Status SyncBackendHostImpl::GetDetailedStatus() {
440 DCHECK(initialized());
441 return core_->sync_manager()->GetDetailedStatus();
444 syncer::sessions::SyncSessionSnapshot
445 SyncBackendHostImpl::GetLastSessionSnapshot() const {
446 return last_snapshot_;
449 bool SyncBackendHostImpl::HasUnsyncedItems() const {
450 DCHECK(initialized());
451 return core_->sync_manager()->HasUnsyncedItems();
454 bool SyncBackendHostImpl::IsNigoriEnabled() const {
455 return registrar_.get() && registrar_->IsNigoriEnabled();
458 syncer::PassphraseType SyncBackendHostImpl::GetPassphraseType() const {
459 return cached_passphrase_type_;
462 base::Time SyncBackendHostImpl::GetExplicitPassphraseTime() const {
463 return cached_explicit_passphrase_time_;
466 bool SyncBackendHostImpl::IsCryptographerReady(
467 const syncer::BaseTransaction* trans) const {
468 return initialized() && trans->GetCryptographer()->is_ready();
471 void SyncBackendHostImpl::GetModelSafeRoutingInfo(
472 syncer::ModelSafeRoutingInfo* out) const {
474 CHECK(registrar_.get());
475 registrar_->GetModelSafeRoutingInfo(out);
481 SyncedDeviceTracker* SyncBackendHostImpl::GetSyncedDeviceTracker() const {
484 return core_->synced_device_tracker();
487 void SyncBackendHostImpl::RequestBufferedProtocolEventsAndEnableForwarding() {
488 registrar_->sync_thread()->message_loop()->PostTask(
491 &SyncBackendHostCore::SendBufferedProtocolEventsAndEnableForwarding,
495 void SyncBackendHostImpl::DisableProtocolEventForwarding() {
496 registrar_->sync_thread()->message_loop()->PostTask(
499 &SyncBackendHostCore::DisableProtocolEventForwarding,
503 void SyncBackendHostImpl::EnableDirectoryTypeDebugInfoForwarding() {
504 DCHECK(initialized());
505 registrar_->sync_thread()->message_loop()->PostTask(
508 &SyncBackendHostCore::EnableDirectoryTypeDebugInfoForwarding,
512 void SyncBackendHostImpl::DisableDirectoryTypeDebugInfoForwarding() {
513 DCHECK(initialized());
514 registrar_->sync_thread()->message_loop()->PostTask(
517 &SyncBackendHostCore::DisableDirectoryTypeDebugInfoForwarding,
521 void SyncBackendHostImpl::GetAllNodesForTypes(
522 syncer::ModelTypeSet types,
523 base::Callback<void(const std::vector<syncer::ModelType>&,
524 ScopedVector<base::ListValue>)> callback) {
525 DCHECK(initialized());
526 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
528 &SyncBackendHostCore::GetAllNodesForTypes,
531 frontend_loop_->message_loop_proxy(),
535 void SyncBackendHostImpl::InitCore(scoped_ptr<DoInitializeOptions> options) {
536 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
537 base::Bind(&SyncBackendHostCore::DoInitialize,
538 core_.get(), base::Passed(&options)));
541 void SyncBackendHostImpl::RequestConfigureSyncer(
542 syncer::ConfigureReason reason,
543 syncer::ModelTypeSet to_download,
544 syncer::ModelTypeSet to_purge,
545 syncer::ModelTypeSet to_journal,
546 syncer::ModelTypeSet to_unapply,
547 syncer::ModelTypeSet to_ignore,
548 const syncer::ModelSafeRoutingInfo& routing_info,
549 const base::Callback<void(syncer::ModelTypeSet,
550 syncer::ModelTypeSet)>& ready_task,
551 const base::Closure& retry_callback) {
552 DoConfigureSyncerTypes config_types;
553 config_types.to_download = to_download;
554 config_types.to_purge = to_purge;
555 config_types.to_journal = to_journal;
556 config_types.to_unapply = to_unapply;
557 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
558 base::Bind(&SyncBackendHostCore::DoConfigureSyncer,
567 void SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop(
568 const syncer::ModelTypeSet enabled_types,
569 const syncer::ModelTypeSet succeeded_configuration_types,
570 const syncer::ModelTypeSet failed_configuration_types,
571 const base::Callback<void(syncer::ModelTypeSet,
572 syncer::ModelTypeSet)>& ready_task) {
576 invalidator_->UpdateRegisteredInvalidationIds(
578 ModelTypeSetToObjectIdSet(enabled_types));
580 if (!ready_task.is_null())
581 ready_task.Run(succeeded_configuration_types, failed_configuration_types);
584 void SyncBackendHostImpl::Observe(
586 const content::NotificationSource& source,
587 const content::NotificationDetails& details) {
588 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
589 DCHECK_EQ(type, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL);
591 content::Details<const syncer::ModelTypeSet> state_details(details);
592 const syncer::ModelTypeSet& types = *(state_details.ptr());
593 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
594 base::Bind(&SyncBackendHostCore::DoRefreshTypes, core_.get(), types));
597 void SyncBackendHostImpl::AddExperimentalTypes() {
598 CHECK(initialized());
599 syncer::Experiments experiments;
600 if (core_->sync_manager()->ReceivedExperiment(&experiments))
601 frontend_->OnExperimentsChanged(experiments);
604 void SyncBackendHostImpl::HandleControlTypesDownloadRetry() {
605 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
609 frontend_->OnSyncConfigureRetry();
612 void SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop(
613 const syncer::WeakHandle<syncer::JsBackend> js_backend,
614 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>
616 syncer::SyncCoreProxy* sync_core_proxy) {
617 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
619 sync_core_proxy_ = sync_core_proxy->Clone();
626 invalidator_->RegisterInvalidationHandler(this);
627 invalidation_handler_registered_ = true;
629 // Fake a state change to initialize the SyncManager's cached invalidator
631 OnInvalidatorStateChange(invalidator_->GetInvalidatorState());
633 // Start forwarding refresh requests to the SyncManager
634 notification_registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
635 content::Source<Profile>(profile_));
637 // Now that we've downloaded the control types, we can see if there are any
638 // experimental types to enable. This should be done before we inform
639 // the frontend to ensure they're visible in the customize screen.
640 AddExperimentalTypes();
641 frontend_->OnBackendInitialized(js_backend,
646 void SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop() {
647 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
651 frontend_->OnBackendInitialized(
652 syncer::WeakHandle<syncer::JsBackend>(),
653 syncer::WeakHandle<syncer::DataTypeDebugInfoListener>(),
657 void SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop(
658 const syncer::sessions::SyncSessionSnapshot& snapshot) {
661 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
663 last_snapshot_ = snapshot;
665 SDVLOG(1) << "Got snapshot " << snapshot.ToString();
667 // Process any changes to the datatypes we're syncing.
668 // TODO(sync): add support for removing types.
670 AddExperimentalTypes();
673 frontend_->OnSyncCycleCompleted();
676 void SyncBackendHostImpl::RetryConfigurationOnFrontendLoop(
677 const base::Closure& retry_callback) {
678 SDVLOG(1) << "Failed to complete configuration, informing of retry.";
679 retry_callback.Run();
682 void SyncBackendHostImpl::PersistEncryptionBootstrapToken(
683 const std::string& token,
684 syncer::BootstrapTokenType token_type) {
685 CHECK(sync_prefs_.get());
686 DCHECK(!token.empty());
687 if (token_type == syncer::PASSPHRASE_BOOTSTRAP_TOKEN)
688 sync_prefs_->SetEncryptionBootstrapToken(token);
690 sync_prefs_->SetKeystoreEncryptionBootstrapToken(token);
693 void SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop(
694 const syncer::SyncProtocolError& sync_error) {
697 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
698 frontend_->OnActionableError(sync_error);
701 void SyncBackendHostImpl::HandleMigrationRequestedOnFrontendLoop(
702 syncer::ModelTypeSet types) {
705 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
706 frontend_->OnMigrationNeededForTypes(types);
709 void SyncBackendHostImpl::OnInvalidatorStateChange(
710 syncer::InvalidatorState state) {
711 registrar_->sync_thread()->message_loop()->PostTask(
713 base::Bind(&SyncBackendHostCore::DoOnInvalidatorStateChange,
718 void SyncBackendHostImpl::OnIncomingInvalidation(
719 const syncer::ObjectIdInvalidationMap& invalidation_map) {
720 registrar_->sync_thread()->message_loop()->PostTask(
722 base::Bind(&SyncBackendHostCore::DoOnIncomingInvalidation,
727 std::string SyncBackendHostImpl::GetOwnerName() const {
728 return "SyncBackendHostImpl";
731 bool SyncBackendHostImpl::CheckPassphraseAgainstCachedPendingKeys(
732 const std::string& passphrase) const {
733 DCHECK(cached_pending_keys_.has_blob());
734 DCHECK(!passphrase.empty());
735 syncer::Nigori nigori;
736 nigori.InitByDerivation("localhost", "dummy", passphrase);
737 std::string plaintext;
738 bool result = nigori.Decrypt(cached_pending_keys_.blob(), &plaintext);
739 DVLOG_IF(1, result) << "Passphrase failed to decrypt pending keys.";
743 void SyncBackendHostImpl::NotifyPassphraseRequired(
744 syncer::PassphraseRequiredReason reason,
745 sync_pb::EncryptedData pending_keys) {
749 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
751 // Update our cache of the cryptographer's pending keys.
752 cached_pending_keys_ = pending_keys;
754 frontend_->OnPassphraseRequired(reason, pending_keys);
757 void SyncBackendHostImpl::NotifyPassphraseAccepted() {
761 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
763 // Clear our cache of the cryptographer's pending keys.
764 cached_pending_keys_.clear_blob();
765 frontend_->OnPassphraseAccepted();
768 void SyncBackendHostImpl::NotifyEncryptedTypesChanged(
769 syncer::ModelTypeSet encrypted_types,
770 bool encrypt_everything) {
774 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
775 frontend_->OnEncryptedTypesChanged(
776 encrypted_types, encrypt_everything);
779 void SyncBackendHostImpl::NotifyEncryptionComplete() {
783 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
784 frontend_->OnEncryptionComplete();
787 void SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop(
788 syncer::PassphraseType type,
789 base::Time explicit_passphrase_time) {
790 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
791 DVLOG(1) << "Passphrase type changed to "
792 << syncer::PassphraseTypeToString(type);
793 cached_passphrase_type_ = type;
794 cached_explicit_passphrase_time_ = explicit_passphrase_time;
797 void SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop(
798 syncer::ConnectionStatus status) {
802 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
804 DVLOG(1) << "Connection status changed: "
805 << syncer::ConnectionStatusToString(status);
806 frontend_->OnConnectionStatusChange(status);
809 void SyncBackendHostImpl::HandleProtocolEventOnFrontendLoop(
810 syncer::ProtocolEvent* event) {
811 scoped_ptr<syncer::ProtocolEvent> scoped_event(event);
814 frontend_->OnProtocolEvent(*scoped_event);
817 void SyncBackendHostImpl::HandleDirectoryCommitCountersUpdatedOnFrontendLoop(
818 syncer::ModelType type,
819 const syncer::CommitCounters& counters) {
822 frontend_->OnDirectoryTypeCommitCounterUpdated(type, counters);
825 void SyncBackendHostImpl::HandleDirectoryUpdateCountersUpdatedOnFrontendLoop(
826 syncer::ModelType type,
827 const syncer::UpdateCounters& counters) {
830 frontend_->OnDirectoryTypeUpdateCounterUpdated(type, counters);
833 void SyncBackendHostImpl::HandleDirectoryStatusCountersUpdatedOnFrontendLoop(
834 syncer::ModelType type,
835 const syncer::StatusCounters& counters) {
838 frontend_->OnDirectoryTypeStatusCounterUpdated(type, counters);
841 base::MessageLoop* SyncBackendHostImpl::GetSyncLoopForTesting() {
842 return registrar_->sync_thread()->message_loop();
845 } // namespace browser_sync