Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync / glue / sync_backend_host_impl.cc
blob50f7df94081c5a624a0edde093d4a1d6eeba8609
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 "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/invalidation/invalidation_service.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/browser/sync/glue/sync_frontend.h"
16 #include "chrome/browser/sync/sync_prefs.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/notification_details.h"
20 #include "content/public/browser/notification_source.h"
21 #include "sync/internal_api/public/base_transaction.h"
22 #include "sync/internal_api/public/http_bridge.h"
23 #include "sync/internal_api/public/internal_components_factory.h"
24 #include "sync/internal_api/public/internal_components_factory_impl.h"
25 #include "sync/internal_api/public/network_resources.h"
26 #include "sync/internal_api/public/sync_manager.h"
27 #include "sync/internal_api/public/sync_manager_factory.h"
28 #include "sync/internal_api/public/util/experiments.h"
29 #include "sync/internal_api/public/util/sync_string_conversions.h"
30 #include "sync/notifier/object_id_invalidation_map.h"
32 // Helper macros to log with the syncer thread name; useful when there
33 // are multiple syncers involved.
35 #define SLOG(severity) LOG(severity) << name_ << ": "
37 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
39 using syncer::InternalComponentsFactory;
41 static const base::FilePath::CharType kSyncDataFolderName[] =
42 FILE_PATH_LITERAL("Sync Data");
44 namespace browser_sync {
46 SyncBackendHostImpl::SyncBackendHostImpl(
47 const std::string& name,
48 Profile* profile,
49 const base::WeakPtr<SyncPrefs>& sync_prefs)
50 : frontend_loop_(base::MessageLoop::current()),
51 profile_(profile),
52 name_(name),
53 initialized_(false),
54 sync_prefs_(sync_prefs),
55 frontend_(NULL),
56 cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE),
57 invalidator_(
58 invalidation::InvalidationServiceFactory::GetForProfile(profile)),
59 invalidation_handler_registered_(false),
60 weak_ptr_factory_(this) {
61 core_ = new SyncBackendHostCore(
62 name_,
63 profile_->GetPath().Append(kSyncDataFolderName),
64 sync_prefs_->HasSyncSetupCompleted(),
65 weak_ptr_factory_.GetWeakPtr());
68 SyncBackendHostImpl::~SyncBackendHostImpl() {
69 DCHECK(!core_.get() && !frontend_) << "Must call Shutdown before destructor.";
70 DCHECK(!registrar_.get());
73 void SyncBackendHostImpl::Initialize(
74 SyncFrontend* frontend,
75 scoped_ptr<base::Thread> sync_thread,
76 const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
77 const GURL& sync_service_url,
78 const syncer::SyncCredentials& credentials,
79 bool delete_sync_data_folder,
80 scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
81 scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
82 syncer::ReportUnrecoverableErrorFunction
83 report_unrecoverable_error_function,
84 syncer::NetworkResources* network_resources) {
85 registrar_.reset(new browser_sync::SyncBackendRegistrar(name_,
86 profile_,
87 sync_thread.Pass()));
88 CHECK(registrar_->sync_thread());
90 frontend_ = frontend;
91 DCHECK(frontend);
93 syncer::ModelSafeRoutingInfo routing_info;
94 std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers;
95 registrar_->GetModelSafeRoutingInfo(&routing_info);
96 registrar_->GetWorkers(&workers);
98 InternalComponentsFactory::Switches factory_switches = {
99 InternalComponentsFactory::ENCRYPTION_KEYSTORE,
100 InternalComponentsFactory::BACKOFF_NORMAL
103 CommandLine* cl = CommandLine::ForCurrentProcess();
104 if (cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) {
105 factory_switches.backoff_override =
106 InternalComponentsFactory::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE;
108 if (cl->HasSwitch(switches::kSyncEnableGetUpdateAvoidance)) {
109 factory_switches.pre_commit_updates_policy =
110 InternalComponentsFactory::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE;
113 scoped_ptr<DoInitializeOptions> init_opts(new DoInitializeOptions(
114 registrar_->sync_thread()->message_loop(),
115 registrar_.get(),
116 routing_info,
117 workers,
118 extensions_activity_monitor_.GetExtensionsActivity(),
119 event_handler,
120 sync_service_url,
121 network_resources->GetHttpPostProviderFactory(
122 make_scoped_refptr(profile_->GetRequestContext()),
123 NetworkTimeTracker::BuildNotifierUpdateCallback(),
124 core_->GetRequestContextCancelationSignal()),
125 credentials,
126 invalidator_->GetInvalidatorClientId(),
127 sync_manager_factory.Pass(),
128 delete_sync_data_folder,
129 sync_prefs_->GetEncryptionBootstrapToken(),
130 sync_prefs_->GetKeystoreEncryptionBootstrapToken(),
131 scoped_ptr<InternalComponentsFactory>(
132 new syncer::InternalComponentsFactoryImpl(factory_switches)).Pass(),
133 unrecoverable_error_handler.Pass(),
134 report_unrecoverable_error_function));
135 InitCore(init_opts.Pass());
138 void SyncBackendHostImpl::UpdateCredentials(
139 const syncer::SyncCredentials& credentials) {
140 DCHECK(registrar_->sync_thread()->IsRunning());
141 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
142 base::Bind(&SyncBackendHostCore::DoUpdateCredentials,
143 core_.get(),
144 credentials));
147 void SyncBackendHostImpl::StartSyncingWithServer() {
148 SDVLOG(1) << "SyncBackendHostImpl::StartSyncingWithServer called.";
150 syncer::ModelSafeRoutingInfo routing_info;
151 registrar_->GetModelSafeRoutingInfo(&routing_info);
153 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
154 base::Bind(&SyncBackendHostCore::DoStartSyncing,
155 core_.get(), routing_info));
158 void SyncBackendHostImpl::SetEncryptionPassphrase(const std::string& passphrase,
159 bool is_explicit) {
160 DCHECK(registrar_->sync_thread()->IsRunning());
161 if (!IsNigoriEnabled()) {
162 NOTREACHED() << "SetEncryptionPassphrase must never be called when nigori"
163 " is disabled.";
164 return;
167 // We should never be called with an empty passphrase.
168 DCHECK(!passphrase.empty());
170 // This should only be called by the frontend.
171 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
173 // SetEncryptionPassphrase should never be called if we are currently
174 // encrypted with an explicit passphrase.
175 DCHECK(cached_passphrase_type_ == syncer::KEYSTORE_PASSPHRASE ||
176 cached_passphrase_type_ == syncer::IMPLICIT_PASSPHRASE);
178 // Post an encryption task on the syncer thread.
179 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
180 base::Bind(&SyncBackendHostCore::DoSetEncryptionPassphrase,
181 core_.get(),
182 passphrase, is_explicit));
185 bool SyncBackendHostImpl::SetDecryptionPassphrase(
186 const std::string& passphrase) {
187 if (!IsNigoriEnabled()) {
188 NOTREACHED() << "SetDecryptionPassphrase must never be called when nigori"
189 " is disabled.";
190 return false;
193 // We should never be called with an empty passphrase.
194 DCHECK(!passphrase.empty());
196 // This should only be called by the frontend.
197 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
199 // This should only be called when we have cached pending keys.
200 DCHECK(cached_pending_keys_.has_blob());
202 // Check the passphrase that was provided against our local cache of the
203 // cryptographer's pending keys. If this was unsuccessful, the UI layer can
204 // immediately call OnPassphraseRequired without showing the user a spinner.
205 if (!CheckPassphraseAgainstCachedPendingKeys(passphrase))
206 return false;
208 // Post a decryption task on the syncer thread.
209 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
210 base::Bind(&SyncBackendHostCore::DoSetDecryptionPassphrase,
211 core_.get(),
212 passphrase));
214 // Since we were able to decrypt the cached pending keys with the passphrase
215 // provided, we immediately alert the UI layer that the passphrase was
216 // accepted. This will avoid the situation where a user enters a passphrase,
217 // clicks OK, immediately reopens the advanced settings dialog, and gets an
218 // unnecessary prompt for a passphrase.
219 // Note: It is not guaranteed that the passphrase will be accepted by the
220 // syncer thread, since we could receive a new nigori node while the task is
221 // pending. This scenario is a valid race, and SetDecryptionPassphrase can
222 // trigger a new OnPassphraseRequired if it needs to.
223 NotifyPassphraseAccepted();
224 return true;
227 void SyncBackendHostImpl::StopSyncingForShutdown() {
228 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
230 // Immediately stop sending messages to the frontend.
231 frontend_ = NULL;
233 // Stop listening for and forwarding locally-triggered sync refresh requests.
234 notification_registrar_.RemoveAll();
236 DCHECK(registrar_->sync_thread()->IsRunning());
238 registrar_->RequestWorkerStopOnUIThread();
240 core_->ShutdownOnUIThread();
243 scoped_ptr<base::Thread> SyncBackendHostImpl::Shutdown(ShutdownOption option) {
244 // StopSyncingForShutdown() (which nulls out |frontend_|) should be
245 // called first.
246 DCHECK(!frontend_);
247 DCHECK(registrar_->sync_thread()->IsRunning());
249 bool sync_disabled = (option == DISABLE_AND_CLAIM_THREAD);
250 bool sync_thread_claimed =
251 (option == DISABLE_AND_CLAIM_THREAD || option == STOP_AND_CLAIM_THREAD);
253 if (invalidation_handler_registered_) {
254 if (sync_disabled) {
255 UnregisterInvalidationIds();
257 invalidator_->UnregisterInvalidationHandler(this);
258 invalidator_ = NULL;
260 invalidation_handler_registered_ = false;
262 // Shut down and destroy sync manager.
263 registrar_->sync_thread()->message_loop()->PostTask(
264 FROM_HERE,
265 base::Bind(&SyncBackendHostCore::DoShutdown,
266 core_.get(), sync_disabled));
267 core_ = NULL;
269 // Worker cleanup.
270 SyncBackendRegistrar* detached_registrar = registrar_.release();
271 detached_registrar->sync_thread()->message_loop()->PostTask(
272 FROM_HERE,
273 base::Bind(&SyncBackendRegistrar::Shutdown,
274 base::Unretained(detached_registrar)));
276 if (sync_thread_claimed)
277 return detached_registrar->ReleaseSyncThread();
278 else
279 return scoped_ptr<base::Thread>();
282 void SyncBackendHostImpl::UnregisterInvalidationIds() {
283 if (invalidation_handler_registered_) {
284 invalidator_->UpdateRegisteredInvalidationIds(
285 this,
286 syncer::ObjectIdSet());
290 void SyncBackendHostImpl::ConfigureDataTypes(
291 syncer::ConfigureReason reason,
292 const DataTypeConfigStateMap& config_state_map,
293 const base::Callback<void(syncer::ModelTypeSet,
294 syncer::ModelTypeSet)>& ready_task,
295 const base::Callback<void()>& retry_callback) {
296 // Only one configure is allowed at a time. This is guaranteed by our
297 // callers. The SyncBackendHostImpl requests one configure as the backend is
298 // initializing and waits for it to complete. After initialization, all
299 // configurations will pass through the DataTypeManager, which is careful to
300 // never send a new configure request until the current request succeeds.
302 // The SyncBackendRegistrar's routing info will be updated by adding the
303 // types_to_add to the list then removing types_to_remove. Any types which
304 // are not in either of those sets will remain untouched.
306 // Types which were not in the list previously are not fully downloaded, so we
307 // must ask the syncer to download them. Any newly supported datatypes will
308 // not have been in that routing info list, so they will be among the types
309 // downloaded if they are enabled.
311 // The SyncBackendRegistrar's state was initially derived from the types
312 // detected to have been downloaded in the database. Afterwards it is
313 // modified only by this function. We expect it to remain in sync with the
314 // backend because configuration requests are never aborted; they are retried
315 // until they succeed or the backend is shut down.
317 syncer::ModelTypeSet previous_types = registrar_->GetLastConfiguredTypes();
319 syncer::ModelTypeSet disabled_types =
320 GetDataTypesInState(DISABLED, config_state_map);
321 syncer::ModelTypeSet fatal_types =
322 GetDataTypesInState(FATAL, config_state_map);
323 syncer::ModelTypeSet crypto_types =
324 GetDataTypesInState(CRYPTO, config_state_map);
325 disabled_types.PutAll(fatal_types);
326 disabled_types.PutAll(crypto_types);
327 syncer::ModelTypeSet active_types =
328 GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map);
329 syncer::ModelTypeSet clean_first_types =
330 GetDataTypesInState(CONFIGURE_CLEAN, config_state_map);
331 syncer::ModelTypeSet types_to_download = registrar_->ConfigureDataTypes(
332 syncer::Union(active_types, clean_first_types),
333 disabled_types);
334 types_to_download.PutAll(clean_first_types);
335 types_to_download.RemoveAll(syncer::ProxyTypes());
336 if (!types_to_download.Empty())
337 types_to_download.Put(syncer::NIGORI);
339 // TODO(sync): crbug.com/137550.
340 // It's dangerous to configure types that have progress markers. Types with
341 // progress markers can trigger a MIGRATION_DONE response. We are not
342 // prepared to handle a migration during a configure, so we must ensure that
343 // all our types_to_download actually contain no data before we sync them.
345 // One common way to end up in this situation used to be types which
346 // downloaded some or all of their data but have not applied it yet. We avoid
347 // problems with those types by purging the data of any such partially synced
348 // types soon after we load the directory.
350 // Another possible scenario is that we have newly supported or newly enabled
351 // data types being downloaded here but the nigori type, which is always
352 // included in any GetUpdates request, requires migration. The server has
353 // code to detect this scenario based on the configure reason, the fact that
354 // the nigori type is the only requested type which requires migration, and
355 // that the requested types list includes at least one non-nigori type. It
356 // will not send a MIGRATION_DONE response in that case. We still need to be
357 // careful to not send progress markers for non-nigori types, though. If a
358 // non-nigori type in the request requires migration, a MIGRATION_DONE
359 // response will be sent.
361 syncer::ModelSafeRoutingInfo routing_info;
362 registrar_->GetModelSafeRoutingInfo(&routing_info);
364 syncer::ModelTypeSet current_types = registrar_->GetLastConfiguredTypes();
365 syncer::ModelTypeSet types_to_purge =
366 syncer::Difference(previous_types, current_types);
367 syncer::ModelTypeSet inactive_types =
368 GetDataTypesInState(CONFIGURE_INACTIVE, config_state_map);
369 types_to_purge.RemoveAll(inactive_types);
371 // If a type has already been disabled and unapplied or journaled, it will
372 // not be part of the |types_to_purge| set, and therefore does not need
373 // to be acted on again.
374 fatal_types.RetainAll(types_to_purge);
375 syncer::ModelTypeSet unapply_types =
376 syncer::Union(crypto_types, clean_first_types);
377 unapply_types.RetainAll(types_to_purge);
379 DCHECK(syncer::Intersection(current_types, fatal_types).Empty());
380 DCHECK(syncer::Intersection(current_types, crypto_types).Empty());
381 DCHECK(current_types.HasAll(types_to_download));
383 SDVLOG(1) << "Types "
384 << syncer::ModelTypeSetToString(types_to_download)
385 << " added; calling DoConfigureSyncer";
386 // Divide up the types into their corresponding actions (each is mutually
387 // exclusive):
388 // - Types which have just been added to the routing info (types_to_download):
389 // are downloaded.
390 // - Types which have encountered a fatal error (fatal_types) are deleted
391 // from the directory and journaled in the delete journal.
392 // - Types which have encountered a cryptographer error (crypto_types) are
393 // unapplied (local state is purged but sync state is not).
394 // - All other types not in the routing info (types just disabled) are deleted
395 // from the directory.
396 // - Everything else (enabled types and already disabled types) is not
397 // touched.
398 RequestConfigureSyncer(reason,
399 types_to_download,
400 types_to_purge,
401 fatal_types,
402 unapply_types,
403 inactive_types,
404 routing_info,
405 ready_task,
406 retry_callback);
409 void SyncBackendHostImpl::EnableEncryptEverything() {
410 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
411 base::Bind(&SyncBackendHostCore::DoEnableEncryptEverything,
412 core_.get()));
415 void SyncBackendHostImpl::ActivateDataType(
416 syncer::ModelType type, syncer::ModelSafeGroup group,
417 ChangeProcessor* change_processor) {
418 registrar_->ActivateDataType(type, group, change_processor, GetUserShare());
421 void SyncBackendHostImpl::DeactivateDataType(syncer::ModelType type) {
422 registrar_->DeactivateDataType(type);
425 syncer::UserShare* SyncBackendHostImpl::GetUserShare() const {
426 return core_->sync_manager()->GetUserShare();
429 SyncBackendHostImpl::Status SyncBackendHostImpl::GetDetailedStatus() {
430 DCHECK(initialized());
431 return core_->sync_manager()->GetDetailedStatus();
434 syncer::sessions::SyncSessionSnapshot
435 SyncBackendHostImpl::GetLastSessionSnapshot() const {
436 return last_snapshot_;
439 bool SyncBackendHostImpl::HasUnsyncedItems() const {
440 DCHECK(initialized());
441 return core_->sync_manager()->HasUnsyncedItems();
444 bool SyncBackendHostImpl::IsNigoriEnabled() const {
445 return registrar_.get() && registrar_->IsNigoriEnabled();
448 syncer::PassphraseType SyncBackendHostImpl::GetPassphraseType() const {
449 return cached_passphrase_type_;
452 base::Time SyncBackendHostImpl::GetExplicitPassphraseTime() const {
453 return cached_explicit_passphrase_time_;
456 bool SyncBackendHostImpl::IsCryptographerReady(
457 const syncer::BaseTransaction* trans) const {
458 return initialized() && trans->GetCryptographer()->is_ready();
461 void SyncBackendHostImpl::GetModelSafeRoutingInfo(
462 syncer::ModelSafeRoutingInfo* out) const {
463 if (initialized()) {
464 CHECK(registrar_.get());
465 registrar_->GetModelSafeRoutingInfo(out);
466 } else {
467 NOTREACHED();
471 SyncedDeviceTracker* SyncBackendHostImpl::GetSyncedDeviceTracker() const {
472 if (!initialized())
473 return NULL;
474 return core_->synced_device_tracker();
477 void SyncBackendHostImpl::InitCore(scoped_ptr<DoInitializeOptions> options) {
478 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
479 base::Bind(&SyncBackendHostCore::DoInitialize,
480 core_.get(), base::Passed(&options)));
483 void SyncBackendHostImpl::RequestConfigureSyncer(
484 syncer::ConfigureReason reason,
485 syncer::ModelTypeSet to_download,
486 syncer::ModelTypeSet to_purge,
487 syncer::ModelTypeSet to_journal,
488 syncer::ModelTypeSet to_unapply,
489 syncer::ModelTypeSet to_ignore,
490 const syncer::ModelSafeRoutingInfo& routing_info,
491 const base::Callback<void(syncer::ModelTypeSet,
492 syncer::ModelTypeSet)>& ready_task,
493 const base::Closure& retry_callback) {
494 DoConfigureSyncerTypes config_types;
495 config_types.to_download = to_download;
496 config_types.to_purge = to_purge;
497 config_types.to_journal = to_journal;
498 config_types.to_unapply = to_unapply;
499 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
500 base::Bind(&SyncBackendHostCore::DoConfigureSyncer,
501 core_.get(),
502 reason,
503 config_types,
504 routing_info,
505 ready_task,
506 retry_callback));
509 void SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop(
510 const syncer::ModelTypeSet enabled_types,
511 const syncer::ModelTypeSet succeeded_configuration_types,
512 const syncer::ModelTypeSet failed_configuration_types,
513 const base::Callback<void(syncer::ModelTypeSet,
514 syncer::ModelTypeSet)>& ready_task) {
515 if (!frontend_)
516 return;
518 invalidator_->UpdateRegisteredInvalidationIds(
519 this,
520 ModelTypeSetToObjectIdSet(enabled_types));
522 if (!ready_task.is_null())
523 ready_task.Run(succeeded_configuration_types, failed_configuration_types);
526 void SyncBackendHostImpl::Observe(
527 int type,
528 const content::NotificationSource& source,
529 const content::NotificationDetails& details) {
530 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
531 DCHECK_EQ(type, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL);
533 content::Details<const syncer::ModelTypeSet> state_details(details);
534 const syncer::ModelTypeSet& types = *(state_details.ptr());
535 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
536 base::Bind(&SyncBackendHostCore::DoRefreshTypes, core_.get(), types));
539 void SyncBackendHostImpl::AddExperimentalTypes() {
540 CHECK(initialized());
541 syncer::Experiments experiments;
542 if (core_->sync_manager()->ReceivedExperiment(&experiments))
543 frontend_->OnExperimentsChanged(experiments);
546 void SyncBackendHostImpl::HandleControlTypesDownloadRetry() {
547 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
548 if (!frontend_)
549 return;
551 frontend_->OnSyncConfigureRetry();
554 void SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop(
555 const syncer::WeakHandle<syncer::JsBackend> js_backend,
556 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>
557 debug_info_listener) {
558 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
559 if (!frontend_)
560 return;
562 initialized_ = true;
564 invalidator_->RegisterInvalidationHandler(this);
565 invalidation_handler_registered_ = true;
567 // Fake a state change to initialize the SyncManager's cached invalidator
568 // state.
569 OnInvalidatorStateChange(invalidator_->GetInvalidatorState());
571 // Start forwarding refresh requests to the SyncManager
572 notification_registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
573 content::Source<Profile>(profile_));
575 // Now that we've downloaded the control types, we can see if there are any
576 // experimental types to enable. This should be done before we inform
577 // the frontend to ensure they're visible in the customize screen.
578 AddExperimentalTypes();
579 frontend_->OnBackendInitialized(js_backend,
580 debug_info_listener,
581 true);
584 void SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop() {
585 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
586 if (!frontend_)
587 return;
589 frontend_->OnBackendInitialized(
590 syncer::WeakHandle<syncer::JsBackend>(),
591 syncer::WeakHandle<syncer::DataTypeDebugInfoListener>(),
592 false);
595 void SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop(
596 const syncer::sessions::SyncSessionSnapshot& snapshot) {
597 if (!frontend_)
598 return;
599 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
601 last_snapshot_ = snapshot;
603 SDVLOG(1) << "Got snapshot " << snapshot.ToString();
605 const syncer::ModelTypeSet to_migrate =
606 snapshot.model_neutral_state().types_needing_local_migration;
607 if (!to_migrate.Empty())
608 frontend_->OnMigrationNeededForTypes(to_migrate);
610 // Process any changes to the datatypes we're syncing.
611 // TODO(sync): add support for removing types.
612 if (initialized())
613 AddExperimentalTypes();
615 if (initialized())
616 frontend_->OnSyncCycleCompleted();
619 void SyncBackendHostImpl::RetryConfigurationOnFrontendLoop(
620 const base::Closure& retry_callback) {
621 SDVLOG(1) << "Failed to complete configuration, informing of retry.";
622 retry_callback.Run();
625 void SyncBackendHostImpl::PersistEncryptionBootstrapToken(
626 const std::string& token,
627 syncer::BootstrapTokenType token_type) {
628 CHECK(sync_prefs_.get());
629 DCHECK(!token.empty());
630 if (token_type == syncer::PASSPHRASE_BOOTSTRAP_TOKEN)
631 sync_prefs_->SetEncryptionBootstrapToken(token);
632 else
633 sync_prefs_->SetKeystoreEncryptionBootstrapToken(token);
636 void SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop(
637 const syncer::SyncProtocolError& sync_error) {
638 if (!frontend_)
639 return;
640 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
641 frontend_->OnActionableError(sync_error);
644 void SyncBackendHostImpl::OnInvalidatorStateChange(
645 syncer::InvalidatorState state) {
646 registrar_->sync_thread()->message_loop()->PostTask(
647 FROM_HERE,
648 base::Bind(&SyncBackendHostCore::DoOnInvalidatorStateChange,
649 core_.get(),
650 state));
653 void SyncBackendHostImpl::OnIncomingInvalidation(
654 const syncer::ObjectIdInvalidationMap& invalidation_map) {
655 registrar_->sync_thread()->message_loop()->PostTask(
656 FROM_HERE,
657 base::Bind(&SyncBackendHostCore::DoOnIncomingInvalidation,
658 core_.get(),
659 invalidation_map));
662 bool SyncBackendHostImpl::CheckPassphraseAgainstCachedPendingKeys(
663 const std::string& passphrase) const {
664 DCHECK(cached_pending_keys_.has_blob());
665 DCHECK(!passphrase.empty());
666 syncer::Nigori nigori;
667 nigori.InitByDerivation("localhost", "dummy", passphrase);
668 std::string plaintext;
669 bool result = nigori.Decrypt(cached_pending_keys_.blob(), &plaintext);
670 DVLOG_IF(1, result) << "Passphrase failed to decrypt pending keys.";
671 return result;
674 void SyncBackendHostImpl::NotifyPassphraseRequired(
675 syncer::PassphraseRequiredReason reason,
676 sync_pb::EncryptedData pending_keys) {
677 if (!frontend_)
678 return;
680 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
682 // Update our cache of the cryptographer's pending keys.
683 cached_pending_keys_ = pending_keys;
685 frontend_->OnPassphraseRequired(reason, pending_keys);
688 void SyncBackendHostImpl::NotifyPassphraseAccepted() {
689 if (!frontend_)
690 return;
692 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
694 // Clear our cache of the cryptographer's pending keys.
695 cached_pending_keys_.clear_blob();
696 frontend_->OnPassphraseAccepted();
699 void SyncBackendHostImpl::NotifyEncryptedTypesChanged(
700 syncer::ModelTypeSet encrypted_types,
701 bool encrypt_everything) {
702 if (!frontend_)
703 return;
705 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
706 frontend_->OnEncryptedTypesChanged(
707 encrypted_types, encrypt_everything);
710 void SyncBackendHostImpl::NotifyEncryptionComplete() {
711 if (!frontend_)
712 return;
714 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
715 frontend_->OnEncryptionComplete();
718 void SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop(
719 syncer::PassphraseType type,
720 base::Time explicit_passphrase_time) {
721 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
722 DVLOG(1) << "Passphrase type changed to "
723 << syncer::PassphraseTypeToString(type);
724 cached_passphrase_type_ = type;
725 cached_explicit_passphrase_time_ = explicit_passphrase_time;
728 void SyncBackendHostImpl::HandleStopSyncingPermanentlyOnFrontendLoop() {
729 if (!frontend_)
730 return;
731 frontend_->OnStopSyncingPermanently();
734 void SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop(
735 syncer::ConnectionStatus status) {
736 if (!frontend_)
737 return;
739 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
741 DVLOG(1) << "Connection status changed: "
742 << syncer::ConnectionStatusToString(status);
743 frontend_->OnConnectionStatusChange(status);
746 base::MessageLoop* SyncBackendHostImpl::GetSyncLoopForTesting() {
747 return registrar_->sync_thread()->message_loop();
750 } // namespace browser_sync
752 #undef SDVLOG
754 #undef SLOG