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/location.h"
9 #include "base/logging.h"
10 #include "base/single_thread_task_runner.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/signin/chrome_signin_client_factory.h"
15 #include "chrome/browser/sync/glue/invalidation_helper.h"
16 #include "chrome/browser/sync/glue/sync_backend_host_core.h"
17 #include "chrome/browser/sync/glue/sync_backend_registrar.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "components/invalidation/public/invalidation_service.h"
20 #include "components/invalidation/public/object_id_invalidation_map.h"
21 #include "components/network_time/network_time_tracker.h"
22 #include "components/signin/core/browser/signin_client.h"
23 #include "components/sync_driver/sync_frontend.h"
24 #include "components/sync_driver/sync_prefs.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/notification_details.h"
27 #include "content/public/browser/notification_source.h"
28 #include "sync/internal_api/public/base_transaction.h"
29 #include "sync/internal_api/public/events/protocol_event.h"
30 #include "sync/internal_api/public/http_bridge.h"
31 #include "sync/internal_api/public/internal_components_factory.h"
32 #include "sync/internal_api/public/internal_components_factory_impl.h"
33 #include "sync/internal_api/public/network_resources.h"
34 #include "sync/internal_api/public/sync_manager.h"
35 #include "sync/internal_api/public/sync_manager_factory.h"
36 #include "sync/internal_api/public/util/experiments.h"
37 #include "sync/internal_api/public/util/sync_string_conversions.h"
39 // Helper macros to log with the syncer thread name; useful when there
40 // are multiple syncers involved.
42 #define SLOG(severity) LOG(severity) << name_ << ": "
44 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
46 using syncer::InternalComponentsFactory
;
48 namespace browser_sync
{
52 void UpdateNetworkTimeOnUIThread(base::Time network_time
,
53 base::TimeDelta resolution
,
54 base::TimeDelta latency
,
55 base::TimeTicks post_time
) {
56 g_browser_process
->network_time_tracker()->UpdateNetworkTime(
57 network_time
, resolution
, latency
, post_time
);
60 void UpdateNetworkTime(const base::Time
& network_time
,
61 const base::TimeDelta
& resolution
,
62 const base::TimeDelta
& latency
) {
63 content::BrowserThread::PostTask(
64 content::BrowserThread::UI
,
66 base::Bind(&UpdateNetworkTimeOnUIThread
,
67 network_time
, resolution
, latency
, base::TimeTicks::Now()));
72 SyncBackendHostImpl::SyncBackendHostImpl(
73 const std::string
& name
,
75 invalidation::InvalidationService
* invalidator
,
76 const base::WeakPtr
<sync_driver::SyncPrefs
>& sync_prefs
,
77 const base::FilePath
& sync_folder
)
78 : frontend_loop_(base::MessageLoop::current()),
82 sync_prefs_(sync_prefs
),
84 cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE
),
85 invalidator_(invalidator
),
86 invalidation_handler_registered_(false),
87 weak_ptr_factory_(this) {
88 core_
= new SyncBackendHostCore(
90 profile_
->GetPath().Append(sync_folder
),
91 sync_prefs_
->HasSyncSetupCompleted(),
92 weak_ptr_factory_
.GetWeakPtr());
95 SyncBackendHostImpl::~SyncBackendHostImpl() {
96 DCHECK(!core_
.get() && !frontend_
) << "Must call Shutdown before destructor.";
97 DCHECK(!registrar_
.get());
100 void SyncBackendHostImpl::Initialize(
101 sync_driver::SyncFrontend
* frontend
,
102 scoped_ptr
<base::Thread
> sync_thread
,
103 const syncer::WeakHandle
<syncer::JsEventHandler
>& event_handler
,
104 const GURL
& sync_service_url
,
105 const syncer::SyncCredentials
& credentials
,
106 bool delete_sync_data_folder
,
107 scoped_ptr
<syncer::SyncManagerFactory
> sync_manager_factory
,
108 scoped_ptr
<syncer::UnrecoverableErrorHandler
> unrecoverable_error_handler
,
109 const base::Closure
& report_unrecoverable_error_function
,
110 syncer::NetworkResources
* network_resources
,
111 scoped_ptr
<syncer::SyncEncryptionHandler::NigoriState
> saved_nigori_state
) {
112 registrar_
.reset(new browser_sync::SyncBackendRegistrar(name_
,
114 sync_thread
.Pass()));
115 CHECK(registrar_
->sync_thread());
117 frontend_
= frontend
;
120 syncer::ModelSafeRoutingInfo routing_info
;
121 std::vector
<scoped_refptr
<syncer::ModelSafeWorker
> > workers
;
122 registrar_
->GetModelSafeRoutingInfo(&routing_info
);
123 registrar_
->GetWorkers(&workers
);
125 InternalComponentsFactory::Switches factory_switches
= {
126 InternalComponentsFactory::ENCRYPTION_KEYSTORE
,
127 InternalComponentsFactory::BACKOFF_NORMAL
130 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
131 if (cl
->HasSwitch(switches::kSyncShortInitialRetryOverride
)) {
132 factory_switches
.backoff_override
=
133 InternalComponentsFactory::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE
;
135 if (cl
->HasSwitch(switches::kSyncEnableGetUpdateAvoidance
)) {
136 factory_switches
.pre_commit_updates_policy
=
137 InternalComponentsFactory::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE
;
139 syncer::PassphraseTransitionClearDataOption clear_data_option
=
140 syncer::PASSPHRASE_TRANSITION_DO_NOT_CLEAR_DATA
;
141 if (cl
->HasSwitch(switches::kSyncEnableClearDataOnPassphraseEncryption
))
142 clear_data_option
= syncer::PASSPHRASE_TRANSITION_CLEAR_DATA
;
144 std::map
<syncer::ModelType
, int64
> invalidation_versions
;
145 sync_prefs_
->GetInvalidationVersions(&invalidation_versions
);
147 scoped_ptr
<DoInitializeOptions
> init_opts(new DoInitializeOptions(
148 registrar_
->sync_thread()->message_loop(), registrar_
.get(), routing_info
,
149 workers
, extensions_activity_monitor_
.GetExtensionsActivity(),
150 event_handler
, sync_service_url
,
151 network_resources
->GetHttpPostProviderFactory(
152 make_scoped_refptr(profile_
->GetRequestContext()),
153 base::Bind(&UpdateNetworkTime
),
154 core_
->GetRequestContextCancelationSignal()),
155 credentials
, invalidator_
? invalidator_
->GetInvalidatorClientId() : "",
156 sync_manager_factory
.Pass(), delete_sync_data_folder
,
157 sync_prefs_
->GetEncryptionBootstrapToken(),
158 sync_prefs_
->GetKeystoreEncryptionBootstrapToken(),
159 scoped_ptr
<InternalComponentsFactory
>(
160 new syncer::InternalComponentsFactoryImpl(factory_switches
))
162 unrecoverable_error_handler
.Pass(), report_unrecoverable_error_function
,
163 saved_nigori_state
.Pass(), clear_data_option
, invalidation_versions
));
164 InitCore(init_opts
.Pass());
167 void SyncBackendHostImpl::UpdateCredentials(
168 const syncer::SyncCredentials
& credentials
) {
169 DCHECK(registrar_
->sync_thread()->IsRunning());
170 registrar_
->sync_thread()->task_runner()->PostTask(
171 FROM_HERE
, base::Bind(&SyncBackendHostCore::DoUpdateCredentials
,
172 core_
.get(), credentials
));
175 void SyncBackendHostImpl::StartSyncingWithServer() {
176 SDVLOG(1) << "SyncBackendHostImpl::StartSyncingWithServer called.";
178 syncer::ModelSafeRoutingInfo routing_info
;
179 registrar_
->GetModelSafeRoutingInfo(&routing_info
);
181 registrar_
->sync_thread()->task_runner()->PostTask(
182 FROM_HERE
, base::Bind(&SyncBackendHostCore::DoStartSyncing
, core_
.get(),
183 routing_info
, sync_prefs_
->GetLastPollTime()));
186 void SyncBackendHostImpl::SetEncryptionPassphrase(const std::string
& passphrase
,
188 DCHECK(registrar_
->sync_thread()->IsRunning());
189 if (!IsNigoriEnabled()) {
190 NOTREACHED() << "SetEncryptionPassphrase must never be called when nigori"
195 // We should never be called with an empty passphrase.
196 DCHECK(!passphrase
.empty());
198 // This should only be called by the frontend.
199 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
201 // SetEncryptionPassphrase should never be called if we are currently
202 // encrypted with an explicit passphrase.
203 DCHECK(cached_passphrase_type_
== syncer::KEYSTORE_PASSPHRASE
||
204 cached_passphrase_type_
== syncer::IMPLICIT_PASSPHRASE
);
206 // Post an encryption task on the syncer thread.
207 registrar_
->sync_thread()->task_runner()->PostTask(
208 FROM_HERE
, base::Bind(&SyncBackendHostCore::DoSetEncryptionPassphrase
,
209 core_
.get(), passphrase
, is_explicit
));
212 bool SyncBackendHostImpl::SetDecryptionPassphrase(
213 const std::string
& passphrase
) {
214 if (!IsNigoriEnabled()) {
215 NOTREACHED() << "SetDecryptionPassphrase must never be called when nigori"
220 // We should never be called with an empty passphrase.
221 DCHECK(!passphrase
.empty());
223 // This should only be called by the frontend.
224 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
226 // This should only be called when we have cached pending keys.
227 DCHECK(cached_pending_keys_
.has_blob());
229 // Check the passphrase that was provided against our local cache of the
230 // cryptographer's pending keys. If this was unsuccessful, the UI layer can
231 // immediately call OnPassphraseRequired without showing the user a spinner.
232 if (!CheckPassphraseAgainstCachedPendingKeys(passphrase
))
235 // Post a decryption task on the syncer thread.
236 registrar_
->sync_thread()->task_runner()->PostTask(
237 FROM_HERE
, base::Bind(&SyncBackendHostCore::DoSetDecryptionPassphrase
,
238 core_
.get(), passphrase
));
240 // Since we were able to decrypt the cached pending keys with the passphrase
241 // provided, we immediately alert the UI layer that the passphrase was
242 // accepted. This will avoid the situation where a user enters a passphrase,
243 // clicks OK, immediately reopens the advanced settings dialog, and gets an
244 // unnecessary prompt for a passphrase.
245 // Note: It is not guaranteed that the passphrase will be accepted by the
246 // syncer thread, since we could receive a new nigori node while the task is
247 // pending. This scenario is a valid race, and SetDecryptionPassphrase can
248 // trigger a new OnPassphraseRequired if it needs to.
249 NotifyPassphraseAccepted();
253 void SyncBackendHostImpl::StopSyncingForShutdown() {
254 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
256 // Immediately stop sending messages to the frontend.
259 // Stop listening for and forwarding locally-triggered sync refresh requests.
260 notification_registrar_
.RemoveAll();
262 // Stop non-blocking sync types from sending any more requests to the syncer.
263 sync_context_proxy_
.reset();
265 DCHECK(registrar_
->sync_thread()->IsRunning());
267 registrar_
->RequestWorkerStopOnUIThread();
269 core_
->ShutdownOnUIThread();
272 scoped_ptr
<base::Thread
> SyncBackendHostImpl::Shutdown(
273 syncer::ShutdownReason reason
) {
274 // StopSyncingForShutdown() (which nulls out |frontend_|) should be
277 DCHECK(registrar_
->sync_thread()->IsRunning());
279 bool sync_thread_claimed
= (reason
!= syncer::BROWSER_SHUTDOWN
);
281 if (invalidation_handler_registered_
) {
282 if (reason
== syncer::DISABLE_SYNC
) {
283 UnregisterInvalidationIds();
285 invalidator_
->UnregisterInvalidationHandler(this);
288 invalidation_handler_registered_
= false;
290 // Shut down and destroy sync manager.
291 registrar_
->sync_thread()->task_runner()->PostTask(
293 base::Bind(&SyncBackendHostCore::DoShutdown
, core_
.get(), reason
));
297 SyncBackendRegistrar
* detached_registrar
= registrar_
.release();
298 detached_registrar
->sync_thread()->task_runner()->PostTask(
299 FROM_HERE
, base::Bind(&SyncBackendRegistrar::Shutdown
,
300 base::Unretained(detached_registrar
)));
302 if (sync_thread_claimed
)
303 return detached_registrar
->ReleaseSyncThread();
305 return scoped_ptr
<base::Thread
>();
308 void SyncBackendHostImpl::UnregisterInvalidationIds() {
309 if (invalidation_handler_registered_
) {
310 CHECK(invalidator_
->UpdateRegisteredInvalidationIds(this,
311 syncer::ObjectIdSet()));
315 syncer::ModelTypeSet
SyncBackendHostImpl::ConfigureDataTypes(
316 syncer::ConfigureReason reason
,
317 const DataTypeConfigStateMap
& config_state_map
,
318 const base::Callback
<void(syncer::ModelTypeSet
, syncer::ModelTypeSet
)>&
320 const base::Callback
<void()>& retry_callback
) {
321 // Only one configure is allowed at a time. This is guaranteed by our
322 // callers. The SyncBackendHostImpl requests one configure as the backend is
323 // initializing and waits for it to complete. After initialization, all
324 // configurations will pass through the DataTypeManager, which is careful to
325 // never send a new configure request until the current request succeeds.
327 // The SyncBackendRegistrar's routing info will be updated by adding the
328 // types_to_add to the list then removing types_to_remove. Any types which
329 // are not in either of those sets will remain untouched.
331 // Types which were not in the list previously are not fully downloaded, so we
332 // must ask the syncer to download them. Any newly supported datatypes will
333 // not have been in that routing info list, so they will be among the types
334 // downloaded if they are enabled.
336 // The SyncBackendRegistrar's state was initially derived from the types
337 // detected to have been downloaded in the database. Afterwards it is
338 // modified only by this function. We expect it to remain in sync with the
339 // backend because configuration requests are never aborted; they are retried
340 // until they succeed or the backend is shut down.
342 syncer::ModelTypeSet disabled_types
=
343 GetDataTypesInState(DISABLED
, config_state_map
);
344 syncer::ModelTypeSet fatal_types
=
345 GetDataTypesInState(FATAL
, config_state_map
);
346 syncer::ModelTypeSet crypto_types
=
347 GetDataTypesInState(CRYPTO
, config_state_map
);
348 syncer::ModelTypeSet unready_types
=
349 GetDataTypesInState(UNREADY
, config_state_map
);
351 disabled_types
.PutAll(fatal_types
);
352 disabled_types
.PutAll(crypto_types
);
353 disabled_types
.PutAll(unready_types
);
355 syncer::ModelTypeSet active_types
=
356 GetDataTypesInState(CONFIGURE_ACTIVE
, config_state_map
);
357 syncer::ModelTypeSet clean_first_types
=
358 GetDataTypesInState(CONFIGURE_CLEAN
, config_state_map
);
359 syncer::ModelTypeSet types_to_download
= registrar_
->ConfigureDataTypes(
360 syncer::Union(active_types
, clean_first_types
),
362 types_to_download
.PutAll(clean_first_types
);
363 types_to_download
.RemoveAll(syncer::ProxyTypes());
364 if (!types_to_download
.Empty())
365 types_to_download
.Put(syncer::NIGORI
);
367 // TODO(sync): crbug.com/137550.
368 // It's dangerous to configure types that have progress markers. Types with
369 // progress markers can trigger a MIGRATION_DONE response. We are not
370 // prepared to handle a migration during a configure, so we must ensure that
371 // all our types_to_download actually contain no data before we sync them.
373 // One common way to end up in this situation used to be types which
374 // downloaded some or all of their data but have not applied it yet. We avoid
375 // problems with those types by purging the data of any such partially synced
376 // types soon after we load the directory.
378 // Another possible scenario is that we have newly supported or newly enabled
379 // data types being downloaded here but the nigori type, which is always
380 // included in any GetUpdates request, requires migration. The server has
381 // code to detect this scenario based on the configure reason, the fact that
382 // the nigori type is the only requested type which requires migration, and
383 // that the requested types list includes at least one non-nigori type. It
384 // will not send a MIGRATION_DONE response in that case. We still need to be
385 // careful to not send progress markers for non-nigori types, though. If a
386 // non-nigori type in the request requires migration, a MIGRATION_DONE
387 // response will be sent.
389 syncer::ModelSafeRoutingInfo routing_info
;
390 registrar_
->GetModelSafeRoutingInfo(&routing_info
);
392 syncer::ModelTypeSet current_types
= registrar_
->GetLastConfiguredTypes();
393 syncer::ModelTypeSet types_to_purge
=
394 syncer::Difference(syncer::ModelTypeSet::All(), current_types
);
395 syncer::ModelTypeSet inactive_types
=
396 GetDataTypesInState(CONFIGURE_INACTIVE
, config_state_map
);
397 types_to_purge
.RemoveAll(inactive_types
);
398 types_to_purge
.RemoveAll(unready_types
);
400 // If a type has already been disabled and unapplied or journaled, it will
401 // not be part of the |types_to_purge| set, and therefore does not need
402 // to be acted on again.
403 fatal_types
.RetainAll(types_to_purge
);
404 syncer::ModelTypeSet unapply_types
=
405 syncer::Union(crypto_types
, clean_first_types
);
406 unapply_types
.RetainAll(types_to_purge
);
408 DCHECK(syncer::Intersection(current_types
, fatal_types
).Empty());
409 DCHECK(syncer::Intersection(current_types
, crypto_types
).Empty());
410 DCHECK(current_types
.HasAll(types_to_download
));
412 SDVLOG(1) << "Types "
413 << syncer::ModelTypeSetToString(types_to_download
)
414 << " added; calling DoConfigureSyncer";
415 // Divide up the types into their corresponding actions (each is mutually
417 // - Types which have just been added to the routing info (types_to_download):
419 // - Types which have encountered a fatal error (fatal_types) are deleted
420 // from the directory and journaled in the delete journal.
421 // - Types which have encountered a cryptographer error (crypto_types) are
422 // unapplied (local state is purged but sync state is not).
423 // - All other types not in the routing info (types just disabled) are deleted
424 // from the directory.
425 // - Everything else (enabled types and already disabled types) is not
427 RequestConfigureSyncer(reason
,
437 DCHECK(syncer::Intersection(active_types
, types_to_purge
).Empty());
438 DCHECK(syncer::Intersection(active_types
, fatal_types
).Empty());
439 DCHECK(syncer::Intersection(active_types
, unapply_types
).Empty());
440 DCHECK(syncer::Intersection(active_types
, inactive_types
).Empty());
441 return syncer::Difference(active_types
, types_to_download
);
444 void SyncBackendHostImpl::EnableEncryptEverything() {
445 registrar_
->sync_thread()->task_runner()->PostTask(
447 base::Bind(&SyncBackendHostCore::DoEnableEncryptEverything
, core_
.get()));
450 void SyncBackendHostImpl::ActivateDataType(
451 syncer::ModelType type
, syncer::ModelSafeGroup group
,
452 sync_driver::ChangeProcessor
* change_processor
) {
453 registrar_
->ActivateDataType(type
, group
, change_processor
, GetUserShare());
456 void SyncBackendHostImpl::DeactivateDataType(syncer::ModelType type
) {
457 registrar_
->DeactivateDataType(type
);
460 syncer::UserShare
* SyncBackendHostImpl::GetUserShare() const {
461 return core_
->sync_manager()->GetUserShare();
464 scoped_ptr
<syncer_v2::SyncContextProxy
>
465 SyncBackendHostImpl::GetSyncContextProxy() {
466 return sync_context_proxy_
.get() ? scoped_ptr
<syncer_v2::SyncContextProxy
>(
467 sync_context_proxy_
->Clone())
468 : scoped_ptr
<syncer_v2::SyncContextProxy
>();
471 SyncBackendHostImpl::Status
SyncBackendHostImpl::GetDetailedStatus() {
472 DCHECK(initialized());
473 return core_
->sync_manager()->GetDetailedStatus();
476 syncer::sessions::SyncSessionSnapshot
477 SyncBackendHostImpl::GetLastSessionSnapshot() const {
478 return last_snapshot_
;
481 bool SyncBackendHostImpl::HasUnsyncedItems() const {
482 DCHECK(initialized());
483 return core_
->sync_manager()->HasUnsyncedItems();
486 bool SyncBackendHostImpl::IsNigoriEnabled() const {
487 return registrar_
.get() && registrar_
->IsNigoriEnabled();
490 syncer::PassphraseType
SyncBackendHostImpl::GetPassphraseType() const {
491 return cached_passphrase_type_
;
494 base::Time
SyncBackendHostImpl::GetExplicitPassphraseTime() const {
495 return cached_explicit_passphrase_time_
;
498 bool SyncBackendHostImpl::IsCryptographerReady(
499 const syncer::BaseTransaction
* trans
) const {
500 return initialized() && trans
->GetCryptographer() &&
501 trans
->GetCryptographer()->is_ready();
504 void SyncBackendHostImpl::GetModelSafeRoutingInfo(
505 syncer::ModelSafeRoutingInfo
* out
) const {
507 CHECK(registrar_
.get());
508 registrar_
->GetModelSafeRoutingInfo(out
);
514 void SyncBackendHostImpl::FlushDirectory() const {
515 DCHECK(initialized());
516 registrar_
->sync_thread()->message_loop()->PostTask(FROM_HERE
,
517 base::Bind(&SyncBackendHostCore::SaveChanges
, core_
));
520 void SyncBackendHostImpl::RequestBufferedProtocolEventsAndEnableForwarding() {
521 registrar_
->sync_thread()->task_runner()->PostTask(
524 &SyncBackendHostCore::SendBufferedProtocolEventsAndEnableForwarding
,
528 void SyncBackendHostImpl::DisableProtocolEventForwarding() {
529 registrar_
->sync_thread()->task_runner()->PostTask(
531 base::Bind(&SyncBackendHostCore::DisableProtocolEventForwarding
, core_
));
534 void SyncBackendHostImpl::EnableDirectoryTypeDebugInfoForwarding() {
535 DCHECK(initialized());
536 registrar_
->sync_thread()->task_runner()->PostTask(
538 base::Bind(&SyncBackendHostCore::EnableDirectoryTypeDebugInfoForwarding
,
542 void SyncBackendHostImpl::DisableDirectoryTypeDebugInfoForwarding() {
543 DCHECK(initialized());
544 registrar_
->sync_thread()->task_runner()->PostTask(
546 base::Bind(&SyncBackendHostCore::DisableDirectoryTypeDebugInfoForwarding
,
550 void SyncBackendHostImpl::GetAllNodesForTypes(
551 syncer::ModelTypeSet types
,
552 base::Callback
<void(const std::vector
<syncer::ModelType
>&,
553 ScopedVector
<base::ListValue
>)> callback
) {
554 DCHECK(initialized());
555 registrar_
->sync_thread()->task_runner()->PostTask(
556 FROM_HERE
, base::Bind(&SyncBackendHostCore::GetAllNodesForTypes
, core_
,
557 types
, frontend_loop_
->task_runner(), callback
));
560 void SyncBackendHostImpl::InitCore(scoped_ptr
<DoInitializeOptions
> options
) {
561 registrar_
->sync_thread()->task_runner()->PostTask(
562 FROM_HERE
, base::Bind(&SyncBackendHostCore::DoInitialize
, core_
.get(),
563 base::Passed(&options
)));
566 void SyncBackendHostImpl::RequestConfigureSyncer(
567 syncer::ConfigureReason reason
,
568 syncer::ModelTypeSet to_download
,
569 syncer::ModelTypeSet to_purge
,
570 syncer::ModelTypeSet to_journal
,
571 syncer::ModelTypeSet to_unapply
,
572 syncer::ModelTypeSet to_ignore
,
573 const syncer::ModelSafeRoutingInfo
& routing_info
,
574 const base::Callback
<void(syncer::ModelTypeSet
,
575 syncer::ModelTypeSet
)>& ready_task
,
576 const base::Closure
& retry_callback
) {
577 DoConfigureSyncerTypes config_types
;
578 config_types
.to_download
= to_download
;
579 config_types
.to_purge
= to_purge
;
580 config_types
.to_journal
= to_journal
;
581 config_types
.to_unapply
= to_unapply
;
582 registrar_
->sync_thread()->task_runner()->PostTask(
584 base::Bind(&SyncBackendHostCore::DoConfigureSyncer
, core_
.get(), reason
,
585 config_types
, routing_info
, ready_task
, retry_callback
));
588 void SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop(
589 const syncer::ModelTypeSet enabled_types
,
590 const syncer::ModelTypeSet succeeded_configuration_types
,
591 const syncer::ModelTypeSet failed_configuration_types
,
592 const base::Callback
<void(syncer::ModelTypeSet
,
593 syncer::ModelTypeSet
)>& ready_task
) {
598 CHECK(invalidator_
->UpdateRegisteredInvalidationIds(
599 this, ModelTypeSetToObjectIdSet(enabled_types
)));
602 if (!ready_task
.is_null())
603 ready_task
.Run(succeeded_configuration_types
, failed_configuration_types
);
606 void SyncBackendHostImpl::Observe(
608 const content::NotificationSource
& source
,
609 const content::NotificationDetails
& details
) {
610 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
611 DCHECK_EQ(type
, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL
);
613 content::Details
<const syncer::ModelTypeSet
> state_details(details
);
614 const syncer::ModelTypeSet
& types
= *(state_details
.ptr());
615 registrar_
->sync_thread()->task_runner()->PostTask(
617 base::Bind(&SyncBackendHostCore::DoRefreshTypes
, core_
.get(), types
));
620 void SyncBackendHostImpl::AddExperimentalTypes() {
621 CHECK(initialized());
622 syncer::Experiments experiments
;
623 if (core_
->sync_manager()->ReceivedExperiment(&experiments
))
624 frontend_
->OnExperimentsChanged(experiments
);
627 void SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop(
628 const syncer::WeakHandle
<syncer::JsBackend
> js_backend
,
629 const syncer::WeakHandle
<syncer::DataTypeDebugInfoListener
>
631 syncer_v2::SyncContextProxy
* sync_context_proxy
,
632 const std::string
& cache_guid
) {
633 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
635 if (sync_context_proxy
)
636 sync_context_proxy_
= sync_context_proxy
->Clone();
644 invalidator_
->RegisterInvalidationHandler(this);
645 invalidation_handler_registered_
= true;
647 // Fake a state change to initialize the SyncManager's cached invalidator
649 OnInvalidatorStateChange(invalidator_
->GetInvalidatorState());
652 // Start forwarding refresh requests to the SyncManager
653 notification_registrar_
.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL
,
654 content::Source
<Profile
>(profile_
));
656 // Now that we've downloaded the control types, we can see if there are any
657 // experimental types to enable. This should be done before we inform
658 // the frontend to ensure they're visible in the customize screen.
659 AddExperimentalTypes();
660 frontend_
->OnBackendInitialized(js_backend
,
666 void SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop() {
667 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
671 frontend_
->OnBackendInitialized(
672 syncer::WeakHandle
<syncer::JsBackend
>(),
673 syncer::WeakHandle
<syncer::DataTypeDebugInfoListener
>(),
678 void SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop(
679 const syncer::sessions::SyncSessionSnapshot
& snapshot
) {
682 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
684 last_snapshot_
= snapshot
;
686 SDVLOG(1) << "Got snapshot " << snapshot
.ToString();
688 if (!snapshot
.poll_finish_time().is_null())
689 sync_prefs_
->SetLastPollTime(snapshot
.poll_finish_time());
691 // Process any changes to the datatypes we're syncing.
692 // TODO(sync): add support for removing types.
694 AddExperimentalTypes();
697 frontend_
->OnSyncCycleCompleted();
700 void SyncBackendHostImpl::RetryConfigurationOnFrontendLoop(
701 const base::Closure
& retry_callback
) {
702 SDVLOG(1) << "Failed to complete configuration, informing of retry.";
703 retry_callback
.Run();
706 void SyncBackendHostImpl::PersistEncryptionBootstrapToken(
707 const std::string
& token
,
708 syncer::BootstrapTokenType token_type
) {
709 CHECK(sync_prefs_
.get());
710 if (token_type
== syncer::PASSPHRASE_BOOTSTRAP_TOKEN
)
711 sync_prefs_
->SetEncryptionBootstrapToken(token
);
713 sync_prefs_
->SetKeystoreEncryptionBootstrapToken(token
);
716 void SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop(
717 const syncer::SyncProtocolError
& sync_error
) {
720 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
721 frontend_
->OnActionableError(sync_error
);
724 void SyncBackendHostImpl::HandleMigrationRequestedOnFrontendLoop(
725 syncer::ModelTypeSet types
) {
728 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
729 frontend_
->OnMigrationNeededForTypes(types
);
732 void SyncBackendHostImpl::OnInvalidatorStateChange(
733 syncer::InvalidatorState state
) {
734 registrar_
->sync_thread()->task_runner()->PostTask(
735 FROM_HERE
, base::Bind(&SyncBackendHostCore::DoOnInvalidatorStateChange
,
736 core_
.get(), state
));
739 void SyncBackendHostImpl::OnIncomingInvalidation(
740 const syncer::ObjectIdInvalidationMap
& invalidation_map
) {
741 registrar_
->sync_thread()->task_runner()->PostTask(
742 FROM_HERE
, base::Bind(&SyncBackendHostCore::DoOnIncomingInvalidation
,
743 core_
.get(), invalidation_map
));
746 std::string
SyncBackendHostImpl::GetOwnerName() const {
747 return "SyncBackendHostImpl";
750 bool SyncBackendHostImpl::CheckPassphraseAgainstCachedPendingKeys(
751 const std::string
& passphrase
) const {
752 DCHECK(cached_pending_keys_
.has_blob());
753 DCHECK(!passphrase
.empty());
754 syncer::Nigori nigori
;
755 nigori
.InitByDerivation("localhost", "dummy", passphrase
);
756 std::string plaintext
;
757 bool result
= nigori
.Decrypt(cached_pending_keys_
.blob(), &plaintext
);
758 DVLOG_IF(1, result
) << "Passphrase failed to decrypt pending keys.";
762 void SyncBackendHostImpl::NotifyPassphraseRequired(
763 syncer::PassphraseRequiredReason reason
,
764 sync_pb::EncryptedData pending_keys
) {
768 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
770 // Update our cache of the cryptographer's pending keys.
771 cached_pending_keys_
= pending_keys
;
773 frontend_
->OnPassphraseRequired(reason
, pending_keys
);
776 void SyncBackendHostImpl::NotifyPassphraseAccepted() {
780 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
782 // Clear our cache of the cryptographer's pending keys.
783 cached_pending_keys_
.clear_blob();
784 frontend_
->OnPassphraseAccepted();
787 void SyncBackendHostImpl::NotifyEncryptedTypesChanged(
788 syncer::ModelTypeSet encrypted_types
,
789 bool encrypt_everything
) {
793 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
794 frontend_
->OnEncryptedTypesChanged(
795 encrypted_types
, encrypt_everything
);
798 void SyncBackendHostImpl::NotifyEncryptionComplete() {
802 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
803 frontend_
->OnEncryptionComplete();
806 void SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop(
807 syncer::PassphraseType type
,
808 base::Time explicit_passphrase_time
) {
809 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
810 DVLOG(1) << "Passphrase type changed to "
811 << syncer::PassphraseTypeToString(type
);
812 cached_passphrase_type_
= type
;
813 cached_explicit_passphrase_time_
= explicit_passphrase_time
;
816 void SyncBackendHostImpl::HandleLocalSetPassphraseEncryptionOnFrontendLoop(
817 const syncer::SyncEncryptionHandler::NigoriState
& nigori_state
) {
818 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
819 frontend_
->OnLocalSetPassphraseEncryption(nigori_state
);
822 void SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop(
823 syncer::ConnectionStatus status
) {
827 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_
);
829 DVLOG(1) << "Connection status changed: "
830 << syncer::ConnectionStatusToString(status
);
831 frontend_
->OnConnectionStatusChange(status
);
834 void SyncBackendHostImpl::HandleProtocolEventOnFrontendLoop(
835 syncer::ProtocolEvent
* event
) {
836 scoped_ptr
<syncer::ProtocolEvent
> scoped_event(event
);
839 frontend_
->OnProtocolEvent(*scoped_event
);
842 void SyncBackendHostImpl::HandleDirectoryCommitCountersUpdatedOnFrontendLoop(
843 syncer::ModelType type
,
844 const syncer::CommitCounters
& counters
) {
847 frontend_
->OnDirectoryTypeCommitCounterUpdated(type
, counters
);
850 void SyncBackendHostImpl::HandleDirectoryUpdateCountersUpdatedOnFrontendLoop(
851 syncer::ModelType type
,
852 const syncer::UpdateCounters
& counters
) {
855 frontend_
->OnDirectoryTypeUpdateCounterUpdated(type
, counters
);
858 void SyncBackendHostImpl::HandleDirectoryStatusCountersUpdatedOnFrontendLoop(
859 syncer::ModelType type
,
860 const syncer::StatusCounters
& counters
) {
863 frontend_
->OnDirectoryTypeStatusCounterUpdated(type
, counters
);
866 void SyncBackendHostImpl::UpdateInvalidationVersions(
867 const std::map
<syncer::ModelType
, int64
>& invalidation_versions
) {
868 sync_prefs_
->UpdateInvalidationVersions(invalidation_versions
);
871 base::MessageLoop
* SyncBackendHostImpl::GetSyncLoopForTesting() {
872 return registrar_
->sync_thread()->message_loop();
875 void SyncBackendHostImpl::RefreshTypesForTest(syncer::ModelTypeSet types
) {
876 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
878 registrar_
->sync_thread()->task_runner()->PostTask(
880 base::Bind(&SyncBackendHostCore::DoRefreshTypes
, core_
.get(), types
));
883 void SyncBackendHostImpl::ClearServerData(
884 const syncer::SyncManager::ClearServerDataCallback
& callback
) {
885 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
886 registrar_
->sync_thread()->task_runner()->PostTask(
887 FROM_HERE
, base::Bind(&SyncBackendHostCore::DoClearServerData
,
888 core_
.get(), callback
));
891 void SyncBackendHostImpl::ClearServerDataDoneOnFrontendLoop(
892 const syncer::SyncManager::ClearServerDataCallback
& frontend_callback
) {
893 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
894 frontend_callback
.Run();
897 } // namespace browser_sync