1 // Copyright (c) 2012 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/profile_sync_service.h"
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/command_line.h"
16 #include "base/compiler_specific.h"
17 #include "base/files/file_util.h"
18 #include "base/logging.h"
19 #include "base/memory/ref_counted.h"
20 #include "base/message_loop/message_loop.h"
21 #include "base/metrics/histogram.h"
22 #include "base/profiler/scoped_profile.h"
23 #include "base/strings/string16.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/threading/thread_restrictions.h"
26 #include "build/build_config.h"
27 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.h"
28 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/browsing_data/browsing_data_helper.h"
30 #include "chrome/browser/chrome_notification_types.h"
31 #include "chrome/browser/defaults.h"
32 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
33 #include "chrome/browser/net/chrome_cookie_notification_details.h"
34 #include "chrome/browser/password_manager/password_store_factory.h"
35 #include "chrome/browser/prefs/chrome_pref_service_factory.h"
36 #include "chrome/browser/prefs/pref_service_syncable.h"
37 #include "chrome/browser/profiles/profile.h"
38 #include "chrome/browser/services/gcm/gcm_profile_service.h"
39 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
40 #include "chrome/browser/signin/about_signin_internals_factory.h"
41 #include "chrome/browser/signin/chrome_signin_client_factory.h"
42 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
43 #include "chrome/browser/signin/signin_manager_factory.h"
44 #include "chrome/browser/sync/backend_migrator.h"
45 #include "chrome/browser/sync/glue/chrome_report_unrecoverable_error.h"
46 #include "chrome/browser/sync/glue/favicon_cache.h"
47 #include "chrome/browser/sync/glue/sync_backend_host.h"
48 #include "chrome/browser/sync/glue/sync_backend_host_impl.h"
49 #include "chrome/browser/sync/glue/sync_start_util.h"
50 #include "chrome/browser/sync/glue/typed_url_data_type_controller.h"
51 #include "chrome/browser/sync/profile_sync_components_factory_impl.h"
52 #include "chrome/browser/sync/sessions/notification_service_sessions_router.h"
53 #include "chrome/browser/sync/supervised_user_signin_manager_wrapper.h"
54 #include "chrome/browser/sync/sync_error_controller.h"
55 #include "chrome/browser/sync/sync_type_preference_provider.h"
56 #include "chrome/browser/ui/browser.h"
57 #include "chrome/browser/ui/browser_list.h"
58 #include "chrome/browser/ui/browser_window.h"
59 #include "chrome/browser/ui/global_error/global_error_service.h"
60 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
61 #include "chrome/common/chrome_switches.h"
62 #include "chrome/common/chrome_version_info.h"
63 #include "chrome/common/pref_names.h"
64 #include "chrome/common/url_constants.h"
65 #include "chrome/grit/generated_resources.h"
66 #include "components/gcm_driver/gcm_driver.h"
67 #include "components/invalidation/invalidation_service.h"
68 #include "components/invalidation/profile_invalidation_provider.h"
69 #include "components/password_manager/core/browser/password_store.h"
70 #include "components/pref_registry/pref_registry_syncable.h"
71 #include "components/signin/core/browser/about_signin_internals.h"
72 #include "components/signin/core/browser/profile_oauth2_token_service.h"
73 #include "components/signin/core/browser/signin_manager.h"
74 #include "components/signin/core/browser/signin_metrics.h"
75 #include "components/sync_driver/change_processor.h"
76 #include "components/sync_driver/data_type_controller.h"
77 #include "components/sync_driver/device_info.h"
78 #include "components/sync_driver/pref_names.h"
79 #include "components/sync_driver/system_encryptor.h"
80 #include "components/sync_driver/user_selectable_sync_type.h"
81 #include "content/public/browser/browser_thread.h"
82 #include "content/public/browser/notification_details.h"
83 #include "content/public/browser/notification_service.h"
84 #include "content/public/browser/notification_source.h"
85 #include "net/cookies/cookie_monster.h"
86 #include "net/url_request/url_request_context_getter.h"
87 #include "sync/api/sync_error.h"
88 #include "sync/internal_api/public/configure_reason.h"
89 #include "sync/internal_api/public/http_bridge_network_resources.h"
90 #include "sync/internal_api/public/network_resources.h"
91 #include "sync/internal_api/public/sessions/type_debug_info_observer.h"
92 #include "sync/internal_api/public/shutdown_reason.h"
93 #include "sync/internal_api/public/sync_context_proxy.h"
94 #include "sync/internal_api/public/sync_encryption_handler.h"
95 #include "sync/internal_api/public/util/experiments.h"
96 #include "sync/internal_api/public/util/sync_db_util.h"
97 #include "sync/internal_api/public/util/sync_string_conversions.h"
98 #include "sync/js/js_event_details.h"
99 #include "sync/util/cryptographer.h"
100 #include "ui/base/l10n/l10n_util.h"
101 #include "ui/base/l10n/time_format.h"
103 #if defined(OS_ANDROID)
104 #include "sync/internal_api/public/read_transaction.h"
107 using browser_sync::NotificationServiceSessionsRouter
;
108 using browser_sync::ProfileSyncServiceStartBehavior
;
109 using browser_sync::SessionsSyncManager
;
110 using browser_sync::SyncBackendHost
;
111 using sync_driver::ChangeProcessor
;
112 using sync_driver::DataTypeController
;
113 using sync_driver::DataTypeManager
;
114 using sync_driver::DataTypeStatusTable
;
115 using sync_driver::DeviceInfoSyncService
;
116 using syncer::ModelType
;
117 using syncer::ModelTypeSet
;
118 using syncer::JsBackend
;
119 using syncer::JsController
;
120 using syncer::JsEventDetails
;
121 using syncer::JsEventHandler
;
122 using syncer::ModelSafeRoutingInfo
;
123 using syncer::SyncCredentials
;
124 using syncer::SyncProtocolError
;
125 using syncer::WeakHandle
;
127 typedef GoogleServiceAuthError AuthError
;
129 const char* ProfileSyncService::kSyncServerUrl
=
130 "https://clients4.google.com/chrome-sync";
132 const char* ProfileSyncService::kDevServerUrl
=
133 "https://clients4.google.com/chrome-sync/dev";
135 const char kSyncUnrecoverableErrorHistogram
[] =
136 "Sync.UnrecoverableErrors";
138 const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy
= {
139 // Number of initial errors (in sequence) to ignore before applying
140 // exponential back-off rules.
143 // Initial delay for exponential back-off in ms.
146 // Factor by which the waiting time will be multiplied.
149 // Fuzzing percentage. ex: 10% will spread requests randomly
150 // between 90%-100% of the calculated time.
153 // Maximum amount of time we are willing to delay our request in ms.
154 // TODO(pavely): crbug.com/246686 ProfileSyncService should retry
155 // RequestAccessToken on connection state change after backoff
156 1000 * 3600 * 4, // 4 hours.
158 // Time to keep an entry from being discarded even when it
159 // has no significant state, -1 to never discard.
162 // Don't use initial delay unless the last request was an error.
166 static const base::FilePath::CharType kSyncDataFolderName
[] =
167 FILE_PATH_LITERAL("Sync Data");
169 static const base::FilePath::CharType kSyncBackupDataFolderName
[] =
170 FILE_PATH_LITERAL("Sync Data Backup");
174 void ClearBrowsingData(BrowsingDataRemover::Observer
* observer
,
178 // BrowsingDataRemover deletes itself when it's done.
179 BrowsingDataRemover
* remover
= BrowsingDataRemover::CreateForRange(
180 profile
, start
, end
);
182 remover
->AddObserver(observer
);
183 remover
->Remove(BrowsingDataRemover::REMOVE_ALL
,
184 BrowsingDataHelper::ALL
);
186 scoped_refptr
<password_manager::PasswordStore
> password
=
187 PasswordStoreFactory::GetForProfile(profile
, Profile::EXPLICIT_ACCESS
);
188 password
->RemoveLoginsSyncedBetween(start
, end
);
191 } // anonymous namespace
193 bool ShouldShowActionOnUI(
194 const syncer::SyncProtocolError
& error
) {
195 return (error
.action
!= syncer::UNKNOWN_ACTION
&&
196 error
.action
!= syncer::DISABLE_SYNC_ON_CLIENT
&&
197 error
.action
!= syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT
);
200 ProfileSyncService::ProfileSyncService(
201 scoped_ptr
<ProfileSyncComponentsFactory
> factory
,
203 scoped_ptr
<SupervisedUserSigninManagerWrapper
> signin_wrapper
,
204 ProfileOAuth2TokenService
* oauth2_token_service
,
205 ProfileSyncServiceStartBehavior start_behavior
)
206 : OAuth2TokenService::Consumer("sync"),
207 last_auth_error_(AuthError::AuthErrorNone()),
208 passphrase_required_reason_(syncer::REASON_PASSPHRASE_NOT_REQUIRED
),
209 factory_(factory
.Pass()),
211 sync_prefs_(profile_
->GetPrefs()),
212 sync_service_url_(GetSyncServiceURL(*CommandLine::ForCurrentProcess())),
213 is_first_time_sync_configure_(false),
214 backend_initialized_(false),
215 sync_disabled_by_admin_(false),
216 is_auth_in_progress_(false),
217 signin_(signin_wrapper
.Pass()),
218 unrecoverable_error_reason_(ERROR_REASON_UNSET
),
219 expect_sync_configuration_aborted_(false),
220 encrypted_types_(syncer::SyncEncryptionHandler::SensitiveTypes()),
221 encrypt_everything_(false),
222 encryption_pending_(false),
223 configure_status_(DataTypeManager::UNKNOWN
),
224 oauth2_token_service_(oauth2_token_service
),
225 request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy
),
227 startup_controller_weak_factory_(this),
228 connection_status_(syncer::CONNECTION_NOT_ATTEMPTED
),
229 last_get_token_error_(GoogleServiceAuthError::AuthErrorNone()),
230 network_resources_(new syncer::HttpBridgeNetworkResources
),
233 oauth2_token_service
,
236 base::Bind(&ProfileSyncService::StartUpSlowBackendComponents
,
237 startup_controller_weak_factory_
.GetWeakPtr(),
239 backup_rollback_controller_(
242 base::Bind(&ProfileSyncService::StartUpSlowBackendComponents
,
243 startup_controller_weak_factory_
.GetWeakPtr(),
245 base::Bind(&ProfileSyncService::StartUpSlowBackendComponents
,
246 startup_controller_weak_factory_
.GetWeakPtr(),
250 backup_finished_(false),
251 clear_browsing_data_(base::Bind(&ClearBrowsingData
)),
252 browsing_data_remover_observer_(NULL
) {
254 syncer::SyncableService::StartSyncFlare
flare(
255 sync_start_util::GetFlareForSyncableService(profile
->GetPath()));
256 scoped_ptr
<browser_sync::LocalSessionEventRouter
> router(
257 new NotificationServiceSessionsRouter(profile
, flare
));
259 DCHECK(factory_
.get());
260 local_device_
= factory_
->CreateLocalDeviceInfoProvider();
261 sessions_sync_manager_
.reset(
262 new SessionsSyncManager(profile
, local_device_
.get(), router
.Pass()));
263 device_info_sync_service_
.reset(
264 new DeviceInfoSyncService(local_device_
.get()));
267 ProfileSyncService::~ProfileSyncService() {
268 sync_prefs_
.RemoveSyncPrefObserver(this);
269 // Shutdown() should have been called before destruction.
270 CHECK(!backend_initialized_
);
273 bool ProfileSyncService::IsSyncEnabledAndLoggedIn() {
274 // Exit if sync is disabled.
275 if (IsManaged() || sync_prefs_
.IsStartSuppressed())
278 // Sync is logged in if there is a non-empty effective username.
279 return !signin_
->GetEffectiveUsername().empty();
282 bool ProfileSyncService::IsOAuthRefreshTokenAvailable() {
283 if (!oauth2_token_service_
)
286 return oauth2_token_service_
->RefreshTokenIsAvailable(
287 signin_
->GetAccountIdToUse());
290 void ProfileSyncService::Initialize() {
291 // We clear this here (vs Shutdown) because we want to remember that an error
292 // happened on shutdown so we can display details (message, location) about it
296 sync_prefs_
.AddSyncPrefObserver(this);
298 // For now, the only thing we can do through policy is to turn sync off.
304 RegisterAuthNotifications();
306 if (!HasSyncSetupCompleted() || signin_
->GetEffectiveUsername().empty()) {
307 // Clean up in case of previous crash / setup abort / signout.
311 TrySyncDatatypePrefRecovery();
313 last_synced_time_
= sync_prefs_
.GetLastSyncedTime();
315 #if defined(OS_CHROMEOS)
316 std::string bootstrap_token
= sync_prefs_
.GetEncryptionBootstrapToken();
317 if (bootstrap_token
.empty()) {
318 sync_prefs_
.SetEncryptionBootstrapToken(
319 sync_prefs_
.GetSpareBootstrapToken());
323 #if !defined(OS_ANDROID)
324 DCHECK(sync_error_controller_
== NULL
)
325 << "Initialize() called more than once.";
326 sync_error_controller_
.reset(new SyncErrorController(this));
327 AddObserver(sync_error_controller_
.get());
330 bool running_rollback
= false;
331 if (browser_sync::BackupRollbackController::IsBackupEnabled()) {
332 // Backup is needed if user's not signed in or signed in but previous
333 // backup didn't finish, i.e. backend didn't switch from backup to sync.
334 need_backup_
= signin_
->GetEffectiveUsername().empty() ||
335 sync_prefs_
.GetFirstSyncTime().is_null();
337 // Try to resume rollback if it didn't finish in last session.
338 running_rollback
= backup_rollback_controller_
.StartRollback();
340 need_backup_
= false;
343 #if defined(ENABLE_PRE_SYNC_BACKUP)
344 if (!running_rollback
&& signin_
->GetEffectiveUsername().empty()) {
348 DCHECK(!running_rollback
);
351 startup_controller_
.Reset(GetRegisteredDataTypes());
352 startup_controller_
.TryStart();
355 void ProfileSyncService::TrySyncDatatypePrefRecovery() {
356 DCHECK(!backend_initialized());
357 if (!HasSyncSetupCompleted())
360 // There was a bug where OnUserChoseDatatypes was not properly called on
361 // configuration (see crbug.com/154940). We detect this by checking whether
362 // kSyncKeepEverythingSynced has a default value. If so, and sync setup has
363 // completed, it means sync was not properly configured, so we manually
364 // set kSyncKeepEverythingSynced.
365 PrefService
* const pref_service
= profile_
->GetPrefs();
368 if (GetPreferredDataTypes().Size() > 1)
371 const PrefService::Preference
* keep_everything_synced
=
372 pref_service
->FindPreference(
373 sync_driver::prefs::kSyncKeepEverythingSynced
);
374 // This will be false if the preference was properly set or if it's controlled
376 if (!keep_everything_synced
->IsDefaultValue())
379 // kSyncKeepEverythingSynced was not properly set. Set it and the preferred
380 // types now, before we configure.
381 UMA_HISTOGRAM_COUNTS("Sync.DatatypePrefRecovery", 1);
382 sync_prefs_
.SetKeepEverythingSynced(true);
383 syncer::ModelTypeSet registered_types
= GetRegisteredDataTypes();
386 void ProfileSyncService::StartSyncingWithServer() {
388 backend_
->StartSyncingWithServer();
391 void ProfileSyncService::RegisterAuthNotifications() {
392 oauth2_token_service_
->AddObserver(this);
394 signin()->AddObserver(this);
397 void ProfileSyncService::UnregisterAuthNotifications() {
399 signin()->RemoveObserver(this);
400 oauth2_token_service_
->RemoveObserver(this);
403 void ProfileSyncService::RegisterDataTypeController(
404 DataTypeController
* data_type_controller
) {
406 directory_data_type_controllers_
.count(data_type_controller
->type()),
408 DCHECK(!GetRegisteredNonBlockingDataTypes().Has(
409 data_type_controller
->type()));
410 directory_data_type_controllers_
[data_type_controller
->type()] =
411 data_type_controller
;
414 void ProfileSyncService::RegisterNonBlockingType(syncer::ModelType type
) {
415 DCHECK_EQ(directory_data_type_controllers_
.count(type
), 0U)
416 << "Duplicate registration of type " << ModelTypeToString(type
);
418 // TODO(rlarocque): Set the enable flag properly when crbug.com/368834 is
419 // fixed and we have some way of telling whether or not this type should be
421 non_blocking_data_type_manager_
.RegisterType(type
, false);
424 void ProfileSyncService::InitializeNonBlockingType(
425 syncer::ModelType type
,
426 const scoped_refptr
<base::SequencedTaskRunner
>& task_runner
,
427 const base::WeakPtr
<syncer::ModelTypeSyncProxyImpl
>& type_sync_proxy
) {
428 non_blocking_data_type_manager_
.InitializeType(
429 type
, task_runner
, type_sync_proxy
);
432 bool ProfileSyncService::IsDataTypeControllerRunning(
433 syncer::ModelType type
) const {
434 DataTypeController::TypeMap::const_iterator iter
=
435 directory_data_type_controllers_
.find(type
);
436 if (iter
== directory_data_type_controllers_
.end()) {
439 return iter
->second
->state() == DataTypeController::RUNNING
;
442 browser_sync::OpenTabsUIDelegate
* ProfileSyncService::GetOpenTabsUIDelegate() {
443 if (!IsDataTypeControllerRunning(syncer::SESSIONS
))
445 return sessions_sync_manager_
.get();
448 browser_sync::FaviconCache
* ProfileSyncService::GetFaviconCache() {
449 return sessions_sync_manager_
->GetFaviconCache();
452 browser_sync::SyncedWindowDelegatesGetter
*
453 ProfileSyncService::GetSyncedWindowDelegatesGetter() const {
454 return sessions_sync_manager_
->GetSyncedWindowDelegatesGetter();
457 sync_driver::DeviceInfoTracker
* ProfileSyncService::GetDeviceInfoTracker()
459 if (!IsDataTypeControllerRunning(syncer::DEVICE_INFO
))
462 return device_info_sync_service_
.get();
465 sync_driver::LocalDeviceInfoProvider
*
466 ProfileSyncService::GetLocalDeviceInfoProvider() {
467 return local_device_
.get();
470 void ProfileSyncService::GetDataTypeControllerStates(
471 DataTypeController::StateMap
* state_map
) const {
472 for (DataTypeController::TypeMap::const_iterator iter
=
473 directory_data_type_controllers_
.begin();
474 iter
!= directory_data_type_controllers_
.end();
476 (*state_map
)[iter
->first
] = iter
->second
.get()->state();
479 SyncCredentials
ProfileSyncService::GetCredentials() {
480 SyncCredentials credentials
;
481 if (backend_mode_
== SYNC
) {
482 credentials
.email
= signin_
->GetEffectiveUsername();
483 DCHECK(!credentials
.email
.empty());
484 credentials
.sync_token
= access_token_
;
486 if (credentials
.sync_token
.empty())
487 credentials
.sync_token
= "credentials_lost";
489 credentials
.scope_set
.insert(signin_
->GetSyncScopeToUse());
495 bool ProfileSyncService::ShouldDeleteSyncFolder() {
496 switch (backend_mode_
) {
498 return !HasSyncSetupCompleted();
510 void ProfileSyncService::InitializeBackend(bool delete_stale_data
) {
516 SyncCredentials credentials
= GetCredentials();
518 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter(
519 profile_
->GetRequestContext());
521 if (backend_mode_
== SYNC
&& delete_stale_data
)
524 scoped_ptr
<syncer::UnrecoverableErrorHandler
>
525 backend_unrecoverable_error_handler(
526 new browser_sync::BackendUnrecoverableErrorHandler(
527 MakeWeakHandle(weak_factory_
.GetWeakPtr())));
529 backend_
->Initialize(
536 scoped_ptr
<syncer::SyncManagerFactory
>(
537 new syncer::SyncManagerFactory(GetManagerType())).Pass(),
538 backend_unrecoverable_error_handler
.Pass(),
539 &browser_sync::ChromeReportUnrecoverableError
,
540 network_resources_
.get());
543 bool ProfileSyncService::IsEncryptedDatatypeEnabled() const {
544 if (encryption_pending())
546 const syncer::ModelTypeSet preferred_types
= GetPreferredDataTypes();
547 const syncer::ModelTypeSet encrypted_types
= GetEncryptedDataTypes();
548 DCHECK(encrypted_types
.Has(syncer::PASSWORDS
));
549 return !Intersection(preferred_types
, encrypted_types
).Empty();
552 void ProfileSyncService::OnProtocolEvent(
553 const syncer::ProtocolEvent
& event
) {
554 FOR_EACH_OBSERVER(browser_sync::ProtocolEventObserver
,
555 protocol_event_observers_
,
556 OnProtocolEvent(event
));
559 void ProfileSyncService::OnDirectoryTypeCommitCounterUpdated(
560 syncer::ModelType type
,
561 const syncer::CommitCounters
& counters
) {
562 FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver
,
563 type_debug_info_observers_
,
564 OnCommitCountersUpdated(type
, counters
));
567 void ProfileSyncService::OnDirectoryTypeUpdateCounterUpdated(
568 syncer::ModelType type
,
569 const syncer::UpdateCounters
& counters
) {
570 FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver
,
571 type_debug_info_observers_
,
572 OnUpdateCountersUpdated(type
, counters
));
575 void ProfileSyncService::OnDirectoryTypeStatusCounterUpdated(
576 syncer::ModelType type
,
577 const syncer::StatusCounters
& counters
) {
578 FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver
,
579 type_debug_info_observers_
,
580 OnStatusCountersUpdated(type
, counters
));
583 void ProfileSyncService::OnDataTypeRequestsSyncStartup(
584 syncer::ModelType type
) {
585 DCHECK(syncer::UserTypes().Has(type
));
586 if (backend_
.get()) {
587 DVLOG(1) << "A data type requested sync startup, but it looks like "
588 "something else beat it to the punch.";
592 if (!GetPreferredDataTypes().Has(type
)) {
593 // We can get here as datatype SyncableServices are typically wired up
594 // to the native datatype even if sync isn't enabled.
595 DVLOG(1) << "Dropping sync startup request because type "
596 << syncer::ModelTypeToString(type
) << "not enabled.";
600 startup_controller_
.OnDataTypeRequestsSyncStartup(type
);
603 void ProfileSyncService::StartUpSlowBackendComponents(
604 ProfileSyncService::BackendMode mode
) {
605 DCHECK_NE(IDLE
, mode
);
606 if (backend_mode_
== mode
) {
610 // Backend mode transition rules:
611 // * can transit from IDLE to any other non-IDLE mode.
612 // * forbidden to transit from SYNC to any other mode, i.e. SYNC backend must
613 // be explicitly shut down before backup/rollback starts.
614 // * can not transit out of ROLLBACK mode until rollback is finished
615 // (successfully or unsuccessfully).
616 // * can not transit out of BACKUP mode until backup is finished
617 // (successfully or unsuccessfully).
618 // * if backup is needed, can only transit to SYNC if backup is finished,
620 if (backend_mode_
== SYNC
) {
621 LOG(DFATAL
) << "Shouldn't switch from mode SYNC to mode " << mode
;
625 if (backend_mode_
== ROLLBACK
||
626 (backend_mode_
== BACKUP
&& !backup_finished_
)) {
627 // Wait for rollback/backup to finish before start new backend.
631 if (mode
== SYNC
&& NeedBackup() && !backup_finished_
) {
632 if (backend_mode_
!= BACKUP
)
633 backup_rollback_controller_
.StartBackup();
637 DVLOG(1) << "Start backend mode: " << mode
;
641 ShutdownImpl(syncer::SWITCH_MODE_SYNC
);
643 ShutdownImpl(syncer::STOP_SYNC
);
646 backend_mode_
= mode
;
648 if (backend_mode_
== BACKUP
)
649 backup_start_time_
= base::Time::Now();
651 if (backend_mode_
== SYNC
&& !backup_start_time_
.is_null()) {
652 UMA_HISTOGRAM_MEDIUM_TIMES("Sync.FirstSyncDelayByBackup",
653 base::Time::Now() - backup_start_time_
);
654 backup_start_time_
= base::Time();
657 if (backend_mode_
== ROLLBACK
)
658 ClearBrowsingDataSinceFirstSync();
659 else if (backend_mode_
== SYNC
)
660 CheckSyncBackupIfNeeded();
662 base::FilePath sync_folder
= backend_mode_
== SYNC
?
663 base::FilePath(kSyncDataFolderName
) :
664 base::FilePath(kSyncBackupDataFolderName
);
666 invalidation::InvalidationService
* invalidator
= NULL
;
667 if (backend_mode_
== SYNC
) {
668 invalidation::ProfileInvalidationProvider
* provider
=
669 invalidation::ProfileInvalidationProviderFactory::GetForProfile(
672 invalidator
= provider
->GetInvalidationService();
676 factory_
->CreateSyncBackendHost(
677 profile_
->GetDebugName(),
680 sync_prefs_
.AsWeakPtr(),
683 // Initialize the backend. Every time we start up a new SyncBackendHost,
684 // we'll want to start from a fresh SyncDB, so delete any old one that might
686 InitializeBackend(ShouldDeleteSyncFolder());
688 UpdateFirstSyncTimePref();
691 void ProfileSyncService::OnGetTokenSuccess(
692 const OAuth2TokenService::Request
* request
,
693 const std::string
& access_token
,
694 const base::Time
& expiration_time
) {
695 DCHECK_EQ(access_token_request_
, request
);
696 access_token_request_
.reset();
697 access_token_
= access_token
;
698 token_receive_time_
= base::Time::Now();
699 last_get_token_error_
= GoogleServiceAuthError::AuthErrorNone();
701 if (sync_prefs_
.SyncHasAuthError()) {
702 sync_prefs_
.SetSyncAuthError(false);
703 UMA_HISTOGRAM_ENUMERATION("Sync.SyncAuthError",
708 if (HasSyncingBackend())
709 backend_
->UpdateCredentials(GetCredentials());
711 startup_controller_
.TryStart();
714 void ProfileSyncService::OnGetTokenFailure(
715 const OAuth2TokenService::Request
* request
,
716 const GoogleServiceAuthError
& error
) {
717 DCHECK_EQ(access_token_request_
, request
);
718 DCHECK_NE(error
.state(), GoogleServiceAuthError::NONE
);
719 access_token_request_
.reset();
720 last_get_token_error_
= error
;
721 switch (error
.state()) {
722 case GoogleServiceAuthError::CONNECTION_FAILED
:
723 case GoogleServiceAuthError::REQUEST_CANCELED
:
724 case GoogleServiceAuthError::SERVICE_ERROR
:
725 case GoogleServiceAuthError::SERVICE_UNAVAILABLE
: {
726 // Transient error. Retry after some time.
727 request_access_token_backoff_
.InformOfRequest(false);
728 next_token_request_time_
= base::Time::Now() +
729 request_access_token_backoff_
.GetTimeUntilRelease();
730 request_access_token_retry_timer_
.Start(
732 request_access_token_backoff_
.GetTimeUntilRelease(),
733 base::Bind(&ProfileSyncService::RequestAccessToken
,
734 weak_factory_
.GetWeakPtr()));
738 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
: {
739 if (!sync_prefs_
.SyncHasAuthError()) {
740 sync_prefs_
.SetSyncAuthError(true);
741 UMA_HISTOGRAM_ENUMERATION("Sync.SyncAuthError",
742 AUTH_ERROR_ENCOUNTERED
,
748 if (error
.state() != GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
) {
749 LOG(ERROR
) << "Unexpected persistent error: " << error
.ToString();
751 // Show error to user.
752 UpdateAuthErrorState(error
);
757 void ProfileSyncService::OnRefreshTokenAvailable(
758 const std::string
& account_id
) {
759 // TODO(vadimt): Remove ScopedProfile below once crbug.com/422460 is fixed.
760 tracked_objects::ScopedProfile
tracking_profile(
761 FROM_HERE_WITH_EXPLICIT_FUNCTION(
762 "422460 ProfileSyncService::OnRefreshTokenAvailable"));
764 if (account_id
== signin_
->GetAccountIdToUse())
765 OnRefreshTokensLoaded();
768 void ProfileSyncService::OnRefreshTokenRevoked(
769 const std::string
& account_id
) {
770 if (!IsOAuthRefreshTokenAvailable()) {
771 access_token_
.clear();
772 // The additional check around IsOAuthRefreshTokenAvailable() above
773 // prevents us sounding the alarm if we actually have a valid token but
774 // a refresh attempt failed for any variety of reasons
775 // (e.g. flaky network). It's possible the token we do have is also
776 // invalid, but in that case we should already have (or can expect) an
777 // auth error sent from the sync backend.
778 UpdateAuthErrorState(
779 GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED
));
783 void ProfileSyncService::OnRefreshTokensLoaded() {
784 // This notification gets fired when OAuth2TokenService loads the tokens
786 // Initialize the backend if sync is enabled. If the sync token was
787 // not loaded, GetCredentials() will generate invalid credentials to
788 // cause the backend to generate an auth error (crbug.com/121755).
789 if (HasSyncingBackend()) {
790 RequestAccessToken();
792 startup_controller_
.TryStart();
796 void ProfileSyncService::Shutdown() {
797 UnregisterAuthNotifications();
799 ShutdownImpl(syncer::BROWSER_SHUTDOWN
);
800 if (sync_error_controller_
) {
801 // Destroy the SyncErrorController when the service shuts down for good.
802 RemoveObserver(sync_error_controller_
.get());
803 sync_error_controller_
.reset();
807 sync_thread_
->Stop();
810 void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason
) {
814 non_blocking_data_type_manager_
.DisconnectSyncBackend();
816 // First, we spin down the backend to stop change processing as soon as
818 base::Time shutdown_start_time
= base::Time::Now();
819 backend_
->StopSyncingForShutdown();
821 // Stop all data type controllers, if needed. Note that until Stop
822 // completes, it is possible in theory to have a ChangeProcessor apply a
823 // change from a native model. In that case, it will get applied to the sync
824 // database (which doesn't get destroyed until we destroy the backend below)
825 // as an unsynced change. That will be persisted, and committed on restart.
826 if (directory_data_type_manager_
) {
827 if (directory_data_type_manager_
->state() != DataTypeManager::STOPPED
) {
828 // When aborting as part of shutdown, we should expect an aborted sync
829 // configure result, else we'll dcheck when we try to read the sync error.
830 expect_sync_configuration_aborted_
= true;
831 directory_data_type_manager_
->Stop();
833 directory_data_type_manager_
.reset();
836 // Shutdown the migrator before the backend to ensure it doesn't pull a null
839 sync_js_controller_
.AttachJsBackend(WeakHandle
<syncer::JsBackend
>());
841 // Move aside the backend so nobody else tries to use it while we are
843 scoped_ptr
<SyncBackendHost
> doomed_backend(backend_
.release());
844 if (doomed_backend
) {
845 sync_thread_
= doomed_backend
->Shutdown(reason
);
846 doomed_backend
.reset();
848 base::TimeDelta shutdown_time
= base::Time::Now() - shutdown_start_time
;
849 UMA_HISTOGRAM_TIMES("Sync.Shutdown.BackendDestroyedTime", shutdown_time
);
851 weak_factory_
.InvalidateWeakPtrs();
853 if (backend_mode_
== SYNC
)
854 startup_controller_
.Reset(GetRegisteredDataTypes());
856 // Don't let backup block sync regardless backup succeeded or not.
857 if (backend_mode_
== BACKUP
)
858 backup_finished_
= true;
860 // Sync could be blocked by rollback/backup. Post task to check whether sync
861 // should start after shutting down rollback/backup backend.
862 if ((backend_mode_
== ROLLBACK
|| backend_mode_
== BACKUP
) &&
863 reason
!= syncer::SWITCH_MODE_SYNC
&&
864 reason
!= syncer::BROWSER_SHUTDOWN
) {
865 base::MessageLoop::current()->PostTask(
866 FROM_HERE
, base::Bind(&ProfileSyncService::TryStartSyncAfterBackup
,
867 startup_controller_weak_factory_
.GetWeakPtr()));
870 // Clear various flags.
871 backend_mode_
= IDLE
;
872 expect_sync_configuration_aborted_
= false;
873 is_auth_in_progress_
= false;
874 backend_initialized_
= false;
875 cached_passphrase_
.clear();
876 access_token_
.clear();
877 encryption_pending_
= false;
878 encrypt_everything_
= false;
879 encrypted_types_
= syncer::SyncEncryptionHandler::SensitiveTypes();
880 passphrase_required_reason_
= syncer::REASON_PASSPHRASE_NOT_REQUIRED
;
881 request_access_token_retry_timer_
.Stop();
882 // Revert to "no auth error".
883 if (last_auth_error_
.state() != GoogleServiceAuthError::NONE
)
884 UpdateAuthErrorState(GoogleServiceAuthError::AuthErrorNone());
889 void ProfileSyncService::DisableForUser() {
890 // Clear prefs (including SyncSetupHasCompleted) before shutting down so
891 // PSS clients don't think we're set up while we're shutting down.
892 sync_prefs_
.ClearPreferences();
893 ClearUnrecoverableError();
894 ShutdownImpl(syncer::DISABLE_SYNC
);
897 bool ProfileSyncService::HasSyncSetupCompleted() const {
898 return sync_prefs_
.HasSyncSetupCompleted();
901 void ProfileSyncService::SetSyncSetupCompleted() {
902 sync_prefs_
.SetSyncSetupCompleted();
905 void ProfileSyncService::UpdateLastSyncedTime() {
906 last_synced_time_
= base::Time::Now();
907 sync_prefs_
.SetLastSyncedTime(last_synced_time_
);
910 void ProfileSyncService::NotifyObservers() {
911 FOR_EACH_OBSERVER(ProfileSyncServiceBase::Observer
, observers_
,
915 void ProfileSyncService::NotifySyncCycleCompleted() {
916 FOR_EACH_OBSERVER(ProfileSyncServiceBase::Observer
, observers_
,
917 OnSyncCycleCompleted());
920 void ProfileSyncService::ClearStaleErrors() {
921 ClearUnrecoverableError();
922 last_actionable_error_
= SyncProtocolError();
923 // Clear the data type errors as well.
924 if (directory_data_type_manager_
.get())
925 directory_data_type_manager_
->ResetDataTypeErrors();
929 void ProfileSyncService::ClearUnrecoverableError() {
930 unrecoverable_error_reason_
= ERROR_REASON_UNSET
;
931 unrecoverable_error_message_
.clear();
932 unrecoverable_error_location_
= tracked_objects::Location();
935 void ProfileSyncService::RegisterNewDataType(syncer::ModelType data_type
) {
936 if (directory_data_type_controllers_
.count(data_type
) > 0)
941 // An invariant has been violated. Transition to an error state where we try
942 // to do as little work as possible, to avoid further corruption or crashes.
943 void ProfileSyncService::OnUnrecoverableError(
944 const tracked_objects::Location
& from_here
,
945 const std::string
& message
) {
946 // Unrecoverable errors that arrive via the syncer::UnrecoverableErrorHandler
947 // interface are assumed to originate within the syncer.
948 unrecoverable_error_reason_
= ERROR_REASON_SYNCER
;
949 OnUnrecoverableErrorImpl(from_here
, message
, true);
952 void ProfileSyncService::OnUnrecoverableErrorImpl(
953 const tracked_objects::Location
& from_here
,
954 const std::string
& message
,
955 bool delete_sync_database
) {
956 DCHECK(HasUnrecoverableError());
957 unrecoverable_error_message_
= message
;
958 unrecoverable_error_location_
= from_here
;
960 UMA_HISTOGRAM_ENUMERATION(kSyncUnrecoverableErrorHistogram
,
961 unrecoverable_error_reason_
,
963 std::string location
;
964 from_here
.Write(true, true, &location
);
966 << "Unrecoverable error detected at " << location
967 << " -- ProfileSyncService unusable: " << message
;
969 // Shut all data types down.
970 base::MessageLoop::current()->PostTask(FROM_HERE
,
971 base::Bind(&ProfileSyncService::ShutdownImpl
,
972 weak_factory_
.GetWeakPtr(),
973 delete_sync_database
?
974 syncer::DISABLE_SYNC
: syncer::STOP_SYNC
));
977 void ProfileSyncService::ReenableDatatype(syncer::ModelType type
) {
978 DCHECK(backend_initialized_
);
979 directory_data_type_manager_
->ReenableType(type
);
982 void ProfileSyncService::UpdateBackendInitUMA(bool success
) {
983 if (backend_mode_
!= SYNC
)
986 is_first_time_sync_configure_
= !HasSyncSetupCompleted();
988 if (is_first_time_sync_configure_
) {
989 UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeFirstTimeSuccess", success
);
991 UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeRestoreSuccess", success
);
994 base::Time on_backend_initialized_time
= base::Time::Now();
995 base::TimeDelta delta
= on_backend_initialized_time
-
996 startup_controller_
.start_backend_time();
997 if (is_first_time_sync_configure_
) {
998 UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeFirstTime", delta
);
1000 UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeRestoreTime", delta
);
1004 void ProfileSyncService::PostBackendInitialization() {
1005 // Never get here for backup / restore.
1006 DCHECK_EQ(backend_mode_
, SYNC
);
1008 if (last_backup_time_
) {
1009 DCHECK(device_info_sync_service_
);
1010 device_info_sync_service_
->UpdateLocalDeviceBackupTime(*last_backup_time_
);
1013 if (protocol_event_observers_
.might_have_observers()) {
1014 backend_
->RequestBufferedProtocolEventsAndEnableForwarding();
1017 non_blocking_data_type_manager_
.ConnectSyncBackend(
1018 backend_
->GetSyncContextProxy());
1020 if (type_debug_info_observers_
.might_have_observers()) {
1021 backend_
->EnableDirectoryTypeDebugInfoForwarding();
1024 // If we have a cached passphrase use it to decrypt/encrypt data now that the
1025 // backend is initialized. We want to call this before notifying observers in
1026 // case this operation affects the "passphrase required" status.
1027 ConsumeCachedPassphraseIfPossible();
1029 // The very first time the backend initializes is effectively the first time
1030 // we can say we successfully "synced". last_synced_time_ will only be null
1031 // in this case, because the pref wasn't restored on StartUp.
1032 if (last_synced_time_
.is_null()) {
1033 UpdateLastSyncedTime();
1036 if (startup_controller_
.auto_start_enabled() && !FirstSetupInProgress()) {
1037 // Backend is initialized but we're not in sync setup, so this must be an
1038 // autostart - mark our sync setup as completed and we'll start syncing
1040 SetSyncSetupCompleted();
1043 // Check HasSyncSetupCompleted() before NotifyObservers() to avoid spurious
1044 // data type configuration because observer may flag setup as complete and
1045 // trigger data type configuration.
1046 if (HasSyncSetupCompleted()) {
1047 ConfigureDataTypeManager();
1049 DCHECK(FirstSetupInProgress());
1055 void ProfileSyncService::OnBackendInitialized(
1056 const syncer::WeakHandle
<syncer::JsBackend
>& js_backend
,
1057 const syncer::WeakHandle
<syncer::DataTypeDebugInfoListener
>&
1058 debug_info_listener
,
1059 const std::string
& cache_guid
,
1061 UpdateBackendInitUMA(success
);
1064 // Something went unexpectedly wrong. Play it safe: stop syncing at once
1065 // and surface error UI to alert the user sync has stopped.
1066 // Keep the directory around for now so that on restart we will retry
1067 // again and potentially succeed in presence of transient file IO failures
1068 // or permissions issues, etc.
1070 // TODO(rlarocque): Consider making this UnrecoverableError less special.
1071 // Unlike every other UnrecoverableError, it does not delete our sync data.
1072 // This exception made sense at the time it was implemented, but our new
1073 // directory corruption recovery mechanism makes it obsolete. By the time
1074 // we get here, we will have already tried and failed to delete the
1075 // directory. It would be no big deal if we tried to delete it again.
1076 OnInternalUnrecoverableError(FROM_HERE
,
1077 "BackendInitialize failure",
1079 ERROR_REASON_BACKEND_INIT_FAILURE
);
1083 backend_initialized_
= true;
1085 sync_js_controller_
.AttachJsBackend(js_backend
);
1086 debug_info_listener_
= debug_info_listener
;
1088 SigninClient
* signin_client
=
1089 ChromeSigninClientFactory::GetForProfile(profile_
);
1090 DCHECK(signin_client
);
1091 std::string signin_scoped_device_id
=
1092 signin_client
->GetSigninScopedDeviceId();
1094 // Initialize local device info.
1095 local_device_
->Initialize(cache_guid
, signin_scoped_device_id
);
1097 DVLOG(1) << "Setting preferred types for non-blocking DTM";
1098 non_blocking_data_type_manager_
.SetPreferredTypes(GetPreferredDataTypes());
1100 // Give the DataTypeControllers a handle to the now initialized backend
1102 for (DataTypeController::TypeMap::iterator it
=
1103 directory_data_type_controllers_
.begin();
1104 it
!= directory_data_type_controllers_
.end(); ++it
) {
1105 it
->second
->OnUserShareReady(GetUserShare());
1108 if (backend_mode_
== BACKUP
|| backend_mode_
== ROLLBACK
)
1109 ConfigureDataTypeManager();
1111 PostBackendInitialization();
1114 void ProfileSyncService::OnSyncCycleCompleted() {
1115 UpdateLastSyncedTime();
1116 if (IsDataTypeControllerRunning(syncer::SESSIONS
)) {
1117 // Trigger garbage collection of old sessions now that we've downloaded
1118 // any new session data.
1119 base::MessageLoop::current()->PostTask(FROM_HERE
, base::Bind(
1120 &SessionsSyncManager::DoGarbageCollection
,
1121 base::AsWeakPtr(sessions_sync_manager_
.get())));
1123 DVLOG(2) << "Notifying observers sync cycle completed";
1124 NotifySyncCycleCompleted();
1127 void ProfileSyncService::OnExperimentsChanged(
1128 const syncer::Experiments
& experiments
) {
1129 if (current_experiments_
.Matches(experiments
))
1132 current_experiments_
= experiments
;
1134 // Handle preference-backed experiments first.
1135 if (experiments
.gcm_channel_state
== syncer::Experiments::SUPPRESSED
) {
1136 profile()->GetPrefs()->SetBoolean(prefs::kGCMChannelEnabled
, false);
1137 gcm::GCMProfileServiceFactory::GetForProfile(profile())->driver()
1140 profile()->GetPrefs()->ClearPref(prefs::kGCMChannelEnabled
);
1141 gcm::GCMProfileServiceFactory::GetForProfile(profile())->driver()
1145 profile()->GetPrefs()->SetBoolean(prefs::kInvalidationServiceUseGCMChannel
,
1146 experiments
.gcm_invalidations_enabled
);
1148 if (experiments
.enhanced_bookmarks_enabled
) {
1149 profile_
->GetPrefs()->SetString(
1150 sync_driver::prefs::kEnhancedBookmarksExtensionId
,
1151 experiments
.enhanced_bookmarks_ext_id
);
1153 profile_
->GetPrefs()->ClearPref(
1154 sync_driver::prefs::kEnhancedBookmarksExtensionId
);
1156 UpdateBookmarksExperimentState(
1157 profile_
->GetPrefs(), g_browser_process
->local_state(), true,
1158 experiments
.enhanced_bookmarks_enabled
? BOOKMARKS_EXPERIMENT_ENABLED
:
1159 BOOKMARKS_EXPERIMENT_NONE
);
1161 // If this is a first time sync for a client, this will be called before
1162 // OnBackendInitialized() to ensure the new datatypes are available at sync
1163 // setup. As a result, the migrator won't exist yet. This is fine because for
1164 // first time sync cases we're only concerned with making the datatype
1166 if (migrator_
.get() &&
1167 migrator_
->state() != browser_sync::BackendMigrator::IDLE
) {
1168 DVLOG(1) << "Dropping OnExperimentsChanged due to migrator busy.";
1172 const syncer::ModelTypeSet registered_types
= GetRegisteredDataTypes();
1173 syncer::ModelTypeSet to_add
;
1174 const syncer::ModelTypeSet to_register
=
1175 Difference(to_add
, registered_types
);
1176 DVLOG(2) << "OnExperimentsChanged called with types: "
1177 << syncer::ModelTypeSetToString(to_add
);
1178 DVLOG(2) << "Enabling types: " << syncer::ModelTypeSetToString(to_register
);
1180 for (syncer::ModelTypeSet::Iterator it
= to_register
.First();
1181 it
.Good(); it
.Inc()) {
1182 // Received notice to enable experimental type. Check if the type is
1183 // registered, and if not register a new datatype controller.
1184 RegisterNewDataType(it
.Get());
1187 // Check if the user has "Keep Everything Synced" enabled. If so, we want
1188 // to turn on all experimental types if they're not already on. Otherwise we
1190 // Note: if any types are already registered, we don't turn them on. This
1191 // covers the case where we're already in the process of reconfiguring
1192 // to turn an experimental type on.
1193 if (sync_prefs_
.HasKeepEverythingSynced()) {
1194 // Mark all data types as preferred.
1195 sync_prefs_
.SetPreferredDataTypes(registered_types
, registered_types
);
1197 // Only automatically turn on types if we have already finished set up.
1198 // Otherwise, just leave the experimental types on by default.
1199 if (!to_register
.Empty() && HasSyncSetupCompleted() && migrator_
) {
1200 DVLOG(1) << "Dynamically enabling new datatypes: "
1201 << syncer::ModelTypeSetToString(to_register
);
1202 OnMigrationNeededForTypes(to_register
);
1207 void ProfileSyncService::UpdateAuthErrorState(const AuthError
& error
) {
1208 is_auth_in_progress_
= false;
1209 last_auth_error_
= error
;
1216 AuthError
ConnectionStatusToAuthError(
1217 syncer::ConnectionStatus status
) {
1219 case syncer::CONNECTION_OK
:
1220 return AuthError::AuthErrorNone();
1222 case syncer::CONNECTION_AUTH_ERROR
:
1223 return AuthError(AuthError::INVALID_GAIA_CREDENTIALS
);
1225 case syncer::CONNECTION_SERVER_ERROR
:
1226 return AuthError(AuthError::CONNECTION_FAILED
);
1230 return AuthError(AuthError::CONNECTION_FAILED
);
1236 void ProfileSyncService::OnConnectionStatusChange(
1237 syncer::ConnectionStatus status
) {
1238 connection_status_update_time_
= base::Time::Now();
1239 connection_status_
= status
;
1240 if (status
== syncer::CONNECTION_AUTH_ERROR
) {
1241 // Sync server returned error indicating that access token is invalid. It
1242 // could be either expired or access is revoked. Let's request another
1243 // access token and if access is revoked then request for token will fail
1244 // with corresponding error. If access token is repeatedly reported
1245 // invalid, there may be some issues with server, e.g. authentication
1246 // state is inconsistent on sync and token server. In that case, we
1247 // backoff token requests exponentially to avoid hammering token server
1248 // too much and to avoid getting same token due to token server's caching
1249 // policy. |request_access_token_retry_timer_| is used to backoff request
1250 // triggered by both auth error and failure talking to GAIA server.
1251 // Therefore, we're likely to reach the backoff ceiling more quickly than
1252 // you would expect from looking at the BackoffPolicy if both types of
1253 // errors happen. We shouldn't receive two errors back-to-back without
1254 // attempting a token/sync request in between, thus crank up request delay
1255 // unnecessary. This is because we won't make a sync request if we hit an
1256 // error until GAIA succeeds at sending a new token, and we won't request
1257 // a new token unless sync reports a token failure. But to be safe, don't
1258 // schedule request if this happens.
1259 if (request_access_token_retry_timer_
.IsRunning()) {
1261 } else if (request_access_token_backoff_
.failure_count() == 0) {
1262 // First time request without delay. Currently invalid token is used
1263 // to initialize sync backend and we'll always end up here. We don't
1264 // want to delay initialization.
1265 request_access_token_backoff_
.InformOfRequest(false);
1266 RequestAccessToken();
1268 request_access_token_backoff_
.InformOfRequest(false);
1269 request_access_token_retry_timer_
.Start(
1271 request_access_token_backoff_
.GetTimeUntilRelease(),
1272 base::Bind(&ProfileSyncService::RequestAccessToken
,
1273 weak_factory_
.GetWeakPtr()));
1276 // Reset backoff time after successful connection.
1277 if (status
== syncer::CONNECTION_OK
) {
1278 // Request shouldn't be scheduled at this time. But if it is, it's
1279 // possible that sync flips between OK and auth error states rapidly,
1280 // thus hammers token server. To be safe, only reset backoff delay when
1281 // no scheduled request.
1282 if (request_access_token_retry_timer_
.IsRunning()) {
1285 request_access_token_backoff_
.Reset();
1289 const GoogleServiceAuthError auth_error
=
1290 ConnectionStatusToAuthError(status
);
1291 DVLOG(1) << "Connection status change: " << auth_error
.ToString();
1292 UpdateAuthErrorState(auth_error
);
1296 void ProfileSyncService::StopSyncingPermanently() {
1297 sync_prefs_
.SetStartSuppressed(true);
1301 void ProfileSyncService::OnPassphraseRequired(
1302 syncer::PassphraseRequiredReason reason
,
1303 const sync_pb::EncryptedData
& pending_keys
) {
1304 DCHECK(backend_
.get());
1305 DCHECK(backend_
->IsNigoriEnabled());
1307 // TODO(lipalani) : add this check to other locations as well.
1308 if (HasUnrecoverableError()) {
1309 // When unrecoverable error is detected we post a task to shutdown the
1310 // backend. The task might not have executed yet.
1314 DVLOG(1) << "Passphrase required with reason: "
1315 << syncer::PassphraseRequiredReasonToString(reason
);
1316 passphrase_required_reason_
= reason
;
1318 const syncer::ModelTypeSet types
= GetPreferredDirectoryDataTypes();
1319 if (directory_data_type_manager_
) {
1320 // Reconfigure without the encrypted types (excluded implicitly via the
1321 // failed datatypes handler).
1322 directory_data_type_manager_
->Configure(types
,
1323 syncer::CONFIGURE_REASON_CRYPTO
);
1326 // TODO(rlarocque): Support non-blocking types. http://crbug.com/351005.
1328 // Notify observers that the passphrase status may have changed.
1332 void ProfileSyncService::OnPassphraseAccepted() {
1333 DVLOG(1) << "Received OnPassphraseAccepted.";
1335 // If the pending keys were resolved via keystore, it's possible we never
1336 // consumed our cached passphrase. Clear it now.
1337 if (!cached_passphrase_
.empty())
1338 cached_passphrase_
.clear();
1340 // Reset passphrase_required_reason_ since we know we no longer require the
1341 // passphrase. We do this here rather than down in ResolvePassphraseRequired()
1342 // because that can be called by OnPassphraseRequired() if no encrypted data
1343 // types are enabled, and we don't want to clobber the true passphrase error.
1344 passphrase_required_reason_
= syncer::REASON_PASSPHRASE_NOT_REQUIRED
;
1346 // Make sure the data types that depend on the passphrase are started at
1348 const syncer::ModelTypeSet types
= GetPreferredDirectoryDataTypes();
1349 if (directory_data_type_manager_
) {
1350 // Re-enable any encrypted types if necessary.
1351 directory_data_type_manager_
->Configure(types
,
1352 syncer::CONFIGURE_REASON_CRYPTO
);
1355 // TODO(rlarocque): Support non-blocking types. http://crbug.com/351005.
1360 void ProfileSyncService::OnEncryptedTypesChanged(
1361 syncer::ModelTypeSet encrypted_types
,
1362 bool encrypt_everything
) {
1363 encrypted_types_
= encrypted_types
;
1364 encrypt_everything_
= encrypt_everything
;
1365 DVLOG(1) << "Encrypted types changed to "
1366 << syncer::ModelTypeSetToString(encrypted_types_
)
1367 << " (encrypt everything is set to "
1368 << (encrypt_everything_
? "true" : "false") << ")";
1369 DCHECK(encrypted_types_
.Has(syncer::PASSWORDS
));
1374 void ProfileSyncService::OnEncryptionComplete() {
1375 DVLOG(1) << "Encryption complete";
1376 if (encryption_pending_
&& encrypt_everything_
) {
1377 encryption_pending_
= false;
1378 // This is to nudge the integration tests when encryption is
1384 void ProfileSyncService::OnMigrationNeededForTypes(
1385 syncer::ModelTypeSet types
) {
1386 DCHECK(backend_initialized_
);
1387 DCHECK(directory_data_type_manager_
.get());
1389 // Migrator must be valid, because we don't sync until it is created and this
1390 // callback originates from a sync cycle.
1391 migrator_
->MigrateTypes(types
);
1394 void ProfileSyncService::OnActionableError(const SyncProtocolError
& error
) {
1395 last_actionable_error_
= error
;
1396 DCHECK_NE(last_actionable_error_
.action
,
1397 syncer::UNKNOWN_ACTION
);
1398 switch (error
.action
) {
1399 case syncer::UPGRADE_CLIENT
:
1400 case syncer::CLEAR_USER_DATA_AND_RESYNC
:
1401 case syncer::ENABLE_SYNC_ON_ACCOUNT
:
1402 case syncer::STOP_AND_RESTART_SYNC
:
1403 // TODO(lipalani) : if setup in progress we want to display these
1404 // actions in the popup. The current experience might not be optimal for
1405 // the user. We just dismiss the dialog.
1406 if (startup_controller_
.setup_in_progress()) {
1407 StopSyncingPermanently();
1408 expect_sync_configuration_aborted_
= true;
1410 // Trigger an unrecoverable error to stop syncing.
1411 OnInternalUnrecoverableError(FROM_HERE
,
1412 last_actionable_error_
.error_description
,
1414 ERROR_REASON_ACTIONABLE_ERROR
);
1416 case syncer::DISABLE_SYNC_AND_ROLLBACK
:
1417 backup_rollback_controller_
.OnRollbackReceived();
1418 // Fall through to shutdown backend and sign user out.
1419 case syncer::DISABLE_SYNC_ON_CLIENT
:
1420 StopSyncingPermanently();
1421 #if !defined(OS_CHROMEOS)
1422 // On desktop Chrome, sign out the user after a dashboard clear.
1423 // Skip sign out on ChromeOS/Android.
1424 if (!startup_controller_
.auto_start_enabled()) {
1425 SigninManagerFactory::GetForProfile(profile_
)->SignOut(
1426 signin_metrics::SERVER_FORCED_DISABLE
);
1430 case syncer::ROLLBACK_DONE
:
1431 backup_rollback_controller_
.OnRollbackDone();
1433 case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT
:
1434 // Sync disabled by domain admin. we should stop syncing until next
1436 sync_disabled_by_admin_
= true;
1437 ShutdownImpl(syncer::DISABLE_SYNC
);
1444 if (error
.action
== syncer::DISABLE_SYNC_ON_CLIENT
||
1445 (error
.action
== syncer::DISABLE_SYNC_AND_ROLLBACK
&&
1446 !backup_rollback_controller_
.StartRollback())) {
1447 // Clean up backup data for sign-out only or when rollback is disabled.
1449 } else if (error
.action
== syncer::ROLLBACK_DONE
) {
1450 // Shut down ROLLBACK backend and delete backup DB.
1451 ShutdownImpl(syncer::DISABLE_SYNC
);
1452 sync_prefs_
.ClearFirstSyncTime();
1456 void ProfileSyncService::OnConfigureDone(
1457 const DataTypeManager::ConfigureResult
& result
) {
1458 configure_status_
= result
.status
;
1459 data_type_status_table_
= result
.data_type_status_table
;
1461 if (backend_mode_
!= SYNC
) {
1462 if (configure_status_
== DataTypeManager::OK
) {
1463 StartSyncingWithServer();
1465 // Backup is done after models are associated.
1466 if (backend_mode_
== BACKUP
)
1467 backup_finished_
= true;
1469 // Asynchronously check whether sync needs to start.
1470 base::MessageLoop::current()->PostTask(
1471 FROM_HERE
, base::Bind(&ProfileSyncService::TryStartSyncAfterBackup
,
1472 startup_controller_weak_factory_
.GetWeakPtr()));
1473 } else if (!expect_sync_configuration_aborted_
) {
1474 DVLOG(1) << "Backup/rollback backend failed to configure.";
1475 ShutdownImpl(syncer::STOP_SYNC
);
1481 // We should have cleared our cached passphrase before we get here (in
1482 // OnBackendInitialized()).
1483 DCHECK(cached_passphrase_
.empty());
1485 if (!sync_configure_start_time_
.is_null()) {
1486 if (result
.status
== DataTypeManager::OK
) {
1487 base::Time sync_configure_stop_time
= base::Time::Now();
1488 base::TimeDelta delta
= sync_configure_stop_time
-
1489 sync_configure_start_time_
;
1490 if (is_first_time_sync_configure_
) {
1491 UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceInitialConfigureTime", delta
);
1493 UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceSubsequentConfigureTime",
1497 sync_configure_start_time_
= base::Time();
1500 // Notify listeners that configuration is done.
1501 content::NotificationService::current()->Notify(
1502 chrome::NOTIFICATION_SYNC_CONFIGURE_DONE
,
1503 content::Source
<ProfileSyncService
>(this),
1504 content::NotificationService::NoDetails());
1506 DVLOG(1) << "PSS OnConfigureDone called with status: " << configure_status_
;
1507 // The possible status values:
1508 // ABORT - Configuration was aborted. This is not an error, if
1509 // initiated by user.
1510 // OK - Some or all types succeeded.
1511 // Everything else is an UnrecoverableError. So treat it as such.
1513 // First handle the abort case.
1514 if (configure_status_
== DataTypeManager::ABORTED
&&
1515 expect_sync_configuration_aborted_
) {
1516 DVLOG(0) << "ProfileSyncService::Observe Sync Configure aborted";
1517 expect_sync_configuration_aborted_
= false;
1521 // Handle unrecoverable error.
1522 if (configure_status_
!= DataTypeManager::OK
) {
1523 // Something catastrophic had happened. We should only have one
1524 // error representing it.
1525 syncer::SyncError error
=
1526 data_type_status_table_
.GetUnrecoverableError();
1527 DCHECK(error
.IsSet());
1528 std::string message
=
1529 "Sync configuration failed with status " +
1530 DataTypeManager::ConfigureStatusToString(configure_status_
) +
1532 syncer::ModelTypeSetToString(
1533 data_type_status_table_
.GetUnrecoverableErrorTypes()) +
1534 ": " + error
.message();
1535 LOG(ERROR
) << "ProfileSyncService error: " << message
;
1536 OnInternalUnrecoverableError(error
.location(),
1539 ERROR_REASON_CONFIGURATION_FAILURE
);
1543 // We should never get in a state where we have no encrypted datatypes
1544 // enabled, and yet we still think we require a passphrase for decryption.
1545 DCHECK(!(IsPassphraseRequiredForDecryption() &&
1546 !IsEncryptedDatatypeEnabled()));
1548 // This must be done before we start syncing with the server to avoid
1549 // sending unencrypted data up on a first time sync.
1550 if (encryption_pending_
)
1551 backend_
->EnableEncryptEverything();
1554 if (migrator_
.get() &&
1555 migrator_
->state() != browser_sync::BackendMigrator::IDLE
) {
1556 // Migration in progress. Let the migrator know we just finished
1557 // configuring something. It will be up to the migrator to call
1558 // StartSyncingWithServer() if migration is now finished.
1559 migrator_
->OnConfigureDone(result
);
1561 StartSyncingWithServer();
1565 void ProfileSyncService::OnConfigureStart() {
1566 sync_configure_start_time_
= base::Time::Now();
1570 ProfileSyncService::SyncStatusSummary
1571 ProfileSyncService::QuerySyncStatusSummary() {
1572 if (HasUnrecoverableError()) {
1573 return UNRECOVERABLE_ERROR
;
1574 } else if (!backend_
) {
1576 } else if (backend_mode_
== BACKUP
) {
1577 return BACKUP_USER_DATA
;
1578 } else if (backend_mode_
== ROLLBACK
) {
1579 return ROLLBACK_USER_DATA
;
1580 } else if (backend_
.get() && !HasSyncSetupCompleted()) {
1581 return SETUP_INCOMPLETE
;
1583 backend_
.get() && HasSyncSetupCompleted() &&
1584 directory_data_type_manager_
.get() &&
1585 directory_data_type_manager_
->state() == DataTypeManager::STOPPED
) {
1586 return DATATYPES_NOT_INITIALIZED
;
1587 } else if (SyncActive()) {
1590 return UNKNOWN_ERROR
;
1593 std::string
ProfileSyncService::QuerySyncStatusSummaryString() {
1594 SyncStatusSummary status
= QuerySyncStatusSummary();
1596 std::string config_status_str
=
1597 configure_status_
!= DataTypeManager::UNKNOWN
?
1598 DataTypeManager::ConfigureStatusToString(configure_status_
) : "";
1601 case UNRECOVERABLE_ERROR
:
1602 return "Unrecoverable error detected";
1604 return "Syncing not enabled";
1605 case SETUP_INCOMPLETE
:
1606 return "First time sync setup incomplete";
1607 case DATATYPES_NOT_INITIALIZED
:
1608 return "Datatypes not fully initialized";
1610 return "Sync service initialized";
1611 case BACKUP_USER_DATA
:
1612 return "Backing-up user data. Status: " + config_status_str
;
1613 case ROLLBACK_USER_DATA
:
1614 return "Restoring user data. Status: " + config_status_str
;
1616 return "Status unknown: Internal error?";
1620 std::string
ProfileSyncService::GetBackendInitializationStateString() const {
1621 return startup_controller_
.GetBackendInitializationStateString();
1624 bool ProfileSyncService::auto_start_enabled() const {
1625 return startup_controller_
.auto_start_enabled();
1628 bool ProfileSyncService::setup_in_progress() const {
1629 return startup_controller_
.setup_in_progress();
1632 bool ProfileSyncService::QueryDetailedSyncStatus(
1633 SyncBackendHost::Status
* result
) {
1634 if (backend_
.get() && backend_initialized_
) {
1635 *result
= backend_
->GetDetailedStatus();
1638 SyncBackendHost::Status status
;
1639 status
.sync_protocol_error
= last_actionable_error_
;
1645 const AuthError
& ProfileSyncService::GetAuthError() const {
1646 return last_auth_error_
;
1649 bool ProfileSyncService::FirstSetupInProgress() const {
1650 return !HasSyncSetupCompleted() && startup_controller_
.setup_in_progress();
1653 void ProfileSyncService::SetSetupInProgress(bool setup_in_progress
) {
1654 // This method is a no-op if |setup_in_progress_| remains unchanged.
1655 if (startup_controller_
.setup_in_progress() == setup_in_progress
)
1658 startup_controller_
.set_setup_in_progress(setup_in_progress
);
1659 if (!setup_in_progress
&& backend_initialized())
1660 ReconfigureDatatypeManager();
1664 bool ProfileSyncService::SyncActive() const {
1665 return backend_initialized_
&& backend_mode_
== SYNC
&&
1666 directory_data_type_manager_
&&
1667 directory_data_type_manager_
->state() != DataTypeManager::STOPPED
;
1670 bool ProfileSyncService::backend_initialized() const {
1671 return backend_initialized_
;
1674 ProfileSyncService::BackendMode
ProfileSyncService::backend_mode() const {
1675 return backend_mode_
;
1678 bool ProfileSyncService::ConfigurationDone() const {
1679 return directory_data_type_manager_
&&
1680 directory_data_type_manager_
->state() == DataTypeManager::CONFIGURED
;
1683 bool ProfileSyncService::waiting_for_auth() const {
1684 return is_auth_in_progress_
;
1687 const syncer::Experiments
& ProfileSyncService::current_experiments() const {
1688 return current_experiments_
;
1691 bool ProfileSyncService::HasUnrecoverableError() const {
1692 return unrecoverable_error_reason_
!= ERROR_REASON_UNSET
;
1695 bool ProfileSyncService::IsPassphraseRequired() const {
1696 return passphrase_required_reason_
!=
1697 syncer::REASON_PASSPHRASE_NOT_REQUIRED
;
1700 bool ProfileSyncService::IsPassphraseRequiredForDecryption() const {
1701 // If there is an encrypted datatype enabled and we don't have the proper
1702 // passphrase, we must prompt the user for a passphrase. The only way for the
1703 // user to avoid entering their passphrase is to disable the encrypted types.
1704 return IsEncryptedDatatypeEnabled() && IsPassphraseRequired();
1707 base::string16
ProfileSyncService::GetLastSyncedTimeString() const {
1708 if (last_synced_time_
.is_null())
1709 return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER
);
1711 base::TimeDelta last_synced
= base::Time::Now() - last_synced_time_
;
1713 if (last_synced
< base::TimeDelta::FromMinutes(1))
1714 return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW
);
1716 return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_ELAPSED
,
1717 ui::TimeFormat::LENGTH_SHORT
, last_synced
);
1720 void ProfileSyncService::UpdateSelectedTypesHistogram(
1721 bool sync_everything
, const syncer::ModelTypeSet chosen_types
) const {
1722 if (!HasSyncSetupCompleted() ||
1723 sync_everything
!= sync_prefs_
.HasKeepEverythingSynced()) {
1724 UMA_HISTOGRAM_BOOLEAN("Sync.SyncEverything", sync_everything
);
1727 // Only log the data types that are shown in the sync settings ui.
1728 // Note: the order of these types must match the ordering of
1729 // the respective types in ModelType
1730 const sync_driver::user_selectable_type::UserSelectableSyncType
1731 user_selectable_types
[] = {
1732 sync_driver::user_selectable_type::BOOKMARKS
,
1733 sync_driver::user_selectable_type::PREFERENCES
,
1734 sync_driver::user_selectable_type::PASSWORDS
,
1735 sync_driver::user_selectable_type::AUTOFILL
,
1736 sync_driver::user_selectable_type::THEMES
,
1737 sync_driver::user_selectable_type::TYPED_URLS
,
1738 sync_driver::user_selectable_type::EXTENSIONS
,
1739 sync_driver::user_selectable_type::APPS
,
1740 sync_driver::user_selectable_type::PROXY_TABS
1743 COMPILE_ASSERT(33 == syncer::MODEL_TYPE_COUNT
, UpdateCustomConfigHistogram
);
1745 if (!sync_everything
) {
1746 const syncer::ModelTypeSet current_types
= GetPreferredDataTypes();
1748 syncer::ModelTypeSet type_set
= syncer::UserSelectableTypes();
1749 syncer::ModelTypeSet::Iterator it
= type_set
.First();
1751 DCHECK_EQ(arraysize(user_selectable_types
), type_set
.Size());
1753 for (size_t i
= 0; i
< arraysize(user_selectable_types
) && it
.Good();
1755 const syncer::ModelType type
= it
.Get();
1756 if (chosen_types
.Has(type
) &&
1757 (!HasSyncSetupCompleted() || !current_types
.Has(type
))) {
1758 // Selected type has changed - log it.
1759 UMA_HISTOGRAM_ENUMERATION(
1761 user_selectable_types
[i
],
1762 sync_driver::user_selectable_type::SELECTABLE_DATATYPE_COUNT
+ 1);
1768 #if defined(OS_CHROMEOS)
1769 void ProfileSyncService::RefreshSpareBootstrapToken(
1770 const std::string
& passphrase
) {
1771 sync_driver::SystemEncryptor encryptor
;
1772 syncer::Cryptographer
temp_cryptographer(&encryptor
);
1773 // The first 2 params (hostname and username) doesn't have any effect here.
1774 syncer::KeyParams key_params
= {"localhost", "dummy", passphrase
};
1776 std::string bootstrap_token
;
1777 if (!temp_cryptographer
.AddKey(key_params
)) {
1778 NOTREACHED() << "Failed to add key to cryptographer.";
1780 temp_cryptographer
.GetBootstrapToken(&bootstrap_token
);
1781 sync_prefs_
.SetSpareBootstrapToken(bootstrap_token
);
1785 void ProfileSyncService::OnUserChoseDatatypes(
1786 bool sync_everything
,
1787 syncer::ModelTypeSet chosen_types
) {
1788 if (!backend_
.get() && !HasUnrecoverableError()) {
1793 UpdateSelectedTypesHistogram(sync_everything
, chosen_types
);
1794 sync_prefs_
.SetKeepEverythingSynced(sync_everything
);
1796 if (directory_data_type_manager_
.get())
1797 directory_data_type_manager_
->ResetDataTypeErrors();
1798 ChangePreferredDataTypes(chosen_types
);
1799 AcknowledgeSyncedTypes();
1802 void ProfileSyncService::ChangePreferredDataTypes(
1803 syncer::ModelTypeSet preferred_types
) {
1805 DVLOG(1) << "ChangePreferredDataTypes invoked";
1806 const syncer::ModelTypeSet registered_types
= GetRegisteredDataTypes();
1807 const syncer::ModelTypeSet registered_preferred_types
=
1808 Intersection(registered_types
, preferred_types
);
1809 sync_prefs_
.SetPreferredDataTypes(registered_types
,
1810 registered_preferred_types
);
1812 // Now reconfigure the DTM.
1813 ReconfigureDatatypeManager();
1815 // TODO(rlarocque): Reconfigure the NonBlockingDataTypeManager, too. Blocked
1816 // on crbug.com/368834. Until that bug is fixed, it's difficult to tell
1817 // which types should be enabled and when.
1820 syncer::ModelTypeSet
ProfileSyncService::GetActiveDataTypes() const {
1821 if (!SyncActive() || !ConfigurationDone())
1822 return syncer::ModelTypeSet();
1823 const syncer::ModelTypeSet preferred_types
= GetPreferredDataTypes();
1824 const syncer::ModelTypeSet failed_types
=
1825 data_type_status_table_
.GetFailedTypes();
1826 return Difference(preferred_types
, failed_types
);
1829 syncer::ModelTypeSet
ProfileSyncService::GetPreferredDataTypes() const {
1830 const syncer::ModelTypeSet registered_types
= GetRegisteredDataTypes();
1831 const syncer::ModelTypeSet preferred_types
=
1832 sync_prefs_
.GetPreferredDataTypes(registered_types
);
1833 const syncer::ModelTypeSet enforced_types
=
1834 Intersection(GetDataTypesFromPreferenceProviders(), registered_types
);
1835 return Union(preferred_types
, enforced_types
);
1838 syncer::ModelTypeSet
1839 ProfileSyncService::GetPreferredDirectoryDataTypes() const {
1840 const syncer::ModelTypeSet registered_directory_types
=
1841 GetRegisteredDirectoryDataTypes();
1842 const syncer::ModelTypeSet preferred_types
=
1843 sync_prefs_
.GetPreferredDataTypes(registered_directory_types
);
1844 const syncer::ModelTypeSet enforced_types
=
1845 Intersection(GetDataTypesFromPreferenceProviders(),
1846 registered_directory_types
);
1847 return Union(preferred_types
, enforced_types
);
1850 syncer::ModelTypeSet
1851 ProfileSyncService::GetPreferredNonBlockingDataTypes() const {
1852 return sync_prefs_
.GetPreferredDataTypes(GetRegisteredNonBlockingDataTypes());
1855 syncer::ModelTypeSet
ProfileSyncService::GetForcedDataTypes() const {
1856 // TODO(treib,zea): When SyncPrefs also implements SyncTypePreferenceProvider,
1857 // we'll need another way to distinguish user-choosable types from
1858 // programmatically-enabled types.
1859 return GetDataTypesFromPreferenceProviders();
1862 syncer::ModelTypeSet
ProfileSyncService::GetRegisteredDataTypes() const {
1863 return Union(GetRegisteredDirectoryDataTypes(),
1864 GetRegisteredNonBlockingDataTypes());
1867 syncer::ModelTypeSet
1868 ProfileSyncService::GetRegisteredDirectoryDataTypes() const {
1869 syncer::ModelTypeSet registered_types
;
1870 // The directory_data_type_controllers_ are determined by command-line flags;
1871 // that's effectively what controls the values returned here.
1872 for (DataTypeController::TypeMap::const_iterator it
=
1873 directory_data_type_controllers_
.begin();
1874 it
!= directory_data_type_controllers_
.end(); ++it
) {
1875 registered_types
.Put(it
->first
);
1877 return registered_types
;
1880 syncer::ModelTypeSet
1881 ProfileSyncService::GetRegisteredNonBlockingDataTypes() const {
1882 return non_blocking_data_type_manager_
.GetRegisteredTypes();
1885 bool ProfileSyncService::IsUsingSecondaryPassphrase() const {
1886 syncer::PassphraseType passphrase_type
= GetPassphraseType();
1887 return passphrase_type
== syncer::FROZEN_IMPLICIT_PASSPHRASE
||
1888 passphrase_type
== syncer::CUSTOM_PASSPHRASE
;
1891 syncer::PassphraseType
ProfileSyncService::GetPassphraseType() const {
1892 return backend_
->GetPassphraseType();
1895 base::Time
ProfileSyncService::GetExplicitPassphraseTime() const {
1896 return backend_
->GetExplicitPassphraseTime();
1899 bool ProfileSyncService::IsCryptographerReady(
1900 const syncer::BaseTransaction
* trans
) const {
1901 return backend_
.get() && backend_
->IsCryptographerReady(trans
);
1904 void ProfileSyncService::ConfigurePriorityDataTypes() {
1905 const syncer::ModelTypeSet priority_types
=
1906 Intersection(GetPreferredDirectoryDataTypes(),
1907 syncer::PriorityUserTypes());
1908 if (!priority_types
.Empty()) {
1909 const syncer::ConfigureReason reason
= HasSyncSetupCompleted() ?
1910 syncer::CONFIGURE_REASON_RECONFIGURATION
:
1911 syncer::CONFIGURE_REASON_NEW_CLIENT
;
1912 directory_data_type_manager_
->Configure(priority_types
, reason
);
1916 void ProfileSyncService::ConfigureDataTypeManager() {
1917 // Don't configure datatypes if the setup UI is still on the screen - this
1918 // is to help multi-screen setting UIs (like iOS) where they don't want to
1919 // start syncing data until the user is done configuring encryption options,
1920 // etc. ReconfigureDatatypeManager() will get called again once the UI calls
1921 // SetSetupInProgress(false).
1922 if (backend_mode_
== SYNC
&& startup_controller_
.setup_in_progress())
1925 bool restart
= false;
1926 if (!directory_data_type_manager_
) {
1928 directory_data_type_manager_
.reset(
1929 factory_
->CreateDataTypeManager(debug_info_listener_
,
1930 &directory_data_type_controllers_
,
1935 // We create the migrator at the same time.
1937 new browser_sync::BackendMigrator(
1938 profile_
->GetDebugName(), GetUserShare(),
1939 this, directory_data_type_manager_
.get(),
1940 base::Bind(&ProfileSyncService::StartSyncingWithServer
,
1941 base::Unretained(this))));
1944 syncer::ModelTypeSet types
;
1945 syncer::ConfigureReason reason
= syncer::CONFIGURE_REASON_UNKNOWN
;
1946 if (backend_mode_
== BACKUP
|| backend_mode_
== ROLLBACK
) {
1947 types
= syncer::BackupTypes();
1948 reason
= syncer::CONFIGURE_REASON_BACKUP_ROLLBACK
;
1950 types
= GetPreferredDirectoryDataTypes();
1951 if (!HasSyncSetupCompleted()) {
1952 reason
= syncer::CONFIGURE_REASON_NEW_CLIENT
;
1953 } else if (restart
) {
1954 // Datatype downloads on restart are generally due to newly supported
1955 // datatypes (although it's also possible we're picking up where a failed
1956 // previous configuration left off).
1957 // TODO(sync): consider detecting configuration recovery and setting
1958 // the reason here appropriately.
1959 reason
= syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE
;
1961 // The user initiated a reconfiguration (either to add or remove types).
1962 reason
= syncer::CONFIGURE_REASON_RECONFIGURATION
;
1966 directory_data_type_manager_
->Configure(types
, reason
);
1969 syncer::UserShare
* ProfileSyncService::GetUserShare() const {
1970 if (backend_
.get() && backend_initialized_
) {
1971 return backend_
->GetUserShare();
1977 syncer::sessions::SyncSessionSnapshot
1978 ProfileSyncService::GetLastSessionSnapshot() const {
1980 return backend_
->GetLastSessionSnapshot();
1981 return syncer::sessions::SyncSessionSnapshot();
1984 bool ProfileSyncService::HasUnsyncedItems() const {
1985 if (HasSyncingBackend() && backend_initialized_
) {
1986 return backend_
->HasUnsyncedItems();
1992 browser_sync::BackendMigrator
*
1993 ProfileSyncService::GetBackendMigratorForTest() {
1994 return migrator_
.get();
1997 void ProfileSyncService::GetModelSafeRoutingInfo(
1998 syncer::ModelSafeRoutingInfo
* out
) const {
1999 if (backend_
.get() && backend_initialized_
) {
2000 backend_
->GetModelSafeRoutingInfo(out
);
2006 base::Value
* ProfileSyncService::GetTypeStatusMap() const {
2007 scoped_ptr
<base::ListValue
> result(new base::ListValue());
2009 if (!backend_
.get() || !backend_initialized_
) {
2010 return result
.release();
2013 DataTypeStatusTable::TypeErrorMap error_map
=
2014 data_type_status_table_
.GetAllErrors();
2015 ModelTypeSet active_types
;
2016 ModelTypeSet passive_types
;
2017 ModelSafeRoutingInfo routing_info
;
2018 backend_
->GetModelSafeRoutingInfo(&routing_info
);
2019 for (ModelSafeRoutingInfo::const_iterator it
= routing_info
.begin();
2020 it
!= routing_info
.end(); ++it
) {
2021 if (it
->second
== syncer::GROUP_PASSIVE
) {
2022 passive_types
.Put(it
->first
);
2024 active_types
.Put(it
->first
);
2028 SyncBackendHost::Status detailed_status
= backend_
->GetDetailedStatus();
2029 ModelTypeSet
&throttled_types(detailed_status
.throttled_types
);
2030 ModelTypeSet registered
= GetRegisteredDataTypes();
2031 scoped_ptr
<base::DictionaryValue
> type_status_header(
2032 new base::DictionaryValue());
2034 type_status_header
->SetString("name", "Model Type");
2035 type_status_header
->SetString("status", "header");
2036 type_status_header
->SetString("value", "Group Type");
2037 type_status_header
->SetString("num_entries", "Total Entries");
2038 type_status_header
->SetString("num_live", "Live Entries");
2039 result
->Append(type_status_header
.release());
2041 scoped_ptr
<base::DictionaryValue
> type_status
;
2042 for (ModelTypeSet::Iterator it
= registered
.First(); it
.Good(); it
.Inc()) {
2043 ModelType type
= it
.Get();
2045 type_status
.reset(new base::DictionaryValue());
2046 type_status
->SetString("name", ModelTypeToString(type
));
2048 if (error_map
.find(type
) != error_map
.end()) {
2049 const syncer::SyncError
&error
= error_map
.find(type
)->second
;
2050 DCHECK(error
.IsSet());
2051 switch (error
.GetSeverity()) {
2052 case syncer::SyncError::SYNC_ERROR_SEVERITY_ERROR
: {
2053 std::string error_text
= "Error: " + error
.location().ToString() +
2054 ", " + error
.GetMessagePrefix() + error
.message();
2055 type_status
->SetString("status", "error");
2056 type_status
->SetString("value", error_text
);
2059 case syncer::SyncError::SYNC_ERROR_SEVERITY_INFO
:
2060 type_status
->SetString("status", "disabled");
2061 type_status
->SetString("value", error
.message());
2064 NOTREACHED() << "Unexpected error severity.";
2067 } else if (syncer::IsProxyType(type
) && passive_types
.Has(type
)) {
2068 // Show a proxy type in "ok" state unless it is disabled by user.
2069 DCHECK(!throttled_types
.Has(type
));
2070 type_status
->SetString("status", "ok");
2071 type_status
->SetString("value", "Passive");
2072 } else if (throttled_types
.Has(type
) && passive_types
.Has(type
)) {
2073 type_status
->SetString("status", "warning");
2074 type_status
->SetString("value", "Passive, Throttled");
2075 } else if (passive_types
.Has(type
)) {
2076 type_status
->SetString("status", "warning");
2077 type_status
->SetString("value", "Passive");
2078 } else if (throttled_types
.Has(type
)) {
2079 type_status
->SetString("status", "warning");
2080 type_status
->SetString("value", "Throttled");
2081 } else if (GetRegisteredNonBlockingDataTypes().Has(type
)) {
2082 type_status
->SetString("status", "ok");
2083 type_status
->SetString("value", "Non-Blocking");
2084 } else if (active_types
.Has(type
)) {
2085 type_status
->SetString("status", "ok");
2086 type_status
->SetString("value", "Active: " +
2087 ModelSafeGroupToString(routing_info
[type
]));
2089 type_status
->SetString("status", "warning");
2090 type_status
->SetString("value", "Disabled by User");
2093 int live_count
= detailed_status
.num_entries_by_type
[type
] -
2094 detailed_status
.num_to_delete_entries_by_type
[type
];
2095 type_status
->SetInteger("num_entries",
2096 detailed_status
.num_entries_by_type
[type
]);
2097 type_status
->SetInteger("num_live", live_count
);
2099 result
->Append(type_status
.release());
2101 return result
.release();
2104 void ProfileSyncService::DeactivateDataType(syncer::ModelType type
) {
2107 backend_
->DeactivateDataType(type
);
2110 void ProfileSyncService::ConsumeCachedPassphraseIfPossible() {
2111 // If no cached passphrase, or sync backend hasn't started up yet, just exit.
2112 // If the backend isn't running yet, OnBackendInitialized() will call this
2113 // method again after the backend starts up.
2114 if (cached_passphrase_
.empty() || !backend_initialized())
2117 // Backend is up and running, so we can consume the cached passphrase.
2118 std::string passphrase
= cached_passphrase_
;
2119 cached_passphrase_
.clear();
2121 // If we need a passphrase to decrypt data, try the cached passphrase.
2122 if (passphrase_required_reason() == syncer::REASON_DECRYPTION
) {
2123 if (SetDecryptionPassphrase(passphrase
)) {
2124 DVLOG(1) << "Cached passphrase successfully decrypted pending keys";
2129 // If we get here, we don't have pending keys (or at least, the passphrase
2130 // doesn't decrypt them) - just try to re-encrypt using the encryption
2132 if (!IsUsingSecondaryPassphrase())
2133 SetEncryptionPassphrase(passphrase
, IMPLICIT
);
2136 void ProfileSyncService::RequestAccessToken() {
2137 // Only one active request at a time.
2138 if (access_token_request_
!= NULL
)
2140 request_access_token_retry_timer_
.Stop();
2141 OAuth2TokenService::ScopeSet oauth2_scopes
;
2142 oauth2_scopes
.insert(signin_
->GetSyncScopeToUse());
2144 // Invalidate previous token, otherwise token service will return the same
2146 const std::string
& account_id
= signin_
->GetAccountIdToUse();
2147 if (!access_token_
.empty()) {
2148 oauth2_token_service_
->InvalidateToken(
2149 account_id
, oauth2_scopes
, access_token_
);
2152 access_token_
.clear();
2154 token_request_time_
= base::Time::Now();
2155 token_receive_time_
= base::Time();
2156 next_token_request_time_
= base::Time();
2157 access_token_request_
=
2158 oauth2_token_service_
->StartRequest(account_id
, oauth2_scopes
, this);
2161 void ProfileSyncService::SetEncryptionPassphrase(const std::string
& passphrase
,
2162 PassphraseType type
) {
2163 // This should only be called when the backend has been initialized.
2164 DCHECK(backend_initialized());
2165 DCHECK(!(type
== IMPLICIT
&& IsUsingSecondaryPassphrase())) <<
2166 "Data is already encrypted using an explicit passphrase";
2167 DCHECK(!(type
== EXPLICIT
&&
2168 passphrase_required_reason_
== syncer::REASON_DECRYPTION
)) <<
2169 "Can not set explicit passphrase when decryption is needed.";
2171 DVLOG(1) << "Setting " << (type
== EXPLICIT
? "explicit" : "implicit")
2172 << " passphrase for encryption.";
2173 if (passphrase_required_reason_
== syncer::REASON_ENCRYPTION
) {
2174 // REASON_ENCRYPTION implies that the cryptographer does not have pending
2175 // keys. Hence, as long as we're not trying to do an invalid passphrase
2176 // change (e.g. explicit -> explicit or explicit -> implicit), we know this
2177 // will succeed. If for some reason a new encryption key arrives via
2178 // sync later, the SBH will trigger another OnPassphraseRequired().
2179 passphrase_required_reason_
= syncer::REASON_PASSPHRASE_NOT_REQUIRED
;
2182 backend_
->SetEncryptionPassphrase(passphrase
, type
== EXPLICIT
);
2185 bool ProfileSyncService::SetDecryptionPassphrase(
2186 const std::string
& passphrase
) {
2187 if (IsPassphraseRequired()) {
2188 DVLOG(1) << "Setting passphrase for decryption.";
2189 return backend_
->SetDecryptionPassphrase(passphrase
);
2191 NOTREACHED() << "SetDecryptionPassphrase must not be called when "
2192 "IsPassphraseRequired() is false.";
2197 void ProfileSyncService::EnableEncryptEverything() {
2198 // Tests override backend_initialized() to always return true, so we
2199 // must check that instead of |backend_initialized_|.
2200 // TODO(akalin): Fix the above. :/
2201 DCHECK(backend_initialized());
2202 // TODO(atwilson): Persist the encryption_pending_ flag to address the various
2203 // problems around cancelling encryption in the background (crbug.com/119649).
2204 if (!encrypt_everything_
)
2205 encryption_pending_
= true;
2208 bool ProfileSyncService::encryption_pending() const {
2209 // We may be called during the setup process before we're
2210 // initialized (via IsEncryptedDatatypeEnabled and
2211 // IsPassphraseRequiredForDecryption).
2212 return encryption_pending_
;
2215 bool ProfileSyncService::EncryptEverythingEnabled() const {
2216 DCHECK(backend_initialized_
);
2217 return encrypt_everything_
|| encryption_pending_
;
2220 syncer::ModelTypeSet
ProfileSyncService::GetEncryptedDataTypes() const {
2221 DCHECK(encrypted_types_
.Has(syncer::PASSWORDS
));
2222 // We may be called during the setup process before we're
2223 // initialized. In this case, we default to the sensitive types.
2224 return encrypted_types_
;
2227 void ProfileSyncService::OnSyncManagedPrefChange(bool is_sync_managed
) {
2228 if (is_sync_managed
) {
2231 // Sync is no longer disabled by policy. Try starting it up if appropriate.
2232 startup_controller_
.TryStart();
2236 void ProfileSyncService::GoogleSigninSucceeded(const std::string
& account_id
,
2237 const std::string
& username
,
2238 const std::string
& password
) {
2239 if (!sync_prefs_
.IsStartSuppressed() && !password
.empty()) {
2240 cached_passphrase_
= password
;
2241 // Try to consume the passphrase we just cached. If the sync backend
2242 // is not running yet, the passphrase will remain cached until the
2243 // backend starts up.
2244 ConsumeCachedPassphraseIfPossible();
2246 #if defined(OS_CHROMEOS)
2247 RefreshSpareBootstrapToken(password
);
2249 if (!backend_initialized() || GetAuthError().state() != AuthError::NONE
) {
2250 // Track the fact that we're still waiting for auth to complete.
2251 is_auth_in_progress_
= true;
2255 void ProfileSyncService::GoogleSignedOut(const std::string
& account_id
,
2256 const std::string
& username
) {
2257 sync_disabled_by_admin_
= false;
2260 if (browser_sync::BackupRollbackController::IsBackupEnabled()) {
2261 need_backup_
= true;
2262 backup_finished_
= false;
2266 void ProfileSyncService::AddObserver(
2267 ProfileSyncServiceBase::Observer
* observer
) {
2268 observers_
.AddObserver(observer
);
2271 void ProfileSyncService::RemoveObserver(
2272 ProfileSyncServiceBase::Observer
* observer
) {
2273 observers_
.RemoveObserver(observer
);
2276 void ProfileSyncService::AddProtocolEventObserver(
2277 browser_sync::ProtocolEventObserver
* observer
) {
2278 protocol_event_observers_
.AddObserver(observer
);
2279 if (HasSyncingBackend()) {
2280 backend_
->RequestBufferedProtocolEventsAndEnableForwarding();
2284 void ProfileSyncService::RemoveProtocolEventObserver(
2285 browser_sync::ProtocolEventObserver
* observer
) {
2286 protocol_event_observers_
.RemoveObserver(observer
);
2287 if (HasSyncingBackend() &&
2288 !protocol_event_observers_
.might_have_observers()) {
2289 backend_
->DisableProtocolEventForwarding();
2293 void ProfileSyncService::AddTypeDebugInfoObserver(
2294 syncer::TypeDebugInfoObserver
* type_debug_info_observer
) {
2295 type_debug_info_observers_
.AddObserver(type_debug_info_observer
);
2296 if (type_debug_info_observers_
.might_have_observers() &&
2297 backend_initialized_
) {
2298 backend_
->EnableDirectoryTypeDebugInfoForwarding();
2302 void ProfileSyncService::RemoveTypeDebugInfoObserver(
2303 syncer::TypeDebugInfoObserver
* type_debug_info_observer
) {
2304 type_debug_info_observers_
.RemoveObserver(type_debug_info_observer
);
2305 if (!type_debug_info_observers_
.might_have_observers() &&
2306 backend_initialized_
) {
2307 backend_
->DisableDirectoryTypeDebugInfoForwarding();
2311 void ProfileSyncService::AddPreferenceProvider(
2312 SyncTypePreferenceProvider
* provider
) {
2313 DCHECK(!HasPreferenceProvider(provider
))
2314 << "Providers may only be added once!";
2315 preference_providers_
.insert(provider
);
2318 void ProfileSyncService::RemovePreferenceProvider(
2319 SyncTypePreferenceProvider
* provider
) {
2320 DCHECK(HasPreferenceProvider(provider
))
2321 << "Only providers that have been added before can be removed!";
2322 preference_providers_
.erase(provider
);
2325 bool ProfileSyncService::HasPreferenceProvider(
2326 SyncTypePreferenceProvider
* provider
) const {
2327 return preference_providers_
.count(provider
) > 0;
2332 class GetAllNodesRequestHelper
2333 : public base::RefCountedThreadSafe
<GetAllNodesRequestHelper
> {
2335 GetAllNodesRequestHelper(
2336 syncer::ModelTypeSet requested_types
,
2337 const base::Callback
<void(scoped_ptr
<base::ListValue
>)>& callback
);
2339 void OnReceivedNodesForTypes(
2340 const std::vector
<syncer::ModelType
>& types
,
2341 ScopedVector
<base::ListValue
> scoped_node_lists
);
2344 friend class base::RefCountedThreadSafe
<GetAllNodesRequestHelper
>;
2345 virtual ~GetAllNodesRequestHelper();
2347 scoped_ptr
<base::ListValue
> result_accumulator_
;
2349 syncer::ModelTypeSet awaiting_types_
;
2350 base::Callback
<void(scoped_ptr
<base::ListValue
>)> callback_
;
2353 GetAllNodesRequestHelper::GetAllNodesRequestHelper(
2354 syncer::ModelTypeSet requested_types
,
2355 const base::Callback
<void(scoped_ptr
<base::ListValue
>)>& callback
)
2356 : result_accumulator_(new base::ListValue()),
2357 awaiting_types_(requested_types
),
2358 callback_(callback
) {}
2360 GetAllNodesRequestHelper::~GetAllNodesRequestHelper() {
2361 if (!awaiting_types_
.Empty()) {
2363 << "GetAllNodesRequest deleted before request was fulfilled. "
2364 << "Missing types are: " << ModelTypeSetToString(awaiting_types_
);
2368 // Called when the set of nodes for a type or set of types has been returned.
2370 // The nodes for several types can be returned at the same time by specifying
2371 // their types in the |types| array, and putting their results at the
2372 // correspnding indices in the |scoped_node_lists|.
2373 void GetAllNodesRequestHelper::OnReceivedNodesForTypes(
2374 const std::vector
<syncer::ModelType
>& types
,
2375 ScopedVector
<base::ListValue
> scoped_node_lists
) {
2376 DCHECK_EQ(types
.size(), scoped_node_lists
.size());
2378 // Take unsafe ownership of the node list.
2379 std::vector
<base::ListValue
*> node_lists
;
2380 scoped_node_lists
.release(&node_lists
);
2382 for (size_t i
= 0; i
< node_lists
.size() && i
< types
.size(); ++i
) {
2383 const ModelType type
= types
[i
];
2384 base::ListValue
* node_list
= node_lists
[i
];
2386 // Add these results to our list.
2387 scoped_ptr
<base::DictionaryValue
> type_dict(new base::DictionaryValue());
2388 type_dict
->SetString("type", ModelTypeToString(type
));
2389 type_dict
->Set("nodes", node_list
);
2390 result_accumulator_
->Append(type_dict
.release());
2392 // Remember that this part of the request is satisfied.
2393 awaiting_types_
.Remove(type
);
2396 if (awaiting_types_
.Empty()) {
2397 callback_
.Run(result_accumulator_
.Pass());
2404 void ProfileSyncService::GetAllNodes(
2405 const base::Callback
<void(scoped_ptr
<base::ListValue
>)>& callback
) {
2406 ModelTypeSet directory_types
= GetRegisteredDirectoryDataTypes();
2407 directory_types
.PutAll(syncer::ControlTypes());
2408 scoped_refptr
<GetAllNodesRequestHelper
> helper
=
2409 new GetAllNodesRequestHelper(directory_types
, callback
);
2411 if (!backend_initialized_
) {
2412 // If there's no backend available to fulfill the request, handle it here.
2413 ScopedVector
<base::ListValue
> empty_results
;
2414 std::vector
<ModelType
> type_vector
;
2415 for (ModelTypeSet::Iterator it
= directory_types
.First();
2416 it
.Good(); it
.Inc()) {
2417 type_vector
.push_back(it
.Get());
2418 empty_results
.push_back(new base::ListValue());
2420 helper
->OnReceivedNodesForTypes(type_vector
, empty_results
.Pass());
2422 backend_
->GetAllNodesForTypes(
2424 base::Bind(&GetAllNodesRequestHelper::OnReceivedNodesForTypes
, helper
));
2428 bool ProfileSyncService::HasObserver(
2429 ProfileSyncServiceBase::Observer
* observer
) const {
2430 return observers_
.HasObserver(observer
);
2433 base::WeakPtr
<syncer::JsController
> ProfileSyncService::GetJsController() {
2434 return sync_js_controller_
.AsWeakPtr();
2437 void ProfileSyncService::SyncEvent(SyncEventCodes code
) {
2438 UMA_HISTOGRAM_ENUMERATION("Sync.EventCodes", code
, MAX_SYNC_EVENT_CODE
);
2442 bool ProfileSyncService::IsSyncEnabled() {
2443 // We have switches::kEnableSync just in case we need to change back to
2444 // sync-disabled-by-default on a platform.
2445 return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableSync
);
2448 bool ProfileSyncService::IsManaged() const {
2449 return sync_prefs_
.IsManaged() || sync_disabled_by_admin_
;
2452 void ProfileSyncService::StopAndSuppress() {
2453 sync_prefs_
.SetStartSuppressed(true);
2454 if (HasSyncingBackend()) {
2455 backend_
->UnregisterInvalidationIds();
2457 ShutdownImpl(syncer::STOP_SYNC
);
2460 bool ProfileSyncService::IsStartSuppressed() const {
2461 return sync_prefs_
.IsStartSuppressed();
2464 SigninManagerBase
* ProfileSyncService::signin() const {
2467 return signin_
->GetOriginal();
2470 void ProfileSyncService::UnsuppressAndStart() {
2472 sync_prefs_
.SetStartSuppressed(false);
2473 if (signin_
.get() && !signin_
->GetOriginal()->IsAuthenticated()) {
2474 signin_
->GetOriginal()->SetAuthenticatedUsername(
2475 profile_
->GetPrefs()->GetString(prefs::kGoogleServicesUsername
));
2477 startup_controller_
.TryStart();
2480 void ProfileSyncService::AcknowledgeSyncedTypes() {
2481 sync_prefs_
.AcknowledgeSyncedTypes(GetRegisteredDataTypes());
2484 void ProfileSyncService::ReconfigureDatatypeManager() {
2485 // If we haven't initialized yet, don't configure the DTM as it could cause
2486 // association to start before a Directory has even been created.
2487 if (backend_initialized_
) {
2488 DCHECK(backend_
.get());
2489 ConfigureDataTypeManager();
2490 } else if (HasUnrecoverableError()) {
2491 // There is nothing more to configure. So inform the listeners,
2494 DVLOG(1) << "ConfigureDataTypeManager not invoked because of an "
2495 << "Unrecoverable error.";
2497 DVLOG(0) << "ConfigureDataTypeManager not invoked because backend is not "
2502 syncer::ModelTypeSet
ProfileSyncService::GetDataTypesFromPreferenceProviders()
2504 syncer::ModelTypeSet types
;
2505 for (std::set
<SyncTypePreferenceProvider
*>::const_iterator it
=
2506 preference_providers_
.begin();
2507 it
!= preference_providers_
.end();
2509 types
.PutAll((*it
)->GetPreferredDataTypes());
2514 const DataTypeStatusTable
& ProfileSyncService::data_type_status_table()
2516 return data_type_status_table_
;
2519 void ProfileSyncService::OnInternalUnrecoverableError(
2520 const tracked_objects::Location
& from_here
,
2521 const std::string
& message
,
2522 bool delete_sync_database
,
2523 UnrecoverableErrorReason reason
) {
2524 DCHECK(!HasUnrecoverableError());
2525 unrecoverable_error_reason_
= reason
;
2526 OnUnrecoverableErrorImpl(from_here
, message
, delete_sync_database
);
2529 syncer::SyncManagerFactory::MANAGER_TYPE
2530 ProfileSyncService::GetManagerType() const {
2531 switch (backend_mode_
) {
2533 return syncer::SyncManagerFactory::NORMAL
;
2535 return syncer::SyncManagerFactory::BACKUP
;
2537 return syncer::SyncManagerFactory::ROLLBACK
;
2541 return syncer::SyncManagerFactory::NORMAL
;
2544 bool ProfileSyncService::IsRetryingAccessTokenFetchForTest() const {
2545 return request_access_token_retry_timer_
.IsRunning();
2548 std::string
ProfileSyncService::GetAccessTokenForTest() const {
2549 return access_token_
;
2552 WeakHandle
<syncer::JsEventHandler
> ProfileSyncService::GetJsEventHandler() {
2553 return MakeWeakHandle(sync_js_controller_
.AsWeakPtr());
2556 syncer::SyncableService
* ProfileSyncService::GetSessionsSyncableService() {
2557 return sessions_sync_manager_
.get();
2560 syncer::SyncableService
* ProfileSyncService::GetDeviceInfoSyncableService() {
2561 return device_info_sync_service_
.get();
2564 ProfileSyncService::SyncTokenStatus::SyncTokenStatus()
2565 : connection_status(syncer::CONNECTION_NOT_ATTEMPTED
),
2566 last_get_token_error(GoogleServiceAuthError::AuthErrorNone()) {}
2567 ProfileSyncService::SyncTokenStatus::~SyncTokenStatus() {}
2569 ProfileSyncService::SyncTokenStatus
2570 ProfileSyncService::GetSyncTokenStatus() const {
2571 SyncTokenStatus status
;
2572 status
.connection_status_update_time
= connection_status_update_time_
;
2573 status
.connection_status
= connection_status_
;
2574 status
.token_request_time
= token_request_time_
;
2575 status
.token_receive_time
= token_receive_time_
;
2576 status
.last_get_token_error
= last_get_token_error_
;
2577 if (request_access_token_retry_timer_
.IsRunning())
2578 status
.next_token_request_time
= next_token_request_time_
;
2582 void ProfileSyncService::OverrideNetworkResourcesForTest(
2583 scoped_ptr
<syncer::NetworkResources
> network_resources
) {
2584 network_resources_
= network_resources
.Pass();
2587 bool ProfileSyncService::HasSyncingBackend() const {
2588 return backend_mode_
!= SYNC
? false : backend_
!= NULL
;
2591 void ProfileSyncService::UpdateFirstSyncTimePref() {
2592 if (signin_
->GetEffectiveUsername().empty()) {
2593 // Clear if user's not signed in and rollback is done.
2594 if (backend_mode_
!= ROLLBACK
)
2595 sync_prefs_
.ClearFirstSyncTime();
2596 } else if (sync_prefs_
.GetFirstSyncTime().is_null() &&
2597 backend_mode_
== SYNC
) {
2598 // Set if not set before and it's syncing now.
2599 sync_prefs_
.SetFirstSyncTime(base::Time::Now());
2603 void ProfileSyncService::ClearBrowsingDataSinceFirstSync() {
2604 base::Time first_sync_time
= sync_prefs_
.GetFirstSyncTime();
2605 if (first_sync_time
.is_null())
2608 clear_browsing_data_
.Run(browsing_data_remover_observer_
,
2614 void ProfileSyncService::SetBrowsingDataRemoverObserverForTesting(
2615 BrowsingDataRemover::Observer
* observer
) {
2616 browsing_data_remover_observer_
= observer
;
2619 void ProfileSyncService::SetClearingBrowseringDataForTesting(
2620 base::Callback
<void(BrowsingDataRemover::Observer
* observer
,
2624 clear_browsing_data_
= c
;
2627 GURL
ProfileSyncService::GetSyncServiceURL(
2628 const base::CommandLine
& command_line
) {
2629 // By default, dev, canary, and unbranded Chromium users will go to the
2630 // development servers. Development servers have more features than standard
2631 // sync servers. Users with officially-branded Chrome stable and beta builds
2632 // will go to the standard sync servers.
2633 GURL
result(kDevServerUrl
);
2635 chrome::VersionInfo::Channel channel
= chrome::VersionInfo::GetChannel();
2636 if (channel
== chrome::VersionInfo::CHANNEL_STABLE
||
2637 channel
== chrome::VersionInfo::CHANNEL_BETA
) {
2638 result
= GURL(kSyncServerUrl
);
2641 // Override the sync server URL from the command-line, if sync server
2642 // command-line argument exists.
2643 if (command_line
.HasSwitch(switches::kSyncServiceURL
)) {
2644 std::string
value(command_line
.GetSwitchValueASCII(
2645 switches::kSyncServiceURL
));
2646 if (!value
.empty()) {
2647 GURL
custom_sync_url(value
);
2648 if (custom_sync_url
.is_valid()) {
2649 result
= custom_sync_url
;
2651 LOG(WARNING
) << "The following sync URL specified at the command-line "
2652 << "is invalid: " << value
;
2659 void ProfileSyncService::CheckSyncBackupIfNeeded() {
2660 DCHECK_EQ(backend_mode_
, SYNC
);
2662 #if defined(ENABLE_PRE_SYNC_BACKUP)
2663 // Check backup once a day.
2664 if (!last_backup_time_
&&
2665 (last_synced_time_
.is_null() ||
2666 base::Time::Now() - last_synced_time_
>=
2667 base::TimeDelta::FromDays(1))) {
2668 // If sync thread is set, need to serialize check on sync thread after
2669 // closing backup DB.
2671 sync_thread_
->message_loop_proxy()->PostTask(
2673 base::Bind(syncer::CheckSyncDbLastModifiedTime
,
2674 profile_
->GetPath().Append(kSyncBackupDataFolderName
),
2675 base::MessageLoopProxy::current(),
2676 base::Bind(&ProfileSyncService::CheckSyncBackupCallback
,
2677 weak_factory_
.GetWeakPtr())));
2679 content::BrowserThread::PostTask(
2680 content::BrowserThread::FILE, FROM_HERE
,
2681 base::Bind(syncer::CheckSyncDbLastModifiedTime
,
2682 profile_
->GetPath().Append(kSyncBackupDataFolderName
),
2683 base::MessageLoopProxy::current(),
2684 base::Bind(&ProfileSyncService::CheckSyncBackupCallback
,
2685 weak_factory_
.GetWeakPtr())));
2691 void ProfileSyncService::CheckSyncBackupCallback(base::Time backup_time
) {
2692 last_backup_time_
.reset(new base::Time(backup_time
));
2694 DCHECK(device_info_sync_service_
);
2695 device_info_sync_service_
->UpdateLocalDeviceBackupTime(*last_backup_time_
);
2698 void ProfileSyncService::TryStartSyncAfterBackup() {
2699 startup_controller_
.Reset(GetRegisteredDataTypes());
2700 startup_controller_
.TryStart();
2703 void ProfileSyncService::CleanUpBackup() {
2704 sync_prefs_
.ClearFirstSyncTime();
2705 profile_
->GetIOTaskRunner()->PostTask(
2707 base::Bind(base::IgnoreResult(base::DeleteFile
),
2708 profile_
->GetPath().Append(kSyncBackupDataFolderName
),
2712 bool ProfileSyncService::NeedBackup() const {
2713 return need_backup_
;
2716 base::Time
ProfileSyncService::GetDeviceBackupTimeForTesting() const {
2717 return device_info_sync_service_
->GetLocalDeviceBackupTime();
2720 void ProfileSyncService::FlushDirectory() const {
2721 // backend_initialized_ implies backend_ isn't NULL and the manager exists.
2722 // If sync is not initialized yet, we fail silently.
2723 if (backend_initialized_
)
2724 backend_
->FlushDirectory();