[Sync] Rely on directory to decide which types need to be purged
[chromium-blink-merge.git] / chrome / browser / sync / glue / sync_backend_host_impl.cc
blob1f500eec851174f63d5ab0894cc20cc67917e9db
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/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/invalidation/object_id_invalidation_map.h"
18 #include "components/network_time/network_time_tracker.h"
19 #include "components/signin/core/browser/signin_client.h"
20 #include "components/sync_driver/sync_frontend.h"
21 #include "components/sync_driver/sync_prefs.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/notification_details.h"
24 #include "content/public/browser/notification_source.h"
25 #include "sync/internal_api/public/base_transaction.h"
26 #include "sync/internal_api/public/events/protocol_event.h"
27 #include "sync/internal_api/public/http_bridge.h"
28 #include "sync/internal_api/public/internal_components_factory.h"
29 #include "sync/internal_api/public/internal_components_factory_impl.h"
30 #include "sync/internal_api/public/network_resources.h"
31 #include "sync/internal_api/public/sync_manager.h"
32 #include "sync/internal_api/public/sync_manager_factory.h"
33 #include "sync/internal_api/public/util/experiments.h"
34 #include "sync/internal_api/public/util/sync_string_conversions.h"
36 // Helper macros to log with the syncer thread name; useful when there
37 // are multiple syncers involved.
39 #define SLOG(severity) LOG(severity) << name_ << ": "
41 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
43 using syncer::InternalComponentsFactory;
45 namespace browser_sync {
47 namespace {
49 void UpdateNetworkTimeOnUIThread(base::Time network_time,
50 base::TimeDelta resolution,
51 base::TimeDelta latency,
52 base::TimeTicks post_time) {
53 g_browser_process->network_time_tracker()->UpdateNetworkTime(
54 network_time, resolution, latency, post_time);
57 void UpdateNetworkTime(const base::Time& network_time,
58 const base::TimeDelta& resolution,
59 const base::TimeDelta& latency) {
60 content::BrowserThread::PostTask(
61 content::BrowserThread::UI,
62 FROM_HERE,
63 base::Bind(&UpdateNetworkTimeOnUIThread,
64 network_time, resolution, latency, base::TimeTicks::Now()));
67 } // namespace
69 SyncBackendHostImpl::SyncBackendHostImpl(
70 const std::string& name,
71 Profile* profile,
72 invalidation::InvalidationService* invalidator,
73 const base::WeakPtr<sync_driver::SyncPrefs>& sync_prefs,
74 const base::FilePath& sync_folder)
75 : frontend_loop_(base::MessageLoop::current()),
76 profile_(profile),
77 name_(name),
78 initialized_(false),
79 sync_prefs_(sync_prefs),
80 frontend_(NULL),
81 cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE),
82 invalidator_(invalidator),
83 invalidation_handler_registered_(false),
84 weak_ptr_factory_(this) {
85 core_ = new SyncBackendHostCore(
86 name_,
87 profile_->GetPath().Append(sync_folder),
88 sync_prefs_->HasSyncSetupCompleted(),
89 weak_ptr_factory_.GetWeakPtr());
92 SyncBackendHostImpl::~SyncBackendHostImpl() {
93 DCHECK(!core_.get() && !frontend_) << "Must call Shutdown before destructor.";
94 DCHECK(!registrar_.get());
97 void SyncBackendHostImpl::Initialize(
98 SyncFrontend* frontend,
99 scoped_ptr<base::Thread> sync_thread,
100 const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
101 const GURL& sync_service_url,
102 const syncer::SyncCredentials& credentials,
103 bool delete_sync_data_folder,
104 scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
105 scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
106 syncer::ReportUnrecoverableErrorFunction
107 report_unrecoverable_error_function,
108 syncer::NetworkResources* network_resources) {
109 registrar_.reset(new browser_sync::SyncBackendRegistrar(name_,
110 profile_,
111 sync_thread.Pass()));
112 CHECK(registrar_->sync_thread());
114 frontend_ = frontend;
115 DCHECK(frontend);
117 syncer::ModelSafeRoutingInfo routing_info;
118 std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers;
119 registrar_->GetModelSafeRoutingInfo(&routing_info);
120 registrar_->GetWorkers(&workers);
122 InternalComponentsFactory::Switches factory_switches = {
123 InternalComponentsFactory::ENCRYPTION_KEYSTORE,
124 InternalComponentsFactory::BACKOFF_NORMAL
127 CommandLine* cl = CommandLine::ForCurrentProcess();
128 if (cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) {
129 factory_switches.backoff_override =
130 InternalComponentsFactory::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE;
132 if (cl->HasSwitch(switches::kSyncEnableGetUpdateAvoidance)) {
133 factory_switches.pre_commit_updates_policy =
134 InternalComponentsFactory::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE;
137 SigninClient* signin_client =
138 ChromeSigninClientFactory::GetForProfile(profile_);
139 DCHECK(signin_client);
140 std::string signin_scoped_device_id =
141 signin_client->GetSigninScopedDeviceId();
143 scoped_ptr<DoInitializeOptions> init_opts(new DoInitializeOptions(
144 registrar_->sync_thread()->message_loop(),
145 registrar_.get(),
146 routing_info,
147 workers,
148 extensions_activity_monitor_.GetExtensionsActivity(),
149 event_handler,
150 sync_service_url,
151 network_resources->GetHttpPostProviderFactory(
152 make_scoped_refptr(profile_->GetRequestContext()),
153 base::Bind(&UpdateNetworkTime),
154 core_->GetRequestContextCancelationSignal()),
155 credentials,
156 invalidator_ ? invalidator_->GetInvalidatorClientId() : "",
157 sync_manager_factory.Pass(),
158 delete_sync_data_folder,
159 sync_prefs_->GetEncryptionBootstrapToken(),
160 sync_prefs_->GetKeystoreEncryptionBootstrapToken(),
161 scoped_ptr<InternalComponentsFactory>(
162 new syncer::InternalComponentsFactoryImpl(factory_switches)).Pass(),
163 unrecoverable_error_handler.Pass(),
164 report_unrecoverable_error_function,
165 signin_scoped_device_id));
166 InitCore(init_opts.Pass());
169 void SyncBackendHostImpl::UpdateCredentials(
170 const syncer::SyncCredentials& credentials) {
171 DCHECK(registrar_->sync_thread()->IsRunning());
172 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
173 base::Bind(&SyncBackendHostCore::DoUpdateCredentials,
174 core_.get(),
175 credentials));
178 void SyncBackendHostImpl::StartSyncingWithServer() {
179 SDVLOG(1) << "SyncBackendHostImpl::StartSyncingWithServer called.";
181 syncer::ModelSafeRoutingInfo routing_info;
182 registrar_->GetModelSafeRoutingInfo(&routing_info);
184 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
185 base::Bind(&SyncBackendHostCore::DoStartSyncing,
186 core_.get(), routing_info));
189 void SyncBackendHostImpl::SetEncryptionPassphrase(const std::string& passphrase,
190 bool is_explicit) {
191 DCHECK(registrar_->sync_thread()->IsRunning());
192 if (!IsNigoriEnabled()) {
193 NOTREACHED() << "SetEncryptionPassphrase must never be called when nigori"
194 " is disabled.";
195 return;
198 // We should never be called with an empty passphrase.
199 DCHECK(!passphrase.empty());
201 // This should only be called by the frontend.
202 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
204 // SetEncryptionPassphrase should never be called if we are currently
205 // encrypted with an explicit passphrase.
206 DCHECK(cached_passphrase_type_ == syncer::KEYSTORE_PASSPHRASE ||
207 cached_passphrase_type_ == syncer::IMPLICIT_PASSPHRASE);
209 // Post an encryption task on the syncer thread.
210 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
211 base::Bind(&SyncBackendHostCore::DoSetEncryptionPassphrase,
212 core_.get(),
213 passphrase, is_explicit));
216 bool SyncBackendHostImpl::SetDecryptionPassphrase(
217 const std::string& passphrase) {
218 if (!IsNigoriEnabled()) {
219 NOTREACHED() << "SetDecryptionPassphrase must never be called when nigori"
220 " is disabled.";
221 return false;
224 // We should never be called with an empty passphrase.
225 DCHECK(!passphrase.empty());
227 // This should only be called by the frontend.
228 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
230 // This should only be called when we have cached pending keys.
231 DCHECK(cached_pending_keys_.has_blob());
233 // Check the passphrase that was provided against our local cache of the
234 // cryptographer's pending keys. If this was unsuccessful, the UI layer can
235 // immediately call OnPassphraseRequired without showing the user a spinner.
236 if (!CheckPassphraseAgainstCachedPendingKeys(passphrase))
237 return false;
239 // Post a decryption task on the syncer thread.
240 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
241 base::Bind(&SyncBackendHostCore::DoSetDecryptionPassphrase,
242 core_.get(),
243 passphrase));
245 // Since we were able to decrypt the cached pending keys with the passphrase
246 // provided, we immediately alert the UI layer that the passphrase was
247 // accepted. This will avoid the situation where a user enters a passphrase,
248 // clicks OK, immediately reopens the advanced settings dialog, and gets an
249 // unnecessary prompt for a passphrase.
250 // Note: It is not guaranteed that the passphrase will be accepted by the
251 // syncer thread, since we could receive a new nigori node while the task is
252 // pending. This scenario is a valid race, and SetDecryptionPassphrase can
253 // trigger a new OnPassphraseRequired if it needs to.
254 NotifyPassphraseAccepted();
255 return true;
258 void SyncBackendHostImpl::StopSyncingForShutdown() {
259 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
261 // Immediately stop sending messages to the frontend.
262 frontend_ = NULL;
264 // Stop listening for and forwarding locally-triggered sync refresh requests.
265 notification_registrar_.RemoveAll();
267 // Stop non-blocking sync types from sending any more requests to the syncer.
268 sync_context_proxy_.reset();
270 DCHECK(registrar_->sync_thread()->IsRunning());
272 registrar_->RequestWorkerStopOnUIThread();
274 core_->ShutdownOnUIThread();
277 scoped_ptr<base::Thread> SyncBackendHostImpl::Shutdown(ShutdownOption option) {
278 // StopSyncingForShutdown() (which nulls out |frontend_|) should be
279 // called first.
280 DCHECK(!frontend_);
281 DCHECK(registrar_->sync_thread()->IsRunning());
283 bool sync_disabled = (option == DISABLE_AND_CLAIM_THREAD);
284 bool sync_thread_claimed =
285 (option == DISABLE_AND_CLAIM_THREAD || option == STOP_AND_CLAIM_THREAD);
287 if (invalidation_handler_registered_) {
288 if (sync_disabled) {
289 UnregisterInvalidationIds();
291 invalidator_->UnregisterInvalidationHandler(this);
292 invalidator_ = NULL;
294 invalidation_handler_registered_ = false;
296 // Shut down and destroy sync manager.
297 registrar_->sync_thread()->message_loop()->PostTask(
298 FROM_HERE,
299 base::Bind(&SyncBackendHostCore::DoShutdown,
300 core_.get(), sync_disabled));
301 core_ = NULL;
303 // Worker cleanup.
304 SyncBackendRegistrar* detached_registrar = registrar_.release();
305 detached_registrar->sync_thread()->message_loop()->PostTask(
306 FROM_HERE,
307 base::Bind(&SyncBackendRegistrar::Shutdown,
308 base::Unretained(detached_registrar)));
310 if (sync_thread_claimed)
311 return detached_registrar->ReleaseSyncThread();
312 else
313 return scoped_ptr<base::Thread>();
316 void SyncBackendHostImpl::UnregisterInvalidationIds() {
317 if (invalidation_handler_registered_) {
318 invalidator_->UpdateRegisteredInvalidationIds(
319 this,
320 syncer::ObjectIdSet());
324 void SyncBackendHostImpl::ConfigureDataTypes(
325 syncer::ConfigureReason reason,
326 const DataTypeConfigStateMap& config_state_map,
327 const base::Callback<void(syncer::ModelTypeSet,
328 syncer::ModelTypeSet)>& ready_task,
329 const base::Callback<void()>& retry_callback) {
330 // Only one configure is allowed at a time. This is guaranteed by our
331 // callers. The SyncBackendHostImpl requests one configure as the backend is
332 // initializing and waits for it to complete. After initialization, all
333 // configurations will pass through the DataTypeManager, which is careful to
334 // never send a new configure request until the current request succeeds.
336 // The SyncBackendRegistrar's routing info will be updated by adding the
337 // types_to_add to the list then removing types_to_remove. Any types which
338 // are not in either of those sets will remain untouched.
340 // Types which were not in the list previously are not fully downloaded, so we
341 // must ask the syncer to download them. Any newly supported datatypes will
342 // not have been in that routing info list, so they will be among the types
343 // downloaded if they are enabled.
345 // The SyncBackendRegistrar's state was initially derived from the types
346 // detected to have been downloaded in the database. Afterwards it is
347 // modified only by this function. We expect it to remain in sync with the
348 // backend because configuration requests are never aborted; they are retried
349 // until they succeed or the backend is shut down.
351 syncer::ModelTypeSet disabled_types =
352 GetDataTypesInState(DISABLED, config_state_map);
353 syncer::ModelTypeSet fatal_types =
354 GetDataTypesInState(FATAL, config_state_map);
355 syncer::ModelTypeSet crypto_types =
356 GetDataTypesInState(CRYPTO, config_state_map);
357 syncer::ModelTypeSet unready_types =
358 GetDataTypesInState(UNREADY, config_state_map);
360 disabled_types.PutAll(fatal_types);
361 disabled_types.PutAll(crypto_types);
362 disabled_types.PutAll(unready_types);
364 syncer::ModelTypeSet active_types =
365 GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map);
366 syncer::ModelTypeSet clean_first_types =
367 GetDataTypesInState(CONFIGURE_CLEAN, config_state_map);
368 syncer::ModelTypeSet types_to_download = registrar_->ConfigureDataTypes(
369 syncer::Union(active_types, clean_first_types),
370 disabled_types);
371 types_to_download.PutAll(clean_first_types);
372 types_to_download.RemoveAll(syncer::ProxyTypes());
373 if (!types_to_download.Empty())
374 types_to_download.Put(syncer::NIGORI);
376 // TODO(sync): crbug.com/137550.
377 // It's dangerous to configure types that have progress markers. Types with
378 // progress markers can trigger a MIGRATION_DONE response. We are not
379 // prepared to handle a migration during a configure, so we must ensure that
380 // all our types_to_download actually contain no data before we sync them.
382 // One common way to end up in this situation used to be types which
383 // downloaded some or all of their data but have not applied it yet. We avoid
384 // problems with those types by purging the data of any such partially synced
385 // types soon after we load the directory.
387 // Another possible scenario is that we have newly supported or newly enabled
388 // data types being downloaded here but the nigori type, which is always
389 // included in any GetUpdates request, requires migration. The server has
390 // code to detect this scenario based on the configure reason, the fact that
391 // the nigori type is the only requested type which requires migration, and
392 // that the requested types list includes at least one non-nigori type. It
393 // will not send a MIGRATION_DONE response in that case. We still need to be
394 // careful to not send progress markers for non-nigori types, though. If a
395 // non-nigori type in the request requires migration, a MIGRATION_DONE
396 // response will be sent.
398 syncer::ModelSafeRoutingInfo routing_info;
399 registrar_->GetModelSafeRoutingInfo(&routing_info);
401 syncer::ModelTypeSet current_types = registrar_->GetLastConfiguredTypes();
402 syncer::ModelTypeSet types_to_purge =
403 syncer::Difference(syncer::ModelTypeSet::All(), current_types);
404 syncer::ModelTypeSet inactive_types =
405 GetDataTypesInState(CONFIGURE_INACTIVE, config_state_map);
406 types_to_purge.RemoveAll(inactive_types);
407 types_to_purge.RemoveAll(unready_types);
409 // If a type has already been disabled and unapplied or journaled, it will
410 // not be part of the |types_to_purge| set, and therefore does not need
411 // to be acted on again.
412 fatal_types.RetainAll(types_to_purge);
413 syncer::ModelTypeSet unapply_types =
414 syncer::Union(crypto_types, clean_first_types);
415 unapply_types.RetainAll(types_to_purge);
417 DCHECK(syncer::Intersection(current_types, fatal_types).Empty());
418 DCHECK(syncer::Intersection(current_types, crypto_types).Empty());
419 DCHECK(current_types.HasAll(types_to_download));
421 SDVLOG(1) << "Types "
422 << syncer::ModelTypeSetToString(types_to_download)
423 << " added; calling DoConfigureSyncer";
424 // Divide up the types into their corresponding actions (each is mutually
425 // exclusive):
426 // - Types which have just been added to the routing info (types_to_download):
427 // are downloaded.
428 // - Types which have encountered a fatal error (fatal_types) are deleted
429 // from the directory and journaled in the delete journal.
430 // - Types which have encountered a cryptographer error (crypto_types) are
431 // unapplied (local state is purged but sync state is not).
432 // - All other types not in the routing info (types just disabled) are deleted
433 // from the directory.
434 // - Everything else (enabled types and already disabled types) is not
435 // touched.
436 RequestConfigureSyncer(reason,
437 types_to_download,
438 types_to_purge,
439 fatal_types,
440 unapply_types,
441 inactive_types,
442 routing_info,
443 ready_task,
444 retry_callback);
447 void SyncBackendHostImpl::EnableEncryptEverything() {
448 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
449 base::Bind(&SyncBackendHostCore::DoEnableEncryptEverything,
450 core_.get()));
453 void SyncBackendHostImpl::ActivateDataType(
454 syncer::ModelType type, syncer::ModelSafeGroup group,
455 ChangeProcessor* change_processor) {
456 registrar_->ActivateDataType(type, group, change_processor, GetUserShare());
459 void SyncBackendHostImpl::DeactivateDataType(syncer::ModelType type) {
460 registrar_->DeactivateDataType(type);
463 syncer::UserShare* SyncBackendHostImpl::GetUserShare() const {
464 return core_->sync_manager()->GetUserShare();
467 scoped_ptr<syncer::SyncContextProxy>
468 SyncBackendHostImpl::GetSyncContextProxy() {
469 return sync_context_proxy_.get() ? scoped_ptr<syncer::SyncContextProxy>(
470 sync_context_proxy_->Clone())
471 : scoped_ptr<syncer::SyncContextProxy>();
474 SyncBackendHostImpl::Status SyncBackendHostImpl::GetDetailedStatus() {
475 DCHECK(initialized());
476 return core_->sync_manager()->GetDetailedStatus();
479 syncer::sessions::SyncSessionSnapshot
480 SyncBackendHostImpl::GetLastSessionSnapshot() const {
481 return last_snapshot_;
484 bool SyncBackendHostImpl::HasUnsyncedItems() const {
485 DCHECK(initialized());
486 return core_->sync_manager()->HasUnsyncedItems();
489 bool SyncBackendHostImpl::IsNigoriEnabled() const {
490 return registrar_.get() && registrar_->IsNigoriEnabled();
493 syncer::PassphraseType SyncBackendHostImpl::GetPassphraseType() const {
494 return cached_passphrase_type_;
497 base::Time SyncBackendHostImpl::GetExplicitPassphraseTime() const {
498 return cached_explicit_passphrase_time_;
501 bool SyncBackendHostImpl::IsCryptographerReady(
502 const syncer::BaseTransaction* trans) const {
503 return initialized() && trans->GetCryptographer() &&
504 trans->GetCryptographer()->is_ready();
507 void SyncBackendHostImpl::GetModelSafeRoutingInfo(
508 syncer::ModelSafeRoutingInfo* out) const {
509 if (initialized()) {
510 CHECK(registrar_.get());
511 registrar_->GetModelSafeRoutingInfo(out);
512 } else {
513 NOTREACHED();
517 SyncedDeviceTracker* SyncBackendHostImpl::GetSyncedDeviceTracker() const {
518 if (!initialized())
519 return NULL;
520 return core_->synced_device_tracker();
523 void SyncBackendHostImpl::RequestBufferedProtocolEventsAndEnableForwarding() {
524 registrar_->sync_thread()->message_loop()->PostTask(
525 FROM_HERE,
526 base::Bind(
527 &SyncBackendHostCore::SendBufferedProtocolEventsAndEnableForwarding,
528 core_));
531 void SyncBackendHostImpl::DisableProtocolEventForwarding() {
532 registrar_->sync_thread()->message_loop()->PostTask(
533 FROM_HERE,
534 base::Bind(
535 &SyncBackendHostCore::DisableProtocolEventForwarding,
536 core_));
539 void SyncBackendHostImpl::EnableDirectoryTypeDebugInfoForwarding() {
540 DCHECK(initialized());
541 registrar_->sync_thread()->message_loop()->PostTask(
542 FROM_HERE,
543 base::Bind(
544 &SyncBackendHostCore::EnableDirectoryTypeDebugInfoForwarding,
545 core_));
548 void SyncBackendHostImpl::DisableDirectoryTypeDebugInfoForwarding() {
549 DCHECK(initialized());
550 registrar_->sync_thread()->message_loop()->PostTask(
551 FROM_HERE,
552 base::Bind(
553 &SyncBackendHostCore::DisableDirectoryTypeDebugInfoForwarding,
554 core_));
557 void SyncBackendHostImpl::GetAllNodesForTypes(
558 syncer::ModelTypeSet types,
559 base::Callback<void(const std::vector<syncer::ModelType>&,
560 ScopedVector<base::ListValue>)> callback) {
561 DCHECK(initialized());
562 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
563 base::Bind(
564 &SyncBackendHostCore::GetAllNodesForTypes,
565 core_,
566 types,
567 frontend_loop_->message_loop_proxy(),
568 callback));
571 void SyncBackendHostImpl::InitCore(scoped_ptr<DoInitializeOptions> options) {
572 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
573 base::Bind(&SyncBackendHostCore::DoInitialize,
574 core_.get(), base::Passed(&options)));
577 void SyncBackendHostImpl::RequestConfigureSyncer(
578 syncer::ConfigureReason reason,
579 syncer::ModelTypeSet to_download,
580 syncer::ModelTypeSet to_purge,
581 syncer::ModelTypeSet to_journal,
582 syncer::ModelTypeSet to_unapply,
583 syncer::ModelTypeSet to_ignore,
584 const syncer::ModelSafeRoutingInfo& routing_info,
585 const base::Callback<void(syncer::ModelTypeSet,
586 syncer::ModelTypeSet)>& ready_task,
587 const base::Closure& retry_callback) {
588 DoConfigureSyncerTypes config_types;
589 config_types.to_download = to_download;
590 config_types.to_purge = to_purge;
591 config_types.to_journal = to_journal;
592 config_types.to_unapply = to_unapply;
593 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
594 base::Bind(&SyncBackendHostCore::DoConfigureSyncer,
595 core_.get(),
596 reason,
597 config_types,
598 routing_info,
599 ready_task,
600 retry_callback));
603 void SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop(
604 const syncer::ModelTypeSet enabled_types,
605 const syncer::ModelTypeSet succeeded_configuration_types,
606 const syncer::ModelTypeSet failed_configuration_types,
607 const base::Callback<void(syncer::ModelTypeSet,
608 syncer::ModelTypeSet)>& ready_task) {
609 if (!frontend_)
610 return;
612 if (invalidator_) {
613 invalidator_->UpdateRegisteredInvalidationIds(
614 this,
615 ModelTypeSetToObjectIdSet(enabled_types));
618 if (!ready_task.is_null())
619 ready_task.Run(succeeded_configuration_types, failed_configuration_types);
622 void SyncBackendHostImpl::Observe(
623 int type,
624 const content::NotificationSource& source,
625 const content::NotificationDetails& details) {
626 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
627 DCHECK_EQ(type, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL);
629 content::Details<const syncer::ModelTypeSet> state_details(details);
630 const syncer::ModelTypeSet& types = *(state_details.ptr());
631 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
632 base::Bind(&SyncBackendHostCore::DoRefreshTypes, core_.get(), types));
635 void SyncBackendHostImpl::AddExperimentalTypes() {
636 CHECK(initialized());
637 syncer::Experiments experiments;
638 if (core_->sync_manager()->ReceivedExperiment(&experiments))
639 frontend_->OnExperimentsChanged(experiments);
642 void SyncBackendHostImpl::HandleControlTypesDownloadRetry() {
643 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
644 if (!frontend_)
645 return;
647 frontend_->OnSyncConfigureRetry();
650 void SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop(
651 const syncer::WeakHandle<syncer::JsBackend> js_backend,
652 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>
653 debug_info_listener,
654 syncer::SyncContextProxy* sync_context_proxy) {
655 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
657 if (sync_context_proxy)
658 sync_context_proxy_ = sync_context_proxy->Clone();
660 if (!frontend_)
661 return;
663 initialized_ = true;
665 if (invalidator_) {
666 invalidator_->RegisterInvalidationHandler(this);
667 invalidation_handler_registered_ = true;
669 // Fake a state change to initialize the SyncManager's cached invalidator
670 // state.
671 OnInvalidatorStateChange(invalidator_->GetInvalidatorState());
674 // Start forwarding refresh requests to the SyncManager
675 notification_registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
676 content::Source<Profile>(profile_));
678 // Now that we've downloaded the control types, we can see if there are any
679 // experimental types to enable. This should be done before we inform
680 // the frontend to ensure they're visible in the customize screen.
681 AddExperimentalTypes();
682 frontend_->OnBackendInitialized(js_backend,
683 debug_info_listener,
684 true);
687 void SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop() {
688 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
689 if (!frontend_)
690 return;
692 frontend_->OnBackendInitialized(
693 syncer::WeakHandle<syncer::JsBackend>(),
694 syncer::WeakHandle<syncer::DataTypeDebugInfoListener>(),
695 false);
698 void SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop(
699 const syncer::sessions::SyncSessionSnapshot& snapshot) {
700 if (!frontend_)
701 return;
702 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
704 last_snapshot_ = snapshot;
706 SDVLOG(1) << "Got snapshot " << snapshot.ToString();
708 // Process any changes to the datatypes we're syncing.
709 // TODO(sync): add support for removing types.
710 if (initialized())
711 AddExperimentalTypes();
713 if (initialized())
714 frontend_->OnSyncCycleCompleted();
717 void SyncBackendHostImpl::RetryConfigurationOnFrontendLoop(
718 const base::Closure& retry_callback) {
719 SDVLOG(1) << "Failed to complete configuration, informing of retry.";
720 retry_callback.Run();
723 void SyncBackendHostImpl::PersistEncryptionBootstrapToken(
724 const std::string& token,
725 syncer::BootstrapTokenType token_type) {
726 CHECK(sync_prefs_.get());
727 DCHECK(!token.empty());
728 if (token_type == syncer::PASSPHRASE_BOOTSTRAP_TOKEN)
729 sync_prefs_->SetEncryptionBootstrapToken(token);
730 else
731 sync_prefs_->SetKeystoreEncryptionBootstrapToken(token);
734 void SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop(
735 const syncer::SyncProtocolError& sync_error) {
736 if (!frontend_)
737 return;
738 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
739 frontend_->OnActionableError(sync_error);
742 void SyncBackendHostImpl::HandleMigrationRequestedOnFrontendLoop(
743 syncer::ModelTypeSet types) {
744 if (!frontend_)
745 return;
746 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
747 frontend_->OnMigrationNeededForTypes(types);
750 void SyncBackendHostImpl::OnInvalidatorStateChange(
751 syncer::InvalidatorState state) {
752 registrar_->sync_thread()->message_loop()->PostTask(
753 FROM_HERE,
754 base::Bind(&SyncBackendHostCore::DoOnInvalidatorStateChange,
755 core_.get(),
756 state));
759 void SyncBackendHostImpl::OnIncomingInvalidation(
760 const syncer::ObjectIdInvalidationMap& invalidation_map) {
761 registrar_->sync_thread()->message_loop()->PostTask(
762 FROM_HERE,
763 base::Bind(&SyncBackendHostCore::DoOnIncomingInvalidation,
764 core_.get(),
765 invalidation_map));
768 std::string SyncBackendHostImpl::GetOwnerName() const {
769 return "SyncBackendHostImpl";
772 bool SyncBackendHostImpl::CheckPassphraseAgainstCachedPendingKeys(
773 const std::string& passphrase) const {
774 DCHECK(cached_pending_keys_.has_blob());
775 DCHECK(!passphrase.empty());
776 syncer::Nigori nigori;
777 nigori.InitByDerivation("localhost", "dummy", passphrase);
778 std::string plaintext;
779 bool result = nigori.Decrypt(cached_pending_keys_.blob(), &plaintext);
780 DVLOG_IF(1, result) << "Passphrase failed to decrypt pending keys.";
781 return result;
784 void SyncBackendHostImpl::NotifyPassphraseRequired(
785 syncer::PassphraseRequiredReason reason,
786 sync_pb::EncryptedData pending_keys) {
787 if (!frontend_)
788 return;
790 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
792 // Update our cache of the cryptographer's pending keys.
793 cached_pending_keys_ = pending_keys;
795 frontend_->OnPassphraseRequired(reason, pending_keys);
798 void SyncBackendHostImpl::NotifyPassphraseAccepted() {
799 if (!frontend_)
800 return;
802 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
804 // Clear our cache of the cryptographer's pending keys.
805 cached_pending_keys_.clear_blob();
806 frontend_->OnPassphraseAccepted();
809 void SyncBackendHostImpl::NotifyEncryptedTypesChanged(
810 syncer::ModelTypeSet encrypted_types,
811 bool encrypt_everything) {
812 if (!frontend_)
813 return;
815 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
816 frontend_->OnEncryptedTypesChanged(
817 encrypted_types, encrypt_everything);
820 void SyncBackendHostImpl::NotifyEncryptionComplete() {
821 if (!frontend_)
822 return;
824 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
825 frontend_->OnEncryptionComplete();
828 void SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop(
829 syncer::PassphraseType type,
830 base::Time explicit_passphrase_time) {
831 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
832 DVLOG(1) << "Passphrase type changed to "
833 << syncer::PassphraseTypeToString(type);
834 cached_passphrase_type_ = type;
835 cached_explicit_passphrase_time_ = explicit_passphrase_time;
838 void SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop(
839 syncer::ConnectionStatus status) {
840 if (!frontend_)
841 return;
843 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
845 DVLOG(1) << "Connection status changed: "
846 << syncer::ConnectionStatusToString(status);
847 frontend_->OnConnectionStatusChange(status);
850 void SyncBackendHostImpl::HandleProtocolEventOnFrontendLoop(
851 syncer::ProtocolEvent* event) {
852 scoped_ptr<syncer::ProtocolEvent> scoped_event(event);
853 if (!frontend_)
854 return;
855 frontend_->OnProtocolEvent(*scoped_event);
858 void SyncBackendHostImpl::HandleDirectoryCommitCountersUpdatedOnFrontendLoop(
859 syncer::ModelType type,
860 const syncer::CommitCounters& counters) {
861 if (!frontend_)
862 return;
863 frontend_->OnDirectoryTypeCommitCounterUpdated(type, counters);
866 void SyncBackendHostImpl::HandleDirectoryUpdateCountersUpdatedOnFrontendLoop(
867 syncer::ModelType type,
868 const syncer::UpdateCounters& counters) {
869 if (!frontend_)
870 return;
871 frontend_->OnDirectoryTypeUpdateCounterUpdated(type, counters);
874 void SyncBackendHostImpl::HandleDirectoryStatusCountersUpdatedOnFrontendLoop(
875 syncer::ModelType type,
876 const syncer::StatusCounters& counters) {
877 if (!frontend_)
878 return;
879 frontend_->OnDirectoryTypeStatusCounterUpdated(type, counters);
882 base::MessageLoop* SyncBackendHostImpl::GetSyncLoopForTesting() {
883 return registrar_->sync_thread()->message_loop();
886 } // namespace browser_sync
888 #undef SDVLOG
890 #undef SLOG