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_core.h"
7 #include "base/files/file_util.h"
8 #include "base/metrics/histogram.h"
9 #include "chrome/browser/sync/glue/invalidation_adapter.h"
10 #include "chrome/browser/sync/glue/local_device_info_provider_impl.h"
11 #include "chrome/browser/sync/glue/sync_backend_registrar.h"
12 #include "chrome/common/chrome_version_info.h"
13 #include "components/invalidation/invalidation_util.h"
14 #include "components/invalidation/object_id_invalidation_map.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "sync/internal_api/public/events/protocol_event.h"
17 #include "sync/internal_api/public/http_post_provider_factory.h"
18 #include "sync/internal_api/public/internal_components_factory.h"
19 #include "sync/internal_api/public/sessions/commit_counters.h"
20 #include "sync/internal_api/public/sessions/status_counters.h"
21 #include "sync/internal_api/public/sessions/sync_session_snapshot.h"
22 #include "sync/internal_api/public/sessions/update_counters.h"
23 #include "sync/internal_api/public/sync_context_proxy.h"
24 #include "sync/internal_api/public/sync_manager.h"
25 #include "sync/internal_api/public/sync_manager_factory.h"
28 // Helper macros to log with the syncer thread name; useful when there
29 // are multiple syncers involved.
31 #define SLOG(severity) LOG(severity) << name_ << ": "
33 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
35 static const int kSaveChangesIntervalSeconds
= 10;
38 class InternalComponentsFactory
;
44 enum SyncBackendInitState
{
45 SETUP_COMPLETED_FOUND_RESTORED_TYPES
= 0,
46 SETUP_COMPLETED_NO_RESTORED_TYPES
,
47 FIRST_SETUP_NO_RESTORED_TYPES
,
48 FIRST_SETUP_RESTORED_TYPES
,
49 SYNC_BACKEND_INIT_STATE_COUNT
54 namespace browser_sync
{
56 DoInitializeOptions::DoInitializeOptions(
57 base::MessageLoop
* sync_loop
,
58 SyncBackendRegistrar
* registrar
,
59 const syncer::ModelSafeRoutingInfo
& routing_info
,
60 const std::vector
<scoped_refptr
<syncer::ModelSafeWorker
> >& workers
,
61 const scoped_refptr
<syncer::ExtensionsActivity
>& extensions_activity
,
62 const syncer::WeakHandle
<syncer::JsEventHandler
>& event_handler
,
63 const GURL
& service_url
,
64 scoped_ptr
<syncer::HttpPostProviderFactory
> http_bridge_factory
,
65 const syncer::SyncCredentials
& credentials
,
66 const std::string
& invalidator_client_id
,
67 scoped_ptr
<syncer::SyncManagerFactory
> sync_manager_factory
,
68 const std::string
& restored_key_for_bootstrapping
,
69 const std::string
& restored_keystore_key_for_bootstrapping
,
70 scoped_ptr
<syncer::InternalComponentsFactory
> internal_components_factory
,
71 scoped_ptr
<syncer::UnrecoverableErrorHandler
> unrecoverable_error_handler
,
72 syncer::ReportUnrecoverableErrorFunction
73 report_unrecoverable_error_function
)
74 : sync_loop(sync_loop
),
76 routing_info(routing_info
),
78 extensions_activity(extensions_activity
),
79 event_handler(event_handler
),
80 service_url(service_url
),
81 http_bridge_factory(http_bridge_factory
.Pass()),
82 credentials(credentials
),
83 invalidator_client_id(invalidator_client_id
),
84 sync_manager_factory(sync_manager_factory
.Pass()),
85 restored_key_for_bootstrapping(restored_key_for_bootstrapping
),
86 restored_keystore_key_for_bootstrapping(
87 restored_keystore_key_for_bootstrapping
),
88 internal_components_factory(internal_components_factory
.Pass()),
89 unrecoverable_error_handler(unrecoverable_error_handler
.Pass()),
90 report_unrecoverable_error_function(report_unrecoverable_error_function
) {
93 DoInitializeOptions::~DoInitializeOptions() {}
95 DoConfigureSyncerTypes::DoConfigureSyncerTypes() {}
97 DoConfigureSyncerTypes::~DoConfigureSyncerTypes() {}
99 SyncBackendHostCore::SyncBackendHostCore(
100 const std::string
& name
,
101 const base::FilePath
& directory_path
,
102 bool has_sync_setup_completed
,
103 const base::WeakPtr
<SyncBackendHostImpl
>& backend
)
105 directory_path_(directory_path
),
109 has_sync_setup_completed_(has_sync_setup_completed
),
110 forward_protocol_events_(false),
111 forward_type_info_(false),
112 weak_ptr_factory_(this) {
113 DCHECK(backend
.get());
116 SyncBackendHostCore::~SyncBackendHostCore() {
117 DCHECK(!sync_manager_
.get());
120 void SyncBackendHostCore::Initialize(scoped_ptr
<DoInitializeOptions
> options
) {
121 content::BrowserThread::PostTask(content::BrowserThread::FILE,
122 FROM_HERE
, base::Bind(
123 &SyncBackendHostCore::CreateDirectoryAndDoInitialize
, this,
124 base::Passed(&options
)));
127 void SyncBackendHostCore::CreateDirectoryAndDoInitialize(
128 scoped_ptr
<DoInitializeOptions
> options
) {
129 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
130 if (!base::CreateDirectory(directory_path_
)) {
131 DLOG(FATAL
) << "Sync Data directory creation failed.";
133 // We need to extract the loop pointer on a separate line because on
134 // Windows the options pointer gets Passed() first.
135 base::MessageLoop
* sync_loop
= options
->sync_loop
;
136 sync_loop
->PostTask(FROM_HERE
, base::Bind(
137 &SyncBackendHostCore::DoInitialize
, this, base::Passed(&options
)));
140 void SyncBackendHostCore::OnSyncCycleCompleted(
141 const syncer::sessions::SyncSessionSnapshot
& snapshot
) {
144 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
148 &SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop
,
152 void SyncBackendHostCore::DoRefreshTypes(syncer::ModelTypeSet types
) {
153 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
154 sync_manager_
->RefreshTypes(types
);
157 void SyncBackendHostCore::OnInitializationComplete(
158 const syncer::WeakHandle
<syncer::JsBackend
>& js_backend
,
159 const syncer::WeakHandle
<syncer::DataTypeDebugInfoListener
>&
162 const syncer::ModelTypeSet restored_types
) {
163 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
166 DoDestroySyncManager(syncer::STOP_SYNC
);
167 host_
.Call(FROM_HERE
,
168 &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop
);
172 // Register for encryption related changes now. We have to do this before
173 // the initializing downloading control types or initializing the encryption
174 // handler in order to receive notifications triggered during encryption
176 sync_manager_
->GetEncryptionHandler()->AddObserver(this);
178 // Sync manager initialization is complete, so we can schedule recurring
180 sync_loop_
->PostTask(FROM_HERE
,
181 base::Bind(&SyncBackendHostCore::StartSavingChanges
,
182 weak_ptr_factory_
.GetWeakPtr()));
184 // Hang on to these for a while longer. We're not ready to hand them back to
185 // the UI thread yet.
186 js_backend_
= js_backend
;
187 debug_info_listener_
= debug_info_listener
;
189 // Track whether or not sync DB and preferences were in sync.
190 SyncBackendInitState backend_init_state
;
191 if (has_sync_setup_completed_
&& !restored_types
.Empty()) {
192 backend_init_state
= SETUP_COMPLETED_FOUND_RESTORED_TYPES
;
193 } else if (has_sync_setup_completed_
&& restored_types
.Empty()) {
194 backend_init_state
= SETUP_COMPLETED_NO_RESTORED_TYPES
;
195 } else if (!has_sync_setup_completed_
&& restored_types
.Empty()) {
196 backend_init_state
= FIRST_SETUP_NO_RESTORED_TYPES
;
197 } else { // (!has_sync_setup_completed_ && !restored_types.Empty())
198 backend_init_state
= FIRST_SETUP_RESTORED_TYPES
;
201 UMA_HISTOGRAM_ENUMERATION("Sync.BackendInitializeRestoreState",
203 SYNC_BACKEND_INIT_STATE_COUNT
);
205 // Before proceeding any further, we need to download the control types and
206 // purge any partial data (ie. data downloaded for a type that was on its way
207 // to being initially synced, but didn't quite make it.). The following
208 // configure cycle will take care of this. It depends on the registrar state
209 // which we initialize below to ensure that we don't perform any downloads if
210 // all control types have already completed their initial sync.
211 registrar_
->SetInitialTypes(restored_types
);
213 syncer::ConfigureReason reason
=
214 restored_types
.Empty() ?
215 syncer::CONFIGURE_REASON_NEW_CLIENT
:
216 syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE
;
218 syncer::ModelTypeSet new_control_types
= registrar_
->ConfigureDataTypes(
219 syncer::ControlTypes(), syncer::ModelTypeSet());
220 syncer::ModelSafeRoutingInfo routing_info
;
221 registrar_
->GetModelSafeRoutingInfo(&routing_info
);
222 SDVLOG(1) << "Control Types "
223 << syncer::ModelTypeSetToString(new_control_types
)
224 << " added; calling ConfigureSyncer";
226 syncer::ModelTypeSet types_to_purge
=
227 syncer::Difference(syncer::ModelTypeSet::All(),
228 GetRoutingInfoTypes(routing_info
));
230 sync_manager_
->ConfigureSyncer(
234 syncer::ModelTypeSet(),
235 syncer::ModelTypeSet(),
237 base::Bind(&SyncBackendHostCore::DoInitialProcessControlTypes
,
238 weak_ptr_factory_
.GetWeakPtr()),
242 void SyncBackendHostCore::OnConnectionStatusChange(
243 syncer::ConnectionStatus status
) {
246 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
249 &SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop
, status
);
252 void SyncBackendHostCore::OnPassphraseRequired(
253 syncer::PassphraseRequiredReason reason
,
254 const sync_pb::EncryptedData
& pending_keys
) {
257 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
260 &SyncBackendHostImpl::NotifyPassphraseRequired
, reason
, pending_keys
);
263 void SyncBackendHostCore::OnPassphraseAccepted() {
266 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
269 &SyncBackendHostImpl::NotifyPassphraseAccepted
);
272 void SyncBackendHostCore::OnBootstrapTokenUpdated(
273 const std::string
& bootstrap_token
,
274 syncer::BootstrapTokenType type
) {
277 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
278 host_
.Call(FROM_HERE
,
279 &SyncBackendHostImpl::PersistEncryptionBootstrapToken
,
284 void SyncBackendHostCore::OnEncryptedTypesChanged(
285 syncer::ModelTypeSet encrypted_types
,
286 bool encrypt_everything
) {
289 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
290 // NOTE: We're in a transaction.
293 &SyncBackendHostImpl::NotifyEncryptedTypesChanged
,
294 encrypted_types
, encrypt_everything
);
297 void SyncBackendHostCore::OnEncryptionComplete() {
300 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
301 // NOTE: We're in a transaction.
304 &SyncBackendHostImpl::NotifyEncryptionComplete
);
307 void SyncBackendHostCore::OnCryptographerStateChanged(
308 syncer::Cryptographer
* cryptographer
) {
312 void SyncBackendHostCore::OnPassphraseTypeChanged(
313 syncer::PassphraseType type
, base::Time passphrase_time
) {
316 &SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop
,
317 type
, passphrase_time
);
320 void SyncBackendHostCore::OnCommitCountersUpdated(
321 syncer::ModelType type
,
322 const syncer::CommitCounters
& counters
) {
325 &SyncBackendHostImpl::HandleDirectoryCommitCountersUpdatedOnFrontendLoop
,
329 void SyncBackendHostCore::OnUpdateCountersUpdated(
330 syncer::ModelType type
,
331 const syncer::UpdateCounters
& counters
) {
334 &SyncBackendHostImpl::HandleDirectoryUpdateCountersUpdatedOnFrontendLoop
,
338 void SyncBackendHostCore::OnStatusCountersUpdated(
339 syncer::ModelType type
,
340 const syncer::StatusCounters
& counters
) {
343 &SyncBackendHostImpl::HandleDirectoryStatusCountersUpdatedOnFrontendLoop
,
347 void SyncBackendHostCore::OnActionableError(
348 const syncer::SyncProtocolError
& sync_error
) {
351 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
354 &SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop
,
358 void SyncBackendHostCore::OnMigrationRequested(syncer::ModelTypeSet types
) {
359 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
362 &SyncBackendHostImpl::HandleMigrationRequestedOnFrontendLoop
,
366 void SyncBackendHostCore::OnProtocolEvent(
367 const syncer::ProtocolEvent
& event
) {
368 // TODO(rlarocque): Find a way to pass event_clone as a scoped_ptr.
369 if (forward_protocol_events_
) {
370 scoped_ptr
<syncer::ProtocolEvent
> event_clone(event
.Clone());
373 &SyncBackendHostImpl::HandleProtocolEventOnFrontendLoop
,
374 event_clone
.release());
378 void SyncBackendHostCore::DoOnInvalidatorStateChange(
379 syncer::InvalidatorState state
) {
380 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
381 sync_manager_
->SetInvalidatorEnabled(state
== syncer::INVALIDATIONS_ENABLED
);
384 void SyncBackendHostCore::DoOnIncomingInvalidation(
385 const syncer::ObjectIdInvalidationMap
& invalidation_map
) {
386 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
388 syncer::ObjectIdSet ids
= invalidation_map
.GetObjectIds();
389 for (syncer::ObjectIdSet::const_iterator ids_it
= ids
.begin();
392 syncer::ModelType type
;
393 if (!NotificationTypeToRealModelType(ids_it
->name(), &type
)) {
394 DLOG(WARNING
) << "Notification has invalid id: "
395 << syncer::ObjectIdToString(*ids_it
);
397 syncer::SingleObjectInvalidationSet invalidation_set
=
398 invalidation_map
.ForObject(*ids_it
);
399 for (syncer::SingleObjectInvalidationSet::const_iterator inv_it
=
400 invalidation_set
.begin();
401 inv_it
!= invalidation_set
.end();
403 scoped_ptr
<syncer::InvalidationInterface
> inv_adapter(
404 new InvalidationAdapter(*inv_it
));
405 sync_manager_
->OnIncomingInvalidation(type
, inv_adapter
.Pass());
411 void SyncBackendHostCore::DoInitialize(
412 scoped_ptr
<DoInitializeOptions
> options
) {
414 sync_loop_
= options
->sync_loop
;
417 // Finish initializing the HttpBridgeFactory. We do this here because
418 // building the user agent may block on some platforms.
419 chrome::VersionInfo version_info
;
420 options
->http_bridge_factory
->Init(
421 LocalDeviceInfoProviderImpl::MakeUserAgentForSyncApi(version_info
));
424 registrar_
= options
->registrar
;
427 sync_manager_
= options
->sync_manager_factory
->CreateSyncManager(name_
);
428 sync_manager_
->AddObserver(this);
430 syncer::SyncManager::InitArgs args
;
431 args
.database_location
= directory_path_
;
432 args
.event_handler
= options
->event_handler
;
433 args
.service_url
= options
->service_url
;
434 args
.post_factory
= options
->http_bridge_factory
.Pass();
435 args
.workers
= options
->workers
;
436 args
.extensions_activity
= options
->extensions_activity
.get();
437 args
.change_delegate
= options
->registrar
; // as SyncManager::ChangeDelegate
438 args
.credentials
= options
->credentials
;
439 args
.invalidator_client_id
= options
->invalidator_client_id
;
440 args
.restored_key_for_bootstrapping
= options
->restored_key_for_bootstrapping
;
441 args
.restored_keystore_key_for_bootstrapping
=
442 options
->restored_keystore_key_for_bootstrapping
;
443 args
.internal_components_factory
=
444 options
->internal_components_factory
.Pass();
445 args
.encryptor
= &encryptor_
;
446 args
.unrecoverable_error_handler
=
447 options
->unrecoverable_error_handler
.Pass();
448 args
.report_unrecoverable_error_function
=
449 options
->report_unrecoverable_error_function
;
450 args
.cancelation_signal
= &stop_syncing_signal_
;
451 sync_manager_
->Init(&args
);
454 void SyncBackendHostCore::DoUpdateCredentials(
455 const syncer::SyncCredentials
& credentials
) {
456 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
457 // UpdateCredentials can be called during backend initialization, possibly
458 // when backend initialization has failed but hasn't notified the UI thread
459 // yet. In that case, the sync manager may have been destroyed on the sync
460 // thread before this task was executed, so we do nothing.
462 sync_manager_
->UpdateCredentials(credentials
);
466 void SyncBackendHostCore::DoStartSyncing(
467 const syncer::ModelSafeRoutingInfo
& routing_info
) {
468 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
469 sync_manager_
->StartSyncingNormally(routing_info
);
472 void SyncBackendHostCore::DoSetEncryptionPassphrase(
473 const std::string
& passphrase
,
475 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
476 sync_manager_
->GetEncryptionHandler()->SetEncryptionPassphrase(
477 passphrase
, is_explicit
);
480 void SyncBackendHostCore::DoInitialProcessControlTypes() {
481 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
483 DVLOG(1) << "Initilalizing Control Types";
485 // Initialize encryption.
486 sync_manager_
->GetEncryptionHandler()->Init();
488 // Note: experiments are currently handled via SBH::AddExperimentalTypes,
489 // which is called at the end of every sync cycle.
490 // TODO(zea): eventually add an experiment handler and initialize it here.
492 if (!sync_manager_
->GetUserShare()) { // NULL in some tests.
493 DVLOG(1) << "Skipping initialization of DeviceInfo";
496 &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop
);
500 if (!sync_manager_
->InitialSyncEndedTypes().HasAll(syncer::ControlTypes())) {
501 LOG(ERROR
) << "Failed to download control types";
504 &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop
);
508 host_
.Call(FROM_HERE
,
509 &SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop
,
511 debug_info_listener_
,
512 sync_manager_
->GetSyncContextProxy(),
513 sync_manager_
->cache_guid());
516 debug_info_listener_
.Reset();
519 void SyncBackendHostCore::DoSetDecryptionPassphrase(
520 const std::string
& passphrase
) {
521 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
522 sync_manager_
->GetEncryptionHandler()->SetDecryptionPassphrase(
526 void SyncBackendHostCore::DoEnableEncryptEverything() {
527 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
528 sync_manager_
->GetEncryptionHandler()->EnableEncryptEverything();
531 void SyncBackendHostCore::ShutdownOnUIThread() {
532 // This will cut short any blocking network tasks, cut short any in-progress
533 // sync cycles, and prevent the creation of new blocking network tasks and new
534 // sync cycles. If there was an in-progress network request, it would have
535 // had a reference to the RequestContextGetter. This reference will be
536 // dropped by the time this function returns.
538 // It is safe to call this even if Sync's backend classes have not been
539 // initialized yet. Those classes will receive the message when the sync
540 // thread finally getes around to constructing them.
541 stop_syncing_signal_
.Signal();
543 // This will drop the HttpBridgeFactory's reference to the
544 // RequestContextGetter. Once this has been called, the HttpBridgeFactory can
545 // no longer be used to create new HttpBridge instances. We can get away with
546 // this because the stop_syncing_signal_ has already been signalled, which
547 // guarantees that the ServerConnectionManager will no longer attempt to
548 // create new connections.
549 release_request_context_signal_
.Signal();
552 void SyncBackendHostCore::DoShutdown(syncer::ShutdownReason reason
) {
553 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
555 DoDestroySyncManager(reason
);
560 weak_ptr_factory_
.InvalidateWeakPtrs();
563 void SyncBackendHostCore::DoDestroySyncManager(syncer::ShutdownReason reason
) {
564 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
566 DisableDirectoryTypeDebugInfoForwarding();
567 save_changes_timer_
.reset();
568 sync_manager_
->RemoveObserver(this);
569 sync_manager_
->ShutdownOnSyncThread(reason
);
570 sync_manager_
.reset();
574 void SyncBackendHostCore::DoConfigureSyncer(
575 syncer::ConfigureReason reason
,
576 const DoConfigureSyncerTypes
& config_types
,
577 const syncer::ModelSafeRoutingInfo routing_info
,
578 const base::Callback
<void(syncer::ModelTypeSet
,
579 syncer::ModelTypeSet
)>& ready_task
,
580 const base::Closure
& retry_callback
) {
581 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
582 DCHECK(!ready_task
.is_null());
583 DCHECK(!retry_callback
.is_null());
584 base::Closure
chained_ready_task(
585 base::Bind(&SyncBackendHostCore::DoFinishConfigureDataTypes
,
586 weak_ptr_factory_
.GetWeakPtr(),
587 config_types
.to_download
,
589 base::Closure
chained_retry_task(
590 base::Bind(&SyncBackendHostCore::DoRetryConfiguration
,
591 weak_ptr_factory_
.GetWeakPtr(),
593 sync_manager_
->ConfigureSyncer(reason
,
594 config_types
.to_download
,
595 config_types
.to_purge
,
596 config_types
.to_journal
,
597 config_types
.to_unapply
,
603 void SyncBackendHostCore::DoFinishConfigureDataTypes(
604 syncer::ModelTypeSet types_to_config
,
605 const base::Callback
<void(syncer::ModelTypeSet
,
606 syncer::ModelTypeSet
)>& ready_task
) {
607 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
609 // Update the enabled types for the bridge and sync manager.
610 syncer::ModelSafeRoutingInfo routing_info
;
611 registrar_
->GetModelSafeRoutingInfo(&routing_info
);
612 syncer::ModelTypeSet enabled_types
= GetRoutingInfoTypes(routing_info
);
613 enabled_types
.RemoveAll(syncer::ProxyTypes());
615 const syncer::ModelTypeSet failed_configuration_types
=
616 Difference(types_to_config
, sync_manager_
->InitialSyncEndedTypes());
617 const syncer::ModelTypeSet succeeded_configuration_types
=
618 Difference(types_to_config
, failed_configuration_types
);
619 host_
.Call(FROM_HERE
,
620 &SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop
,
622 succeeded_configuration_types
,
623 failed_configuration_types
,
627 void SyncBackendHostCore::DoRetryConfiguration(
628 const base::Closure
& retry_callback
) {
629 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
630 host_
.Call(FROM_HERE
,
631 &SyncBackendHostImpl::RetryConfigurationOnFrontendLoop
,
635 void SyncBackendHostCore::SendBufferedProtocolEventsAndEnableForwarding() {
636 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
637 forward_protocol_events_
= true;
640 // Grab our own copy of the buffered events.
641 // The buffer is not modified by this operation.
642 std::vector
<syncer::ProtocolEvent
*> buffered_events
;
643 sync_manager_
->GetBufferedProtocolEvents().release(&buffered_events
);
645 // Send them all over the fence to the host.
646 for (std::vector
<syncer::ProtocolEvent
*>::iterator it
=
647 buffered_events
.begin(); it
!= buffered_events
.end(); ++it
) {
648 // TODO(rlarocque): Make it explicit that host_ takes ownership.
651 &SyncBackendHostImpl::HandleProtocolEventOnFrontendLoop
,
657 void SyncBackendHostCore::DisableProtocolEventForwarding() {
658 forward_protocol_events_
= false;
661 void SyncBackendHostCore::EnableDirectoryTypeDebugInfoForwarding() {
662 DCHECK(sync_manager_
);
664 forward_type_info_
= true;
666 if (!sync_manager_
->HasDirectoryTypeDebugInfoObserver(this))
667 sync_manager_
->RegisterDirectoryTypeDebugInfoObserver(this);
668 sync_manager_
->RequestEmitDebugInfo();
671 void SyncBackendHostCore::DisableDirectoryTypeDebugInfoForwarding() {
672 DCHECK(sync_manager_
);
674 if (!forward_type_info_
)
677 forward_type_info_
= false;
679 if (sync_manager_
->HasDirectoryTypeDebugInfoObserver(this))
680 sync_manager_
->UnregisterDirectoryTypeDebugInfoObserver(this);
683 void SyncBackendHostCore::GetAllNodesForTypes(
684 syncer::ModelTypeSet types
,
685 scoped_refptr
<base::SequencedTaskRunner
> task_runner
,
686 base::Callback
<void(const std::vector
<syncer::ModelType
>& type
,
687 ScopedVector
<base::ListValue
>)> callback
) {
688 std::vector
<syncer::ModelType
> types_vector
;
689 ScopedVector
<base::ListValue
> node_lists
;
691 syncer::ModelSafeRoutingInfo routes
;
692 registrar_
->GetModelSafeRoutingInfo(&routes
);
693 syncer::ModelTypeSet enabled_types
= GetRoutingInfoTypes(routes
);
695 for (syncer::ModelTypeSet::Iterator it
= types
.First(); it
.Good(); it
.Inc()) {
696 types_vector
.push_back(it
.Get());
697 if (!enabled_types
.Has(it
.Get())) {
698 node_lists
.push_back(new base::ListValue());
700 node_lists
.push_back(
701 sync_manager_
->GetAllNodesForType(it
.Get()).release());
705 task_runner
->PostTask(
707 base::Bind(callback
, types_vector
, base::Passed(&node_lists
)));
710 void SyncBackendHostCore::StartSavingChanges() {
711 // We may already be shut down.
714 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
715 DCHECK(!save_changes_timer_
.get());
716 save_changes_timer_
.reset(new base::RepeatingTimer
<SyncBackendHostCore
>());
717 save_changes_timer_
->Start(FROM_HERE
,
718 base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds
),
719 this, &SyncBackendHostCore::SaveChanges
);
722 void SyncBackendHostCore::SaveChanges() {
723 DCHECK_EQ(base::MessageLoop::current(), sync_loop_
);
724 sync_manager_
->SaveChanges();
727 } // namespace browser_sync