MacViews: Get c/b/ui/views/tabs to build on Mac
[chromium-blink-merge.git] / chrome / browser / sync / profile_sync_service.cc
blob72f7999c8bacbf526b7f512b0cb0b5e6c9a7b969
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"
7 #include <cstddef>
8 #include <map>
9 #include <vector>
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"
105 #endif
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.
144 2000,
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.
151 0.2, // 20%
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.
163 false,
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");
172 namespace {
174 void ClearBrowsingData(BrowsingDataRemover::Observer* observer,
175 Profile* profile,
176 base::Time start,
177 base::Time end) {
178 // BrowsingDataRemover deletes itself when it's done.
179 BrowsingDataRemover* remover = BrowsingDataRemover::CreateForRange(
180 profile, start, end);
181 if (observer)
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,
202 Profile* profile,
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()),
210 profile_(profile),
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),
226 weak_factory_(this),
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),
231 startup_controller_(
232 start_behavior,
233 oauth2_token_service,
234 &sync_prefs_,
235 signin_.get(),
236 base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
237 startup_controller_weak_factory_.GetWeakPtr(),
238 SYNC)),
239 backup_rollback_controller_(
240 &sync_prefs_,
241 signin_.get(),
242 base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
243 startup_controller_weak_factory_.GetWeakPtr(),
244 BACKUP),
245 base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
246 startup_controller_weak_factory_.GetWeakPtr(),
247 ROLLBACK)),
248 backend_mode_(IDLE),
249 need_backup_(false),
250 backup_finished_(false),
251 clear_browsing_data_(base::Bind(&ClearBrowsingData)),
252 browsing_data_remover_observer_(NULL) {
253 DCHECK(profile);
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())
276 return false;
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_)
284 return false;
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
293 // in about:sync.
294 ClearStaleErrors();
296 sync_prefs_.AddSyncPrefObserver(this);
298 // For now, the only thing we can do through policy is to turn sync off.
299 if (IsManaged()) {
300 DisableForUser();
301 return;
304 RegisterAuthNotifications();
306 if (!HasSyncSetupCompleted() || signin_->GetEffectiveUsername().empty()) {
307 // Clean up in case of previous crash / setup abort / signout.
308 DisableForUser();
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());
321 #endif
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());
328 #endif
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();
339 } else {
340 need_backup_ = false;
343 #if defined(ENABLE_PRE_SYNC_BACKUP)
344 if (!running_rollback && signin_->GetEffectiveUsername().empty()) {
345 CleanUpBackup();
347 #else
348 DCHECK(!running_rollback);
349 #endif
351 startup_controller_.Reset(GetRegisteredDataTypes());
352 startup_controller_.TryStart();
355 void ProfileSyncService::TrySyncDatatypePrefRecovery() {
356 DCHECK(!backend_initialized());
357 if (!HasSyncSetupCompleted())
358 return;
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();
366 if (!pref_service)
367 return;
368 if (GetPreferredDataTypes().Size() > 1)
369 return;
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
375 // by policy.
376 if (!keep_everything_synced->IsDefaultValue())
377 return;
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() {
387 if (backend_)
388 backend_->StartSyncingWithServer();
391 void ProfileSyncService::RegisterAuthNotifications() {
392 oauth2_token_service_->AddObserver(this);
393 if (signin())
394 signin()->AddObserver(this);
397 void ProfileSyncService::UnregisterAuthNotifications() {
398 if (signin())
399 signin()->RemoveObserver(this);
400 oauth2_token_service_->RemoveObserver(this);
403 void ProfileSyncService::RegisterDataTypeController(
404 DataTypeController* data_type_controller) {
405 DCHECK_EQ(
406 directory_data_type_controllers_.count(data_type_controller->type()),
407 0U);
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
420 // enabled.
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()) {
437 return false;
439 return iter->second->state() == DataTypeController::RUNNING;
442 browser_sync::OpenTabsUIDelegate* ProfileSyncService::GetOpenTabsUIDelegate() {
443 if (!IsDataTypeControllerRunning(syncer::SESSIONS))
444 return NULL;
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()
458 const {
459 if (!IsDataTypeControllerRunning(syncer::DEVICE_INFO))
460 return NULL;
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();
475 ++iter)
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());
492 return credentials;
495 bool ProfileSyncService::ShouldDeleteSyncFolder() {
496 switch (backend_mode_) {
497 case SYNC:
498 return !HasSyncSetupCompleted();
499 case BACKUP:
500 return true;
501 case ROLLBACK:
502 return false;
503 case IDLE:
504 NOTREACHED();
505 return true;
507 return true;
510 void ProfileSyncService::InitializeBackend(bool delete_stale_data) {
511 if (!backend_) {
512 NOTREACHED();
513 return;
516 SyncCredentials credentials = GetCredentials();
518 scoped_refptr<net::URLRequestContextGetter> request_context_getter(
519 profile_->GetRequestContext());
521 if (backend_mode_ == SYNC && delete_stale_data)
522 ClearStaleErrors();
524 scoped_ptr<syncer::UnrecoverableErrorHandler>
525 backend_unrecoverable_error_handler(
526 new browser_sync::BackendUnrecoverableErrorHandler(
527 MakeWeakHandle(weak_factory_.GetWeakPtr())));
529 backend_->Initialize(
530 this,
531 sync_thread_.Pass(),
532 GetJsEventHandler(),
533 sync_service_url_,
534 credentials,
535 delete_stale_data,
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())
545 return true;
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.";
589 return;
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.";
597 return;
600 startup_controller_.OnDataTypeRequestsSyncStartup(type);
603 void ProfileSyncService::StartUpSlowBackendComponents(
604 ProfileSyncService::BackendMode mode) {
605 DCHECK_NE(IDLE, mode);
606 if (backend_mode_ == mode) {
607 return;
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;
622 return;
625 if (backend_mode_ == ROLLBACK ||
626 (backend_mode_ == BACKUP && !backup_finished_)) {
627 // Wait for rollback/backup to finish before start new backend.
628 return;
631 if (mode == SYNC && NeedBackup() && !backup_finished_) {
632 if (backend_mode_ != BACKUP)
633 backup_rollback_controller_.StartBackup();
634 return;
637 DVLOG(1) << "Start backend mode: " << mode;
639 if (backend_) {
640 if (mode == SYNC)
641 ShutdownImpl(syncer::SWITCH_MODE_SYNC);
642 else
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(
670 profile_);
671 if (provider)
672 invalidator = provider->GetInvalidationService();
675 backend_.reset(
676 factory_->CreateSyncBackendHost(
677 profile_->GetDebugName(),
678 profile_,
679 invalidator,
680 sync_prefs_.AsWeakPtr(),
681 sync_folder));
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
685 // be there.
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",
704 AUTH_ERROR_FIXED,
705 AUTH_ERROR_LIMIT);
708 if (HasSyncingBackend())
709 backend_->UpdateCredentials(GetCredentials());
710 else
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(
731 FROM_HERE,
732 request_access_token_backoff_.GetTimeUntilRelease(),
733 base::Bind(&ProfileSyncService::RequestAccessToken,
734 weak_factory_.GetWeakPtr()));
735 NotifyObservers();
736 break;
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,
743 AUTH_ERROR_LIMIT);
745 // Fallthrough.
747 default: {
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
785 // from storage.
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();
791 } else {
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();
806 if (sync_thread_)
807 sync_thread_->Stop();
810 void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason) {
811 if (!backend_)
812 return;
814 non_blocking_data_type_manager_.DisconnectSyncBackend();
816 // First, we spin down the backend to stop change processing as soon as
817 // possible.
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
837 // snapshot.
838 migrator_.reset();
839 sync_js_controller_.AttachJsBackend(WeakHandle<syncer::JsBackend>());
841 // Move aside the backend so nobody else tries to use it while we are
842 // shutting it down.
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());
886 NotifyObservers();
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_,
912 OnStateChanged());
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)
937 return;
938 NOTREACHED();
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_,
962 ERROR_REASON_LIMIT);
963 std::string location;
964 from_here.Write(true, true, &location);
965 LOG(ERROR)
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)
984 return;
986 is_first_time_sync_configure_ = !HasSyncSetupCompleted();
988 if (is_first_time_sync_configure_) {
989 UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeFirstTimeSuccess", success);
990 } else {
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);
999 } else {
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
1039 // below.
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();
1048 } else {
1049 DCHECK(FirstSetupInProgress());
1052 NotifyObservers();
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,
1060 bool success) {
1061 UpdateBackendInitUMA(success);
1063 if (!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",
1078 false,
1079 ERROR_REASON_BACKEND_INIT_FAILURE);
1080 return;
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
1101 // as a UserShare.
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();
1110 else
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))
1130 return;
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()
1138 ->Disable();
1139 } else {
1140 profile()->GetPrefs()->ClearPref(prefs::kGCMChannelEnabled);
1141 gcm::GCMProfileServiceFactory::GetForProfile(profile())->driver()
1142 ->Enable();
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);
1152 } else {
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
1165 // available.
1166 if (migrator_.get() &&
1167 migrator_->state() != browser_sync::BackendMigrator::IDLE) {
1168 DVLOG(1) << "Dropping OnExperimentsChanged due to migrator busy.";
1169 return;
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
1189 // leave them off.
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;
1211 NotifyObservers();
1214 namespace {
1216 AuthError ConnectionStatusToAuthError(
1217 syncer::ConnectionStatus status) {
1218 switch (status) {
1219 case syncer::CONNECTION_OK:
1220 return AuthError::AuthErrorNone();
1221 break;
1222 case syncer::CONNECTION_AUTH_ERROR:
1223 return AuthError(AuthError::INVALID_GAIA_CREDENTIALS);
1224 break;
1225 case syncer::CONNECTION_SERVER_ERROR:
1226 return AuthError(AuthError::CONNECTION_FAILED);
1227 break;
1228 default:
1229 NOTREACHED();
1230 return AuthError(AuthError::CONNECTION_FAILED);
1234 } // namespace
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()) {
1260 NOTREACHED();
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();
1267 } else {
1268 request_access_token_backoff_.InformOfRequest(false);
1269 request_access_token_retry_timer_.Start(
1270 FROM_HERE,
1271 request_access_token_backoff_.GetTimeUntilRelease(),
1272 base::Bind(&ProfileSyncService::RequestAccessToken,
1273 weak_factory_.GetWeakPtr()));
1275 } else {
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()) {
1283 NOTREACHED();
1284 } else {
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);
1298 DisableForUser();
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.
1311 return;
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.
1329 NotifyObservers();
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
1347 // this time.
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.
1357 NotifyObservers();
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));
1371 NotifyObservers();
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
1379 // finished.
1380 NotifyObservers();
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,
1413 true,
1414 ERROR_REASON_ACTIONABLE_ERROR);
1415 break;
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);
1428 #endif
1429 break;
1430 case syncer::ROLLBACK_DONE:
1431 backup_rollback_controller_.OnRollbackDone();
1432 break;
1433 case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT:
1434 // Sync disabled by domain admin. we should stop syncing until next
1435 // restart.
1436 sync_disabled_by_admin_ = true;
1437 ShutdownImpl(syncer::DISABLE_SYNC);
1438 break;
1439 default:
1440 NOTREACHED();
1442 NotifyObservers();
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.
1448 CleanUpBackup();
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);
1478 return;
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);
1492 } else {
1493 UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceSubsequentConfigureTime",
1494 delta);
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;
1518 return;
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_) +
1531 " caused by " +
1532 syncer::ModelTypeSetToString(
1533 data_type_status_table_.GetUnrecoverableErrorTypes()) +
1534 ": " + error.message();
1535 LOG(ERROR) << "ProfileSyncService error: " << message;
1536 OnInternalUnrecoverableError(error.location(),
1537 message,
1538 true,
1539 ERROR_REASON_CONFIGURATION_FAILURE);
1540 return;
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();
1552 NotifyObservers();
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);
1560 } else {
1561 StartSyncingWithServer();
1565 void ProfileSyncService::OnConfigureStart() {
1566 sync_configure_start_time_ = base::Time::Now();
1567 NotifyObservers();
1570 ProfileSyncService::SyncStatusSummary
1571 ProfileSyncService::QuerySyncStatusSummary() {
1572 if (HasUnrecoverableError()) {
1573 return UNRECOVERABLE_ERROR;
1574 } else if (!backend_) {
1575 return NOT_ENABLED;
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;
1582 } else if (
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()) {
1588 return INITIALIZED;
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_) : "";
1600 switch (status) {
1601 case UNRECOVERABLE_ERROR:
1602 return "Unrecoverable error detected";
1603 case NOT_ENABLED:
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";
1609 case 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;
1615 default:
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();
1636 return true;
1637 } else {
1638 SyncBackendHost::Status status;
1639 status.sync_protocol_error = last_actionable_error_;
1640 *result = status;
1641 return false;
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)
1656 return;
1658 startup_controller_.set_setup_in_progress(setup_in_progress);
1659 if (!setup_in_progress && backend_initialized())
1660 ReconfigureDatatypeManager();
1661 NotifyObservers();
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();
1754 ++i, it.Inc()) {
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(
1760 "Sync.CustomSync",
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);
1783 #endif
1785 void ProfileSyncService::OnUserChoseDatatypes(
1786 bool sync_everything,
1787 syncer::ModelTypeSet chosen_types) {
1788 if (!backend_.get() && !HasUnrecoverableError()) {
1789 NOTREACHED();
1790 return;
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())
1923 return;
1925 bool restart = false;
1926 if (!directory_data_type_manager_) {
1927 restart = true;
1928 directory_data_type_manager_.reset(
1929 factory_->CreateDataTypeManager(debug_info_listener_,
1930 &directory_data_type_controllers_,
1931 this,
1932 backend_.get(),
1933 this));
1935 // We create the migrator at the same time.
1936 migrator_.reset(
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;
1949 } else {
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;
1960 } else {
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();
1973 NOTREACHED();
1974 return NULL;
1977 syncer::sessions::SyncSessionSnapshot
1978 ProfileSyncService::GetLastSessionSnapshot() const {
1979 if (backend_)
1980 return backend_->GetLastSessionSnapshot();
1981 return syncer::sessions::SyncSessionSnapshot();
1984 bool ProfileSyncService::HasUnsyncedItems() const {
1985 if (HasSyncingBackend() && backend_initialized_) {
1986 return backend_->HasUnsyncedItems();
1988 NOTREACHED();
1989 return false;
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);
2001 } else {
2002 NOTREACHED();
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);
2023 } else {
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);
2058 break;
2059 case syncer::SyncError::SYNC_ERROR_SEVERITY_INFO:
2060 type_status->SetString("status", "disabled");
2061 type_status->SetString("value", error.message());
2062 break;
2063 default:
2064 NOTREACHED() << "Unexpected error severity.";
2065 break;
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]));
2088 } else {
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) {
2105 if (!backend_)
2106 return;
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())
2115 return;
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";
2125 return;
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
2131 // passphrase.
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)
2139 return;
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
2145 // token again.
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;
2180 NotifyObservers();
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);
2190 } else {
2191 NOTREACHED() << "SetDecryptionPassphrase must not be called when "
2192 "IsPassphraseRequired() is false.";
2193 return 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) {
2229 DisableForUser();
2230 } else {
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);
2248 #endif
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;
2258 DisableForUser();
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;
2330 namespace {
2332 class GetAllNodesRequestHelper
2333 : public base::RefCountedThreadSafe<GetAllNodesRequestHelper> {
2334 public:
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);
2343 private:
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()) {
2362 DLOG(WARNING)
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());
2398 callback_.Reset();
2402 } // namespace
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());
2421 } else {
2422 backend_->GetAllNodesForTypes(
2423 directory_types,
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);
2441 // static
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 {
2465 if (!signin_)
2466 return NULL;
2467 return signin_->GetOriginal();
2470 void ProfileSyncService::UnsuppressAndStart() {
2471 DCHECK(profile_);
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,
2492 NotifyObservers();
2494 DVLOG(1) << "ConfigureDataTypeManager not invoked because of an "
2495 << "Unrecoverable error.";
2496 } else {
2497 DVLOG(0) << "ConfigureDataTypeManager not invoked because backend is not "
2498 << "initialized";
2502 syncer::ModelTypeSet ProfileSyncService::GetDataTypesFromPreferenceProviders()
2503 const {
2504 syncer::ModelTypeSet types;
2505 for (std::set<SyncTypePreferenceProvider*>::const_iterator it =
2506 preference_providers_.begin();
2507 it != preference_providers_.end();
2508 ++it) {
2509 types.PutAll((*it)->GetPreferredDataTypes());
2511 return types;
2514 const DataTypeStatusTable& ProfileSyncService::data_type_status_table()
2515 const {
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_) {
2532 case SYNC:
2533 return syncer::SyncManagerFactory::NORMAL;
2534 case BACKUP:
2535 return syncer::SyncManagerFactory::BACKUP;
2536 case ROLLBACK:
2537 return syncer::SyncManagerFactory::ROLLBACK;
2538 case IDLE:
2539 NOTREACHED();
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_;
2579 return status;
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())
2606 return;
2608 clear_browsing_data_.Run(browsing_data_remover_observer_,
2609 profile_,
2610 first_sync_time,
2611 base::Time::Now());
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,
2621 Profile*,
2622 base::Time,
2623 base::Time)> c) {
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;
2650 } else {
2651 LOG(WARNING) << "The following sync URL specified at the command-line "
2652 << "is invalid: " << value;
2656 return result;
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.
2670 if (sync_thread_) {
2671 sync_thread_->message_loop_proxy()->PostTask(
2672 FROM_HERE,
2673 base::Bind(syncer::CheckSyncDbLastModifiedTime,
2674 profile_->GetPath().Append(kSyncBackupDataFolderName),
2675 base::MessageLoopProxy::current(),
2676 base::Bind(&ProfileSyncService::CheckSyncBackupCallback,
2677 weak_factory_.GetWeakPtr())));
2678 } else {
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())));
2688 #endif
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(
2706 FROM_HERE,
2707 base::Bind(base::IgnoreResult(base::DeleteFile),
2708 profile_->GetPath().Append(kSyncBackupDataFolderName),
2709 true));
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();