profile_sync_service.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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. 4 5#include "chrome/browser/sync/profile_sync_service.h" 6 7#include <cstddef> 8#include <map> 9#include <vector> 10 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/strings/string16.h" 23#include "base/strings/stringprintf.h" 24#include "base/threading/thread_restrictions.h" 25#include "build/build_config.h" 26#include "chrome/browser/bookmarks/enhanced_bookmarks_features.h" 27#include "chrome/browser/browser_process.h" 28#include "chrome/browser/browsing_data/browsing_data_helper.h" 29#include "chrome/browser/chrome_notification_types.h" 30#include "chrome/browser/defaults.h" 31#include "chrome/browser/invalidation/profile_invalidation_provider_factory.h" 32#include "chrome/browser/net/chrome_cookie_notification_details.h" 33#include "chrome/browser/password_manager/password_store_factory.h" 34#include "chrome/browser/prefs/chrome_pref_service_factory.h" 35#include "chrome/browser/prefs/pref_service_syncable.h" 36#include "chrome/browser/profiles/profile.h" 37#include "chrome/browser/services/gcm/gcm_profile_service.h" 38#include "chrome/browser/services/gcm/gcm_profile_service_factory.h" 39#include "chrome/browser/signin/about_signin_internals_factory.h" 40#include "chrome/browser/signin/chrome_signin_client_factory.h" 41#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 42#include "chrome/browser/signin/signin_manager_factory.h" 43#include "chrome/browser/sync/backend_migrator.h" 44#include "chrome/browser/sync/glue/chrome_report_unrecoverable_error.h" 45#include "chrome/browser/sync/glue/favicon_cache.h" 46#include "chrome/browser/sync/glue/sync_backend_host.h" 47#include "chrome/browser/sync/glue/sync_backend_host_impl.h" 48#include "chrome/browser/sync/glue/sync_start_util.h" 49#include "chrome/browser/sync/glue/typed_url_data_type_controller.h" 50#include "chrome/browser/sync/profile_sync_components_factory_impl.h" 51#include "chrome/browser/sync/sessions/notification_service_sessions_router.h" 52#include "chrome/browser/sync/supervised_user_signin_manager_wrapper.h" 53#include "chrome/browser/sync/sync_error_controller.h" 54#include "chrome/browser/sync/sync_type_preference_provider.h" 55#include "chrome/browser/ui/browser.h" 56#include "chrome/browser/ui/browser_list.h" 57#include "chrome/browser/ui/browser_window.h" 58#include "chrome/browser/ui/global_error/global_error_service.h" 59#include "chrome/browser/ui/global_error/global_error_service_factory.h" 60#include "chrome/common/chrome_switches.h" 61#include "chrome/common/chrome_version_info.h" 62#include "chrome/common/pref_names.h" 63#include "chrome/common/url_constants.h" 64#include "chrome/grit/generated_resources.h" 65#include "components/gcm_driver/gcm_driver.h" 66#include "components/invalidation/invalidation_service.h" 67#include "components/invalidation/profile_invalidation_provider.h" 68#include "components/password_manager/core/browser/password_store.h" 69#include "components/pref_registry/pref_registry_syncable.h" 70#include "components/signin/core/browser/about_signin_internals.h" 71#include "components/signin/core/browser/profile_oauth2_token_service.h" 72#include "components/signin/core/browser/signin_manager.h" 73#include "components/signin/core/browser/signin_metrics.h" 74#include "components/sync_driver/change_processor.h" 75#include "components/sync_driver/data_type_controller.h" 76#include "components/sync_driver/device_info.h" 77#include "components/sync_driver/pref_names.h" 78#include "components/sync_driver/system_encryptor.h" 79#include "components/sync_driver/user_selectable_sync_type.h" 80#include "content/public/browser/browser_thread.h" 81#include "content/public/browser/notification_details.h" 82#include "content/public/browser/notification_service.h" 83#include "content/public/browser/notification_source.h" 84#include "net/cookies/cookie_monster.h" 85#include "net/url_request/url_request_context_getter.h" 86#include "sync/api/sync_error.h" 87#include "sync/internal_api/public/configure_reason.h" 88#include "sync/internal_api/public/http_bridge_network_resources.h" 89#include "sync/internal_api/public/network_resources.h" 90#include "sync/internal_api/public/sessions/type_debug_info_observer.h" 91#include "sync/internal_api/public/shutdown_reason.h" 92#include "sync/internal_api/public/sync_context_proxy.h" 93#include "sync/internal_api/public/sync_encryption_handler.h" 94#include "sync/internal_api/public/util/experiments.h" 95#include "sync/internal_api/public/util/sync_db_util.h" 96#include "sync/internal_api/public/util/sync_string_conversions.h" 97#include "sync/js/js_event_details.h" 98#include "sync/util/cryptographer.h" 99#include "ui/base/l10n/l10n_util.h" 100#include "ui/base/l10n/time_format.h" 101 102#if defined(OS_ANDROID) 103#include "sync/internal_api/public/read_transaction.h" 104#endif 105 106using browser_sync::NotificationServiceSessionsRouter; 107using browser_sync::ProfileSyncServiceStartBehavior; 108using browser_sync::SessionsSyncManager; 109using browser_sync::SyncBackendHost; 110using sync_driver::ChangeProcessor; 111using sync_driver::DataTypeController; 112using sync_driver::DataTypeManager; 113using sync_driver::DataTypeStatusTable; 114using sync_driver::DeviceInfoSyncService; 115using syncer::ModelType; 116using syncer::ModelTypeSet; 117using syncer::JsBackend; 118using syncer::JsController; 119using syncer::JsEventDetails; 120using syncer::JsEventHandler; 121using syncer::ModelSafeRoutingInfo; 122using syncer::SyncCredentials; 123using syncer::SyncProtocolError; 124using syncer::WeakHandle; 125 126typedef GoogleServiceAuthError AuthError; 127 128const char* ProfileSyncService::kSyncServerUrl = 129 "https://clients4.google.com/chrome-sync"; 130 131const char* ProfileSyncService::kDevServerUrl = 132 "https://clients4.google.com/chrome-sync/dev"; 133 134const char kSyncUnrecoverableErrorHistogram[] = 135 "Sync.UnrecoverableErrors"; 136 137const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = { 138 // Number of initial errors (in sequence) to ignore before applying 139 // exponential back-off rules. 140 0, 141 142 // Initial delay for exponential back-off in ms. 143 2000, 144 145 // Factor by which the waiting time will be multiplied. 146 2, 147 148 // Fuzzing percentage. ex: 10% will spread requests randomly 149 // between 90%-100% of the calculated time. 150 0.2, // 20% 151 152 // Maximum amount of time we are willing to delay our request in ms. 153 // TODO(pavely): crbug.com/246686 ProfileSyncService should retry 154 // RequestAccessToken on connection state change after backoff 155 1000 * 3600 * 4, // 4 hours. 156 157 // Time to keep an entry from being discarded even when it 158 // has no significant state, -1 to never discard. 159 -1, 160 161 // Don't use initial delay unless the last request was an error. 162 false, 163}; 164 165static const base::FilePath::CharType kSyncDataFolderName[] = 166 FILE_PATH_LITERAL("Sync Data"); 167 168static const base::FilePath::CharType kSyncBackupDataFolderName[] = 169 FILE_PATH_LITERAL("Sync Data Backup"); 170 171namespace { 172 173void ClearBrowsingData(BrowsingDataRemover::Observer* observer, 174 Profile* profile, 175 base::Time start, 176 base::Time end) { 177 // BrowsingDataRemover deletes itself when it's done. 178 BrowsingDataRemover* remover = BrowsingDataRemover::CreateForRange( 179 profile, start, end); 180 if (observer) 181 remover->AddObserver(observer); 182 remover->Remove(BrowsingDataRemover::REMOVE_ALL, 183 BrowsingDataHelper::ALL); 184 185 scoped_refptr<password_manager::PasswordStore> password = 186 PasswordStoreFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS); 187 password->RemoveLoginsSyncedBetween(start, end); 188} 189 190} // anonymous namespace 191 192bool ShouldShowActionOnUI( 193 const syncer::SyncProtocolError& error) { 194 return (error.action != syncer::UNKNOWN_ACTION && 195 error.action != syncer::DISABLE_SYNC_ON_CLIENT && 196 error.action != syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT); 197} 198 199ProfileSyncService::ProfileSyncService( 200 scoped_ptr<ProfileSyncComponentsFactory> factory, 201 Profile* profile, 202 scoped_ptr<SupervisedUserSigninManagerWrapper> signin_wrapper, 203 ProfileOAuth2TokenService* oauth2_token_service, 204 ProfileSyncServiceStartBehavior start_behavior) 205 : OAuth2TokenService::Consumer("sync"), 206 last_auth_error_(AuthError::AuthErrorNone()), 207 passphrase_required_reason_(syncer::REASON_PASSPHRASE_NOT_REQUIRED), 208 factory_(factory.Pass()), 209 profile_(profile), 210 sync_prefs_(profile_->GetPrefs()), 211 sync_service_url_(GetSyncServiceURL(*CommandLine::ForCurrentProcess())), 212 is_first_time_sync_configure_(false), 213 backend_initialized_(false), 214 sync_disabled_by_admin_(false), 215 is_auth_in_progress_(false), 216 signin_(signin_wrapper.Pass()), 217 unrecoverable_error_reason_(ERROR_REASON_UNSET), 218 expect_sync_configuration_aborted_(false), 219 encrypted_types_(syncer::SyncEncryptionHandler::SensitiveTypes()), 220 encrypt_everything_(false), 221 encryption_pending_(false), 222 configure_status_(DataTypeManager::UNKNOWN), 223 oauth2_token_service_(oauth2_token_service), 224 request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy), 225 weak_factory_(this), 226 startup_controller_weak_factory_(this), 227 connection_status_(syncer::CONNECTION_NOT_ATTEMPTED), 228 last_get_token_error_(GoogleServiceAuthError::AuthErrorNone()), 229 network_resources_(new syncer::HttpBridgeNetworkResources), 230 startup_controller_( 231 start_behavior, 232 oauth2_token_service, 233 &sync_prefs_, 234 signin_.get(), 235 base::Bind(&ProfileSyncService::StartUpSlowBackendComponents, 236 startup_controller_weak_factory_.GetWeakPtr(), 237 SYNC)), 238 backup_rollback_controller_( 239 &sync_prefs_, 240 signin_.get(), 241 base::Bind(&ProfileSyncService::StartUpSlowBackendComponents, 242 startup_controller_weak_factory_.GetWeakPtr(), 243 BACKUP), 244 base::Bind(&ProfileSyncService::StartUpSlowBackendComponents, 245 startup_controller_weak_factory_.GetWeakPtr(), 246 ROLLBACK)), 247 backend_mode_(IDLE), 248 need_backup_(false), 249 backup_finished_(false), 250 clear_browsing_data_(base::Bind(&ClearBrowsingData)), 251 browsing_data_remover_observer_(NULL) { 252 DCHECK(profile); 253 syncer::SyncableService::StartSyncFlare flare( 254 sync_start_util::GetFlareForSyncableService(profile->GetPath())); 255 scoped_ptr<browser_sync::LocalSessionEventRouter> router( 256 new NotificationServiceSessionsRouter(profile, flare)); 257 258 DCHECK(factory_.get()); 259 local_device_ = factory_->CreateLocalDeviceInfoProvider(); 260 sessions_sync_manager_.reset( 261 new SessionsSyncManager(profile, local_device_.get(), router.Pass())); 262 device_info_sync_service_.reset( 263 new DeviceInfoSyncService(local_device_.get())); 264} 265 266ProfileSyncService::~ProfileSyncService() { 267 sync_prefs_.RemoveSyncPrefObserver(this); 268 // Shutdown() should have been called before destruction. 269 CHECK(!backend_initialized_); 270} 271 272bool ProfileSyncService::IsSyncEnabledAndLoggedIn() { 273 // Exit if sync is disabled. 274 if (IsManaged() || sync_prefs_.IsStartSuppressed()) 275 return false; 276 277 // Sync is logged in if there is a non-empty effective username. 278 return !signin_->GetEffectiveUsername().empty(); 279} 280 281bool ProfileSyncService::IsOAuthRefreshTokenAvailable() { 282 if (!oauth2_token_service_) 283 return false; 284 285 return oauth2_token_service_->RefreshTokenIsAvailable( 286 signin_->GetAccountIdToUse()); 287} 288 289void ProfileSyncService::Initialize() { 290 // We clear this here (vs Shutdown) because we want to remember that an error 291 // happened on shutdown so we can display details (message, location) about it 292 // in about:sync. 293 ClearStaleErrors(); 294 295 sync_prefs_.AddSyncPrefObserver(this); 296 297 // For now, the only thing we can do through policy is to turn sync off. 298 if (IsManaged()) { 299 DisableForUser(); 300 return; 301 } 302 303 RegisterAuthNotifications(); 304 305 if (!HasSyncSetupCompleted() || signin_->GetEffectiveUsername().empty()) { 306 // Clean up in case of previous crash / setup abort / signout. 307 DisableForUser(); 308 } 309 310 TrySyncDatatypePrefRecovery(); 311 312 last_synced_time_ = sync_prefs_.GetLastSyncedTime(); 313 314#if defined(OS_CHROMEOS) 315 std::string bootstrap_token = sync_prefs_.GetEncryptionBootstrapToken(); 316 if (bootstrap_token.empty()) { 317 sync_prefs_.SetEncryptionBootstrapToken( 318 sync_prefs_.GetSpareBootstrapToken()); 319 } 320#endif 321 322#if !defined(OS_ANDROID) 323 DCHECK(sync_error_controller_ == NULL) 324 << "Initialize() called more than once."; 325 sync_error_controller_.reset(new SyncErrorController(this)); 326 AddObserver(sync_error_controller_.get()); 327#endif 328 329 bool running_rollback = false; 330 if (browser_sync::BackupRollbackController::IsBackupEnabled()) { 331 // Backup is needed if user's not signed in or signed in but previous 332 // backup didn't finish, i.e. backend didn't switch from backup to sync. 333 need_backup_ = signin_->GetEffectiveUsername().empty() || 334 sync_prefs_.GetFirstSyncTime().is_null(); 335 336 // Try to resume rollback if it didn't finish in last session. 337 running_rollback = backup_rollback_controller_.StartRollback(); 338 } else { 339 need_backup_ = false; 340 } 341 342#if defined(ENABLE_PRE_SYNC_BACKUP) 343 if (!running_rollback && signin_->GetEffectiveUsername().empty()) { 344 CleanUpBackup(); 345 } 346#else 347 DCHECK(!running_rollback); 348#endif 349 350 startup_controller_.Reset(GetRegisteredDataTypes()); 351 startup_controller_.TryStart(); 352} 353 354void ProfileSyncService::TrySyncDatatypePrefRecovery() { 355 DCHECK(!sync_initialized()); 356 if (!HasSyncSetupCompleted()) 357 return; 358 359 // There was a bug where OnUserChoseDatatypes was not properly called on 360 // configuration (see crbug.com/154940). We detect this by checking whether 361 // kSyncKeepEverythingSynced has a default value. If so, and sync setup has 362 // completed, it means sync was not properly configured, so we manually 363 // set kSyncKeepEverythingSynced. 364 PrefService* const pref_service = profile_->GetPrefs(); 365 if (!pref_service) 366 return; 367 if (GetPreferredDataTypes().Size() > 1) 368 return; 369 370 const PrefService::Preference* keep_everything_synced = 371 pref_service->FindPreference( 372 sync_driver::prefs::kSyncKeepEverythingSynced); 373 // This will be false if the preference was properly set or if it's controlled 374 // by policy. 375 if (!keep_everything_synced->IsDefaultValue()) 376 return; 377 378 // kSyncKeepEverythingSynced was not properly set. Set it and the preferred 379 // types now, before we configure. 380 UMA_HISTOGRAM_COUNTS("Sync.DatatypePrefRecovery", 1); 381 sync_prefs_.SetKeepEverythingSynced(true); 382 syncer::ModelTypeSet registered_types = GetRegisteredDataTypes(); 383} 384 385void ProfileSyncService::StartSyncingWithServer() { 386 if (backend_) 387 backend_->StartSyncingWithServer(); 388} 389 390void ProfileSyncService::RegisterAuthNotifications() { 391 oauth2_token_service_->AddObserver(this); 392 if (signin()) 393 signin()->AddObserver(this); 394} 395 396void ProfileSyncService::UnregisterAuthNotifications() { 397 if (signin()) 398 signin()->RemoveObserver(this); 399 oauth2_token_service_->RemoveObserver(this); 400} 401 402void ProfileSyncService::RegisterDataTypeController( 403 DataTypeController* data_type_controller) { 404 DCHECK_EQ( 405 directory_data_type_controllers_.count(data_type_controller->type()), 406 0U); 407 DCHECK(!GetRegisteredNonBlockingDataTypes().Has( 408 data_type_controller->type())); 409 directory_data_type_controllers_[data_type_controller->type()] = 410 data_type_controller; 411} 412 413void ProfileSyncService::RegisterNonBlockingType(syncer::ModelType type) { 414 DCHECK_EQ(directory_data_type_controllers_.count(type), 0U) 415 << "Duplicate registration of type " << ModelTypeToString(type); 416 417 // TODO(rlarocque): Set the enable flag properly when crbug.com/368834 is 418 // fixed and we have some way of telling whether or not this type should be 419 // enabled. 420 non_blocking_data_type_manager_.RegisterType(type, false); 421} 422 423void ProfileSyncService::InitializeNonBlockingType( 424 syncer::ModelType type, 425 const scoped_refptr<base::SequencedTaskRunner>& task_runner, 426 const base::WeakPtr<syncer::ModelTypeSyncProxyImpl>& type_sync_proxy) { 427 non_blocking_data_type_manager_.InitializeType( 428 type, task_runner, type_sync_proxy); 429} 430 431bool ProfileSyncService::IsDataTypeControllerRunning( 432 syncer::ModelType type) const { 433 DataTypeController::TypeMap::const_iterator iter = 434 directory_data_type_controllers_.find(type); 435 if (iter == directory_data_type_controllers_.end()) { 436 return false; 437 } 438 return iter->second->state() == DataTypeController::RUNNING; 439} 440 441browser_sync::OpenTabsUIDelegate* ProfileSyncService::GetOpenTabsUIDelegate() { 442 if (!IsDataTypeControllerRunning(syncer::SESSIONS)) 443 return NULL; 444 return sessions_sync_manager_.get(); 445} 446 447browser_sync::FaviconCache* ProfileSyncService::GetFaviconCache() { 448 return sessions_sync_manager_->GetFaviconCache(); 449} 450 451browser_sync::SyncedWindowDelegatesGetter* 452ProfileSyncService::GetSyncedWindowDelegatesGetter() const { 453 return sessions_sync_manager_->GetSyncedWindowDelegatesGetter(); 454} 455 456sync_driver::DeviceInfoTracker* ProfileSyncService::GetDeviceInfoTracker() 457 const { 458 if (!IsDataTypeControllerRunning(syncer::DEVICE_INFO)) 459 return NULL; 460 461 return device_info_sync_service_.get(); 462} 463 464sync_driver::LocalDeviceInfoProvider* 465ProfileSyncService::GetLocalDeviceInfoProvider() { 466 return local_device_.get(); 467} 468 469void ProfileSyncService::GetDataTypeControllerStates( 470 DataTypeController::StateMap* state_map) const { 471 for (DataTypeController::TypeMap::const_iterator iter = 472 directory_data_type_controllers_.begin(); 473 iter != directory_data_type_controllers_.end(); 474 ++iter) 475 (*state_map)[iter->first] = iter->second.get()->state(); 476} 477 478SyncCredentials ProfileSyncService::GetCredentials() { 479 SyncCredentials credentials; 480 if (backend_mode_ == SYNC) { 481 credentials.email = signin_->GetEffectiveUsername(); 482 DCHECK(!credentials.email.empty()); 483 credentials.sync_token = access_token_; 484 485 if (credentials.sync_token.empty()) 486 credentials.sync_token = "credentials_lost"; 487 488 credentials.scope_set.insert(signin_->GetSyncScopeToUse()); 489 } 490 491 return credentials; 492} 493 494bool ProfileSyncService::ShouldDeleteSyncFolder() { 495 switch (backend_mode_) { 496 case SYNC: 497 return !HasSyncSetupCompleted(); 498 case BACKUP: 499 return true; 500 case ROLLBACK: 501 return false; 502 case IDLE: 503 NOTREACHED(); 504 return true; 505 } 506 return true; 507} 508 509void ProfileSyncService::InitializeBackend(bool delete_stale_data) { 510 if (!backend_) { 511 NOTREACHED(); 512 return; 513 } 514 515 SyncCredentials credentials = GetCredentials(); 516 517 scoped_refptr<net::URLRequestContextGetter> request_context_getter( 518 profile_->GetRequestContext()); 519 520 if (backend_mode_ == SYNC && delete_stale_data) 521 ClearStaleErrors(); 522 523 scoped_ptr<syncer::UnrecoverableErrorHandler> 524 backend_unrecoverable_error_handler( 525 new browser_sync::BackendUnrecoverableErrorHandler( 526 MakeWeakHandle(weak_factory_.GetWeakPtr()))); 527 528 backend_->Initialize( 529 this, 530 sync_thread_.Pass(), 531 GetJsEventHandler(), 532 sync_service_url_, 533 credentials, 534 delete_stale_data, 535 scoped_ptr<syncer::SyncManagerFactory>( 536 new syncer::SyncManagerFactory(GetManagerType())).Pass(), 537 backend_unrecoverable_error_handler.Pass(), 538 &browser_sync::ChromeReportUnrecoverableError, 539 network_resources_.get()); 540} 541 542bool ProfileSyncService::IsEncryptedDatatypeEnabled() const { 543 if (encryption_pending()) 544 return true; 545 const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes(); 546 const syncer::ModelTypeSet encrypted_types = GetEncryptedDataTypes(); 547 DCHECK(encrypted_types.Has(syncer::PASSWORDS)); 548 return !Intersection(preferred_types, encrypted_types).Empty(); 549} 550 551void ProfileSyncService::OnSyncConfigureRetry() { 552 // Note: in order to handle auth failures that arise before the backend is 553 // initialized (e.g. from invalidation notifier, or downloading new control 554 // types), we have to gracefully handle configuration retries at all times. 555 // At this point an auth error badge should be shown, which once resolved 556 // will trigger a new sync cycle. 557 NotifyObservers(); 558} 559 560void ProfileSyncService::OnProtocolEvent( 561 const syncer::ProtocolEvent& event) { 562 FOR_EACH_OBSERVER(browser_sync::ProtocolEventObserver, 563 protocol_event_observers_, 564 OnProtocolEvent(event)); 565} 566 567void ProfileSyncService::OnDirectoryTypeCommitCounterUpdated( 568 syncer::ModelType type, 569 const syncer::CommitCounters& counters) { 570 FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver, 571 type_debug_info_observers_, 572 OnCommitCountersUpdated(type, counters)); 573} 574 575void ProfileSyncService::OnDirectoryTypeUpdateCounterUpdated( 576 syncer::ModelType type, 577 const syncer::UpdateCounters& counters) { 578 FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver, 579 type_debug_info_observers_, 580 OnUpdateCountersUpdated(type, counters)); 581} 582 583void ProfileSyncService::OnDirectoryTypeStatusCounterUpdated( 584 syncer::ModelType type, 585 const syncer::StatusCounters& counters) { 586 FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver, 587 type_debug_info_observers_, 588 OnStatusCountersUpdated(type, counters)); 589} 590 591void ProfileSyncService::OnDataTypeRequestsSyncStartup( 592 syncer::ModelType type) { 593 DCHECK(syncer::UserTypes().Has(type)); 594 if (backend_.get()) { 595 DVLOG(1) << "A data type requested sync startup, but it looks like " 596 "something else beat it to the punch."; 597 return; 598 } 599 600 if (!GetPreferredDataTypes().Has(type)) { 601 // We can get here as datatype SyncableServices are typically wired up 602 // to the native datatype even if sync isn't enabled. 603 DVLOG(1) << "Dropping sync startup request because type " 604 << syncer::ModelTypeToString(type) << "not enabled."; 605 return; 606 } 607 608 startup_controller_.OnDataTypeRequestsSyncStartup(type); 609} 610 611void ProfileSyncService::StartUpSlowBackendComponents( 612 ProfileSyncService::BackendMode mode) { 613 DCHECK_NE(IDLE, mode); 614 if (backend_mode_ == mode) { 615 return; 616 } 617 618 // Backend mode transition rules: 619 // * can transit from IDLE to any other non-IDLE mode. 620 // * forbidden to transit from SYNC to any other mode, i.e. SYNC backend must 621 // be explicitly shut down before backup/rollback starts. 622 // * can not transit out of ROLLBACK mode until rollback is finished 623 // (successfully or unsuccessfully). 624 // * can not transit out of BACKUP mode until backup is finished 625 // (successfully or unsuccessfully). 626 // * if backup is needed, can only transit to SYNC if backup is finished, 627 628 if (backend_mode_ == SYNC) { 629 LOG(DFATAL) << "Shouldn't switch from mode SYNC to mode " << mode; 630 return; 631 } 632 633 if (backend_mode_ == ROLLBACK || 634 (backend_mode_ == BACKUP && !backup_finished_)) { 635 // Wait for rollback/backup to finish before start new backend. 636 return; 637 } 638 639 if (mode == SYNC && NeedBackup() && !backup_finished_) { 640 if (backend_mode_ != BACKUP) 641 backup_rollback_controller_.StartBackup(); 642 return; 643 } 644 645 DVLOG(1) << "Start backend mode: " << mode; 646 647 if (backend_) { 648 if (mode == SYNC) 649 ShutdownImpl(syncer::SWITCH_MODE_SYNC); 650 else 651 ShutdownImpl(syncer::STOP_SYNC); 652 } 653 654 backend_mode_ = mode; 655 656 if (backend_mode_ == BACKUP) 657 backup_start_time_ = base::Time::Now(); 658 659 if (backend_mode_ == SYNC && !backup_start_time_.is_null()) { 660 UMA_HISTOGRAM_MEDIUM_TIMES("Sync.FirstSyncDelayByBackup", 661 base::Time::Now() - backup_start_time_); 662 backup_start_time_ = base::Time(); 663 } 664 665 if (backend_mode_ == ROLLBACK) 666 ClearBrowsingDataSinceFirstSync(); 667 else if (backend_mode_ == SYNC) 668 CheckSyncBackupIfNeeded(); 669 670 base::FilePath sync_folder = backend_mode_ == SYNC ? 671 base::FilePath(kSyncDataFolderName) : 672 base::FilePath(kSyncBackupDataFolderName); 673 674 invalidation::InvalidationService* invalidator = NULL; 675 if (backend_mode_ == SYNC) { 676 invalidation::ProfileInvalidationProvider* provider = 677 invalidation::ProfileInvalidationProviderFactory::GetForProfile( 678 profile_); 679 if (provider) 680 invalidator = provider->GetInvalidationService(); 681 } 682 683 backend_.reset( 684 factory_->CreateSyncBackendHost( 685 profile_->GetDebugName(), 686 profile_, 687 invalidator, 688 sync_prefs_.AsWeakPtr(), 689 sync_folder)); 690 691 // Initialize the backend. Every time we start up a new SyncBackendHost, 692 // we'll want to start from a fresh SyncDB, so delete any old one that might 693 // be there. 694 InitializeBackend(ShouldDeleteSyncFolder()); 695 696 UpdateFirstSyncTimePref(); 697 698 NotifyObservers(); 699} 700 701void ProfileSyncService::OnGetTokenSuccess( 702 const OAuth2TokenService::Request* request, 703 const std::string& access_token, 704 const base::Time& expiration_time) { 705 DCHECK_EQ(access_token_request_, request); 706 access_token_request_.reset(); 707 access_token_ = access_token; 708 token_receive_time_ = base::Time::Now(); 709 last_get_token_error_ = GoogleServiceAuthError::AuthErrorNone(); 710 711 if (sync_prefs_.SyncHasAuthError()) { 712 sync_prefs_.SetSyncAuthError(false); 713 UMA_HISTOGRAM_ENUMERATION("Sync.SyncAuthError", 714 AUTH_ERROR_FIXED, 715 AUTH_ERROR_LIMIT); 716 } 717 718 if (HasSyncingBackend()) 719 backend_->UpdateCredentials(GetCredentials()); 720 else 721 startup_controller_.TryStart(); 722} 723 724void ProfileSyncService::OnGetTokenFailure( 725 const OAuth2TokenService::Request* request, 726 const GoogleServiceAuthError& error) { 727 DCHECK_EQ(access_token_request_, request); 728 DCHECK_NE(error.state(), GoogleServiceAuthError::NONE); 729 access_token_request_.reset(); 730 last_get_token_error_ = error; 731 switch (error.state()) { 732 case GoogleServiceAuthError::CONNECTION_FAILED: 733 case GoogleServiceAuthError::REQUEST_CANCELED: 734 case GoogleServiceAuthError::SERVICE_ERROR: 735 case GoogleServiceAuthError::SERVICE_UNAVAILABLE: { 736 // Transient error. Retry after some time. 737 request_access_token_backoff_.InformOfRequest(false); 738 next_token_request_time_ = base::Time::Now() + 739 request_access_token_backoff_.GetTimeUntilRelease(); 740 request_access_token_retry_timer_.Start( 741 FROM_HERE, 742 request_access_token_backoff_.GetTimeUntilRelease(), 743 base::Bind(&ProfileSyncService::RequestAccessToken, 744 weak_factory_.GetWeakPtr())); 745 NotifyObservers(); 746 break; 747 } 748 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: { 749 if (!sync_prefs_.SyncHasAuthError()) { 750 sync_prefs_.SetSyncAuthError(true); 751 UMA_HISTOGRAM_ENUMERATION("Sync.SyncAuthError", 752 AUTH_ERROR_ENCOUNTERED, 753 AUTH_ERROR_LIMIT); 754 } 755 // Fallthrough. 756 } 757 default: { 758 if (error.state() != GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) { 759 LOG(ERROR) << "Unexpected persistent error: " << error.ToString(); 760 } 761 // Show error to user. 762 UpdateAuthErrorState(error); 763 } 764 } 765} 766 767void ProfileSyncService::OnRefreshTokenAvailable( 768 const std::string& account_id) { 769 if (account_id == signin_->GetAccountIdToUse()) 770 OnRefreshTokensLoaded(); 771} 772 773void ProfileSyncService::OnRefreshTokenRevoked( 774 const std::string& account_id) { 775 if (!IsOAuthRefreshTokenAvailable()) { 776 access_token_.clear(); 777 // The additional check around IsOAuthRefreshTokenAvailable() above 778 // prevents us sounding the alarm if we actually have a valid token but 779 // a refresh attempt failed for any variety of reasons 780 // (e.g. flaky network). It's possible the token we do have is also 781 // invalid, but in that case we should already have (or can expect) an 782 // auth error sent from the sync backend. 783 UpdateAuthErrorState( 784 GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED)); 785 } 786} 787 788void ProfileSyncService::OnRefreshTokensLoaded() { 789 // This notification gets fired when OAuth2TokenService loads the tokens 790 // from storage. 791 // Initialize the backend if sync is enabled. If the sync token was 792 // not loaded, GetCredentials() will generate invalid credentials to 793 // cause the backend to generate an auth error (crbug.com/121755). 794 if (HasSyncingBackend()) { 795 RequestAccessToken(); 796 } else { 797 startup_controller_.TryStart(); 798 } 799} 800 801void ProfileSyncService::Shutdown() { 802 UnregisterAuthNotifications(); 803 804 ShutdownImpl(syncer::BROWSER_SHUTDOWN); 805 if (sync_error_controller_) { 806 // Destroy the SyncErrorController when the service shuts down for good. 807 RemoveObserver(sync_error_controller_.get()); 808 sync_error_controller_.reset(); 809 } 810 811 if (sync_thread_) 812 sync_thread_->Stop(); 813} 814 815void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason) { 816 if (!backend_) 817 return; 818 819 non_blocking_data_type_manager_.DisconnectSyncBackend(); 820 821 // First, we spin down the backend to stop change processing as soon as 822 // possible. 823 base::Time shutdown_start_time = base::Time::Now(); 824 backend_->StopSyncingForShutdown(); 825 826 // Stop all data type controllers, if needed. Note that until Stop 827 // completes, it is possible in theory to have a ChangeProcessor apply a 828 // change from a native model. In that case, it will get applied to the sync 829 // database (which doesn't get destroyed until we destroy the backend below) 830 // as an unsynced change. That will be persisted, and committed on restart. 831 if (directory_data_type_manager_) { 832 if (directory_data_type_manager_->state() != DataTypeManager::STOPPED) { 833 // When aborting as part of shutdown, we should expect an aborted sync 834 // configure result, else we'll dcheck when we try to read the sync error. 835 expect_sync_configuration_aborted_ = true; 836 directory_data_type_manager_->Stop(); 837 } 838 directory_data_type_manager_.reset(); 839 } 840 841 // Shutdown the migrator before the backend to ensure it doesn't pull a null 842 // snapshot. 843 migrator_.reset(); 844 sync_js_controller_.AttachJsBackend(WeakHandle<syncer::JsBackend>()); 845 846 // Move aside the backend so nobody else tries to use it while we are 847 // shutting it down. 848 scoped_ptr<SyncBackendHost> doomed_backend(backend_.release()); 849 if (doomed_backend) { 850 sync_thread_ = doomed_backend->Shutdown(reason); 851 doomed_backend.reset(); 852 } 853 base::TimeDelta shutdown_time = base::Time::Now() - shutdown_start_time; 854 UMA_HISTOGRAM_TIMES("Sync.Shutdown.BackendDestroyedTime", shutdown_time); 855 856 weak_factory_.InvalidateWeakPtrs(); 857 858 if (backend_mode_ == SYNC) 859 startup_controller_.Reset(GetRegisteredDataTypes()); 860 861 // Don't let backup block sync regardless backup succeeded or not. 862 if (backend_mode_ == BACKUP) 863 backup_finished_ = true; 864 865 // Sync could be blocked by rollback/backup. Post task to check whether sync 866 // should start after shutting down rollback/backup backend. 867 if ((backend_mode_ == ROLLBACK || backend_mode_ == BACKUP) && 868 reason != syncer::SWITCH_MODE_SYNC && 869 reason != syncer::BROWSER_SHUTDOWN) { 870 base::MessageLoop::current()->PostTask( 871 FROM_HERE, base::Bind(&ProfileSyncService::TryStartSyncAfterBackup, 872 startup_controller_weak_factory_.GetWeakPtr())); 873 } 874 875 // Clear various flags. 876 backend_mode_ = IDLE; 877 expect_sync_configuration_aborted_ = false; 878 is_auth_in_progress_ = false; 879 backend_initialized_ = false; 880 cached_passphrase_.clear(); 881 access_token_.clear(); 882 encryption_pending_ = false; 883 encrypt_everything_ = false; 884 encrypted_types_ = syncer::SyncEncryptionHandler::SensitiveTypes(); 885 passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED; 886 request_access_token_retry_timer_.Stop(); 887 // Revert to "no auth error". 888 if (last_auth_error_.state() != GoogleServiceAuthError::NONE) 889 UpdateAuthErrorState(GoogleServiceAuthError::AuthErrorNone()); 890 891 NotifyObservers(); 892} 893 894void ProfileSyncService::DisableForUser() { 895 // Clear prefs (including SyncSetupHasCompleted) before shutting down so 896 // PSS clients don't think we're set up while we're shutting down. 897 sync_prefs_.ClearPreferences(); 898 ClearUnrecoverableError(); 899 ShutdownImpl(syncer::DISABLE_SYNC); 900} 901 902bool ProfileSyncService::HasSyncSetupCompleted() const { 903 return sync_prefs_.HasSyncSetupCompleted(); 904} 905 906void ProfileSyncService::SetSyncSetupCompleted() { 907 sync_prefs_.SetSyncSetupCompleted(); 908} 909 910void ProfileSyncService::UpdateLastSyncedTime() { 911 last_synced_time_ = base::Time::Now(); 912 sync_prefs_.SetLastSyncedTime(last_synced_time_); 913} 914 915void ProfileSyncService::NotifyObservers() { 916 FOR_EACH_OBSERVER(ProfileSyncServiceBase::Observer, observers_, 917 OnStateChanged()); 918} 919 920void ProfileSyncService::NotifySyncCycleCompleted() { 921 FOR_EACH_OBSERVER(ProfileSyncServiceBase::Observer, observers_, 922 OnSyncCycleCompleted()); 923} 924 925void ProfileSyncService::ClearStaleErrors() { 926 ClearUnrecoverableError(); 927 last_actionable_error_ = SyncProtocolError(); 928 // Clear the data type errors as well. 929 if (directory_data_type_manager_.get()) 930 directory_data_type_manager_->ResetDataTypeErrors(); 931 932} 933 934void ProfileSyncService::ClearUnrecoverableError() { 935 unrecoverable_error_reason_ = ERROR_REASON_UNSET; 936 unrecoverable_error_message_.clear(); 937 unrecoverable_error_location_ = tracked_objects::Location(); 938} 939 940void ProfileSyncService::RegisterNewDataType(syncer::ModelType data_type) { 941 if (directory_data_type_controllers_.count(data_type) > 0) 942 return; 943 NOTREACHED(); 944} 945 946// An invariant has been violated. Transition to an error state where we try 947// to do as little work as possible, to avoid further corruption or crashes. 948void ProfileSyncService::OnUnrecoverableError( 949 const tracked_objects::Location& from_here, 950 const std::string& message) { 951 // Unrecoverable errors that arrive via the syncer::UnrecoverableErrorHandler 952 // interface are assumed to originate within the syncer. 953 unrecoverable_error_reason_ = ERROR_REASON_SYNCER; 954 OnUnrecoverableErrorImpl(from_here, message, true); 955} 956 957void ProfileSyncService::OnUnrecoverableErrorImpl( 958 const tracked_objects::Location& from_here, 959 const std::string& message, 960 bool delete_sync_database) { 961 DCHECK(HasUnrecoverableError()); 962 unrecoverable_error_message_ = message; 963 unrecoverable_error_location_ = from_here; 964 965 UMA_HISTOGRAM_ENUMERATION(kSyncUnrecoverableErrorHistogram, 966 unrecoverable_error_reason_, 967 ERROR_REASON_LIMIT); 968 NotifyObservers(); 969 std::string location; 970 from_here.Write(true, true, &location); 971 LOG(ERROR) 972 << "Unrecoverable error detected at " << location 973 << " -- ProfileSyncService unusable: " << message; 974 975 // Shut all data types down. 976 base::MessageLoop::current()->PostTask(FROM_HERE, 977 base::Bind(&ProfileSyncService::ShutdownImpl, 978 weak_factory_.GetWeakPtr(), 979 delete_sync_database ? 980 syncer::DISABLE_SYNC : syncer::STOP_SYNC)); 981} 982 983void ProfileSyncService::ReenableDatatype(syncer::ModelType type) { 984 DCHECK(backend_initialized_); 985 directory_data_type_manager_->ReenableType(type); 986} 987 988void ProfileSyncService::UpdateBackendInitUMA(bool success) { 989 if (backend_mode_ != SYNC) 990 return; 991 992 is_first_time_sync_configure_ = !HasSyncSetupCompleted(); 993 994 if (is_first_time_sync_configure_) { 995 UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeFirstTimeSuccess", success); 996 } else { 997 UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeRestoreSuccess", success); 998 } 999 1000 base::Time on_backend_initialized_time = base::Time::Now(); 1001 base::TimeDelta delta = on_backend_initialized_time - 1002 startup_controller_.start_backend_time(); 1003 if (is_first_time_sync_configure_) { 1004 UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeFirstTime", delta); 1005 } else { 1006 UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeRestoreTime", delta); 1007 } 1008} 1009 1010void ProfileSyncService::PostBackendInitialization() { 1011 // Never get here for backup / restore. 1012 DCHECK_EQ(backend_mode_, SYNC); 1013 1014 if (last_backup_time_) { 1015 DCHECK(device_info_sync_service_); 1016 device_info_sync_service_->UpdateLocalDeviceBackupTime(*last_backup_time_); 1017 } 1018 1019 if (protocol_event_observers_.might_have_observers()) { 1020 backend_->RequestBufferedProtocolEventsAndEnableForwarding(); 1021 } 1022 1023 non_blocking_data_type_manager_.ConnectSyncBackend( 1024 backend_->GetSyncContextProxy()); 1025 1026 if (type_debug_info_observers_.might_have_observers()) { 1027 backend_->EnableDirectoryTypeDebugInfoForwarding(); 1028 } 1029 1030 // If we have a cached passphrase use it to decrypt/encrypt data now that the 1031 // backend is initialized. We want to call this before notifying observers in 1032 // case this operation affects the "passphrase required" status. 1033 ConsumeCachedPassphraseIfPossible(); 1034 1035 // The very first time the backend initializes is effectively the first time 1036 // we can say we successfully "synced". last_synced_time_ will only be null 1037 // in this case, because the pref wasn't restored on StartUp. 1038 if (last_synced_time_.is_null()) { 1039 UpdateLastSyncedTime(); 1040 } 1041 1042 if (startup_controller_.auto_start_enabled() && !FirstSetupInProgress()) { 1043 // Backend is initialized but we're not in sync setup, so this must be an 1044 // autostart - mark our sync setup as completed and we'll start syncing 1045 // below. 1046 SetSyncSetupCompleted(); 1047 } 1048 1049 // Check HasSyncSetupCompleted() before NotifyObservers() to avoid spurious 1050 // data type configuration because observer may flag setup as complete and 1051 // trigger data type configuration. 1052 if (HasSyncSetupCompleted()) { 1053 ConfigureDataTypeManager(); 1054 } else { 1055 DCHECK(FirstSetupInProgress()); 1056 } 1057 1058 NotifyObservers(); 1059} 1060 1061void ProfileSyncService::OnBackendInitialized( 1062 const syncer::WeakHandle<syncer::JsBackend>& js_backend, 1063 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>& 1064 debug_info_listener, 1065 const std::string& cache_guid, 1066 bool success) { 1067 UpdateBackendInitUMA(success); 1068 1069 if (!success) { 1070 // Something went unexpectedly wrong. Play it safe: stop syncing at once 1071 // and surface error UI to alert the user sync has stopped. 1072 // Keep the directory around for now so that on restart we will retry 1073 // again and potentially succeed in presence of transient file IO failures 1074 // or permissions issues, etc. 1075 // 1076 // TODO(rlarocque): Consider making this UnrecoverableError less special. 1077 // Unlike every other UnrecoverableError, it does not delete our sync data. 1078 // This exception made sense at the time it was implemented, but our new 1079 // directory corruption recovery mechanism makes it obsolete. By the time 1080 // we get here, we will have already tried and failed to delete the 1081 // directory. It would be no big deal if we tried to delete it again. 1082 OnInternalUnrecoverableError(FROM_HERE, 1083 "BackendInitialize failure", 1084 false, 1085 ERROR_REASON_BACKEND_INIT_FAILURE); 1086 return; 1087 } 1088 1089 backend_initialized_ = true; 1090 1091 sync_js_controller_.AttachJsBackend(js_backend); 1092 debug_info_listener_ = debug_info_listener; 1093 1094 SigninClient* signin_client = 1095 ChromeSigninClientFactory::GetForProfile(profile_); 1096 DCHECK(signin_client); 1097 std::string signin_scoped_device_id = 1098 signin_client->GetSigninScopedDeviceId(); 1099 1100 // Initialize local device info. 1101 local_device_->Initialize(cache_guid, signin_scoped_device_id); 1102 1103 DVLOG(1) << "Setting preferred types for non-blocking DTM"; 1104 non_blocking_data_type_manager_.SetPreferredTypes(GetPreferredDataTypes()); 1105 1106 // Give the DataTypeControllers a handle to the now initialized backend 1107 // as a UserShare. 1108 for (DataTypeController::TypeMap::iterator it = 1109 directory_data_type_controllers_.begin(); 1110 it != directory_data_type_controllers_.end(); ++it) { 1111 it->second->OnUserShareReady(GetUserShare()); 1112 } 1113 1114 if (backend_mode_ == BACKUP || backend_mode_ == ROLLBACK) 1115 ConfigureDataTypeManager(); 1116 else 1117 PostBackendInitialization(); 1118} 1119 1120void ProfileSyncService::OnSyncCycleCompleted() { 1121 UpdateLastSyncedTime(); 1122 if (IsDataTypeControllerRunning(syncer::SESSIONS)) { 1123 // Trigger garbage collection of old sessions now that we've downloaded 1124 // any new session data. 1125 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 1126 &SessionsSyncManager::DoGarbageCollection, 1127 base::AsWeakPtr(sessions_sync_manager_.get()))); 1128 } 1129 DVLOG(2) << "Notifying observers sync cycle completed"; 1130 NotifySyncCycleCompleted(); 1131} 1132 1133void ProfileSyncService::OnExperimentsChanged( 1134 const syncer::Experiments& experiments) { 1135 if (current_experiments_.Matches(experiments)) 1136 return; 1137 1138 current_experiments_ = experiments; 1139 1140 // Handle preference-backed experiments first. 1141 if (experiments.gcm_channel_state == syncer::Experiments::SUPPRESSED) { 1142 profile()->GetPrefs()->SetBoolean(prefs::kGCMChannelEnabled, false); 1143 gcm::GCMProfileServiceFactory::GetForProfile(profile())->driver() 1144 ->Disable(); 1145 } else { 1146 profile()->GetPrefs()->ClearPref(prefs::kGCMChannelEnabled); 1147 gcm::GCMProfileServiceFactory::GetForProfile(profile())->driver() 1148 ->Enable(); 1149 } 1150 1151 profile()->GetPrefs()->SetBoolean(prefs::kInvalidationServiceUseGCMChannel, 1152 experiments.gcm_invalidations_enabled); 1153 1154 if (experiments.enhanced_bookmarks_enabled) { 1155 profile_->GetPrefs()->SetString( 1156 sync_driver::prefs::kEnhancedBookmarksExtensionId, 1157 experiments.enhanced_bookmarks_ext_id); 1158 } else { 1159 profile_->GetPrefs()->ClearPref( 1160 sync_driver::prefs::kEnhancedBookmarksExtensionId); 1161 } 1162 UpdateBookmarksExperimentState( 1163 profile_->GetPrefs(), g_browser_process->local_state(), true, 1164 experiments.enhanced_bookmarks_enabled ? BOOKMARKS_EXPERIMENT_ENABLED : 1165 BOOKMARKS_EXPERIMENT_NONE); 1166 1167 // If this is a first time sync for a client, this will be called before 1168 // OnBackendInitialized() to ensure the new datatypes are available at sync 1169 // setup. As a result, the migrator won't exist yet. This is fine because for 1170 // first time sync cases we're only concerned with making the datatype 1171 // available. 1172 if (migrator_.get() && 1173 migrator_->state() != browser_sync::BackendMigrator::IDLE) { 1174 DVLOG(1) << "Dropping OnExperimentsChanged due to migrator busy."; 1175 return; 1176 } 1177 1178 const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes(); 1179 syncer::ModelTypeSet to_add; 1180 const syncer::ModelTypeSet to_register = 1181 Difference(to_add, registered_types); 1182 DVLOG(2) << "OnExperimentsChanged called with types: " 1183 << syncer::ModelTypeSetToString(to_add); 1184 DVLOG(2) << "Enabling types: " << syncer::ModelTypeSetToString(to_register); 1185 1186 for (syncer::ModelTypeSet::Iterator it = to_register.First(); 1187 it.Good(); it.Inc()) { 1188 // Received notice to enable experimental type. Check if the type is 1189 // registered, and if not register a new datatype controller. 1190 RegisterNewDataType(it.Get()); 1191 } 1192 1193 // Check if the user has "Keep Everything Synced" enabled. If so, we want 1194 // to turn on all experimental types if they're not already on. Otherwise we 1195 // leave them off. 1196 // Note: if any types are already registered, we don't turn them on. This 1197 // covers the case where we're already in the process of reconfiguring 1198 // to turn an experimental type on. 1199 if (sync_prefs_.HasKeepEverythingSynced()) { 1200 // Mark all data types as preferred. 1201 sync_prefs_.SetPreferredDataTypes(registered_types, registered_types); 1202 1203 // Only automatically turn on types if we have already finished set up. 1204 // Otherwise, just leave the experimental types on by default. 1205 if (!to_register.Empty() && HasSyncSetupCompleted() && migrator_) { 1206 DVLOG(1) << "Dynamically enabling new datatypes: " 1207 << syncer::ModelTypeSetToString(to_register); 1208 OnMigrationNeededForTypes(to_register); 1209 } 1210 } 1211} 1212 1213void ProfileSyncService::UpdateAuthErrorState(const AuthError& error) { 1214 is_auth_in_progress_ = false; 1215 last_auth_error_ = error; 1216 1217 NotifyObservers(); 1218} 1219 1220namespace { 1221 1222AuthError ConnectionStatusToAuthError( 1223 syncer::ConnectionStatus status) { 1224 switch (status) { 1225 case syncer::CONNECTION_OK: 1226 return AuthError::AuthErrorNone(); 1227 break; 1228 case syncer::CONNECTION_AUTH_ERROR: 1229 return AuthError(AuthError::INVALID_GAIA_CREDENTIALS); 1230 break; 1231 case syncer::CONNECTION_SERVER_ERROR: 1232 return AuthError(AuthError::CONNECTION_FAILED); 1233 break; 1234 default: 1235 NOTREACHED(); 1236 return AuthError(AuthError::CONNECTION_FAILED); 1237 } 1238} 1239 1240} // namespace 1241 1242void ProfileSyncService::OnConnectionStatusChange( 1243 syncer::ConnectionStatus status) { 1244 connection_status_update_time_ = base::Time::Now(); 1245 connection_status_ = status; 1246 if (status == syncer::CONNECTION_AUTH_ERROR) { 1247 // Sync server returned error indicating that access token is invalid. It 1248 // could be either expired or access is revoked. Let's request another 1249 // access token and if access is revoked then request for token will fail 1250 // with corresponding error. If access token is repeatedly reported 1251 // invalid, there may be some issues with server, e.g. authentication 1252 // state is inconsistent on sync and token server. In that case, we 1253 // backoff token requests exponentially to avoid hammering token server 1254 // too much and to avoid getting same token due to token server's caching 1255 // policy. |request_access_token_retry_timer_| is used to backoff request 1256 // triggered by both auth error and failure talking to GAIA server. 1257 // Therefore, we're likely to reach the backoff ceiling more quickly than 1258 // you would expect from looking at the BackoffPolicy if both types of 1259 // errors happen. We shouldn't receive two errors back-to-back without 1260 // attempting a token/sync request in between, thus crank up request delay 1261 // unnecessary. This is because we won't make a sync request if we hit an 1262 // error until GAIA succeeds at sending a new token, and we won't request 1263 // a new token unless sync reports a token failure. But to be safe, don't 1264 // schedule request if this happens. 1265 if (request_access_token_retry_timer_.IsRunning()) { 1266 NOTREACHED(); 1267 } else if (request_access_token_backoff_.failure_count() == 0) { 1268 // First time request without delay. Currently invalid token is used 1269 // to initialize sync backend and we'll always end up here. We don't 1270 // want to delay initialization. 1271 request_access_token_backoff_.InformOfRequest(false); 1272 RequestAccessToken(); 1273 } else { 1274 request_access_token_backoff_.InformOfRequest(false); 1275 request_access_token_retry_timer_.Start( 1276 FROM_HERE, 1277 request_access_token_backoff_.GetTimeUntilRelease(), 1278 base::Bind(&ProfileSyncService::RequestAccessToken, 1279 weak_factory_.GetWeakPtr())); 1280 } 1281 } else { 1282 // Reset backoff time after successful connection. 1283 if (status == syncer::CONNECTION_OK) { 1284 // Request shouldn't be scheduled at this time. But if it is, it's 1285 // possible that sync flips between OK and auth error states rapidly, 1286 // thus hammers token server. To be safe, only reset backoff delay when 1287 // no scheduled request. 1288 if (request_access_token_retry_timer_.IsRunning()) { 1289 NOTREACHED(); 1290 } else { 1291 request_access_token_backoff_.Reset(); 1292 } 1293 } 1294 1295 const GoogleServiceAuthError auth_error = 1296 ConnectionStatusToAuthError(status); 1297 DVLOG(1) << "Connection status change: " << auth_error.ToString(); 1298 UpdateAuthErrorState(auth_error); 1299 } 1300} 1301 1302void ProfileSyncService::StopSyncingPermanently() { 1303 sync_prefs_.SetStartSuppressed(true); 1304 DisableForUser(); 1305} 1306 1307void ProfileSyncService::OnPassphraseRequired( 1308 syncer::PassphraseRequiredReason reason, 1309 const sync_pb::EncryptedData& pending_keys) { 1310 DCHECK(backend_.get()); 1311 DCHECK(backend_->IsNigoriEnabled()); 1312 1313 // TODO(lipalani) : add this check to other locations as well. 1314 if (HasUnrecoverableError()) { 1315 // When unrecoverable error is detected we post a task to shutdown the 1316 // backend. The task might not have executed yet. 1317 return; 1318 } 1319 1320 DVLOG(1) << "Passphrase required with reason: " 1321 << syncer::PassphraseRequiredReasonToString(reason); 1322 passphrase_required_reason_ = reason; 1323 1324 const syncer::ModelTypeSet types = GetPreferredDirectoryDataTypes(); 1325 if (directory_data_type_manager_) { 1326 // Reconfigure without the encrypted types (excluded implicitly via the 1327 // failed datatypes handler). 1328 directory_data_type_manager_->Configure(types, 1329 syncer::CONFIGURE_REASON_CRYPTO); 1330 } 1331 1332 // TODO(rlarocque): Support non-blocking types. http://crbug.com/351005. 1333 1334 // Notify observers that the passphrase status may have changed. 1335 NotifyObservers(); 1336} 1337 1338void ProfileSyncService::OnPassphraseAccepted() { 1339 DVLOG(1) << "Received OnPassphraseAccepted."; 1340 1341 // If the pending keys were resolved via keystore, it's possible we never 1342 // consumed our cached passphrase. Clear it now. 1343 if (!cached_passphrase_.empty()) 1344 cached_passphrase_.clear(); 1345 1346 // Reset passphrase_required_reason_ since we know we no longer require the 1347 // passphrase. We do this here rather than down in ResolvePassphraseRequired() 1348 // because that can be called by OnPassphraseRequired() if no encrypted data 1349 // types are enabled, and we don't want to clobber the true passphrase error. 1350 passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED; 1351 1352 // Make sure the data types that depend on the passphrase are started at 1353 // this time. 1354 const syncer::ModelTypeSet types = GetPreferredDirectoryDataTypes(); 1355 if (directory_data_type_manager_) { 1356 // Re-enable any encrypted types if necessary. 1357 directory_data_type_manager_->Configure(types, 1358 syncer::CONFIGURE_REASON_CRYPTO); 1359 } 1360 1361 // TODO(rlarocque): Support non-blocking types. http://crbug.com/351005. 1362 1363 NotifyObservers(); 1364} 1365 1366void ProfileSyncService::OnEncryptedTypesChanged( 1367 syncer::ModelTypeSet encrypted_types, 1368 bool encrypt_everything) { 1369 encrypted_types_ = encrypted_types; 1370 encrypt_everything_ = encrypt_everything; 1371 DVLOG(1) << "Encrypted types changed to " 1372 << syncer::ModelTypeSetToString(encrypted_types_) 1373 << " (encrypt everything is set to " 1374 << (encrypt_everything_ ? "true" : "false") << ")"; 1375 DCHECK(encrypted_types_.Has(syncer::PASSWORDS)); 1376 1377 NotifyObservers(); 1378} 1379 1380void ProfileSyncService::OnEncryptionComplete() { 1381 DVLOG(1) << "Encryption complete"; 1382 if (encryption_pending_ && encrypt_everything_) { 1383 encryption_pending_ = false; 1384 // This is to nudge the integration tests when encryption is 1385 // finished. 1386 NotifyObservers(); 1387 } 1388} 1389 1390void ProfileSyncService::OnMigrationNeededForTypes( 1391 syncer::ModelTypeSet types) { 1392 DCHECK(backend_initialized_); 1393 DCHECK(directory_data_type_manager_.get()); 1394 1395 // Migrator must be valid, because we don't sync until it is created and this 1396 // callback originates from a sync cycle. 1397 migrator_->MigrateTypes(types); 1398} 1399 1400void ProfileSyncService::OnActionableError(const SyncProtocolError& error) { 1401 last_actionable_error_ = error; 1402 DCHECK_NE(last_actionable_error_.action, 1403 syncer::UNKNOWN_ACTION); 1404 switch (error.action) { 1405 case syncer::UPGRADE_CLIENT: 1406 case syncer::CLEAR_USER_DATA_AND_RESYNC: 1407 case syncer::ENABLE_SYNC_ON_ACCOUNT: 1408 case syncer::STOP_AND_RESTART_SYNC: 1409 // TODO(lipalani) : if setup in progress we want to display these 1410 // actions in the popup. The current experience might not be optimal for 1411 // the user. We just dismiss the dialog. 1412 if (startup_controller_.setup_in_progress()) { 1413 StopSyncingPermanently(); 1414 expect_sync_configuration_aborted_ = true; 1415 } 1416 // Trigger an unrecoverable error to stop syncing. 1417 OnInternalUnrecoverableError(FROM_HERE, 1418 last_actionable_error_.error_description, 1419 true, 1420 ERROR_REASON_ACTIONABLE_ERROR); 1421 break; 1422 case syncer::DISABLE_SYNC_AND_ROLLBACK: 1423 backup_rollback_controller_.OnRollbackReceived(); 1424 // Fall through to shutdown backend and sign user out. 1425 case syncer::DISABLE_SYNC_ON_CLIENT: 1426 StopSyncingPermanently(); 1427#if !defined(OS_CHROMEOS) 1428 // On desktop Chrome, sign out the user after a dashboard clear. 1429 // Skip sign out on ChromeOS/Android. 1430 if (!startup_controller_.auto_start_enabled()) { 1431 SigninManagerFactory::GetForProfile(profile_)->SignOut( 1432 signin_metrics::SERVER_FORCED_DISABLE); 1433 } 1434#endif 1435 break; 1436 case syncer::ROLLBACK_DONE: 1437 backup_rollback_controller_.OnRollbackDone(); 1438 break; 1439 case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT: 1440 // Sync disabled by domain admin. we should stop syncing until next 1441 // restart. 1442 sync_disabled_by_admin_ = true; 1443 ShutdownImpl(syncer::DISABLE_SYNC); 1444 break; 1445 default: 1446 NOTREACHED(); 1447 } 1448 NotifyObservers(); 1449 1450 if (error.action == syncer::DISABLE_SYNC_ON_CLIENT || 1451 (error.action == syncer::DISABLE_SYNC_AND_ROLLBACK && 1452 !backup_rollback_controller_.StartRollback())) { 1453 // Clean up backup data for sign-out only or when rollback is disabled. 1454 CleanUpBackup(); 1455 } else if (error.action == syncer::ROLLBACK_DONE) { 1456 // Shut down ROLLBACK backend and delete backup DB. 1457 ShutdownImpl(syncer::DISABLE_SYNC); 1458 sync_prefs_.ClearFirstSyncTime(); 1459 } 1460} 1461 1462void ProfileSyncService::OnConfigureDone( 1463 const DataTypeManager::ConfigureResult& result) { 1464 configure_status_ = result.status; 1465 data_type_status_table_ = result.data_type_status_table; 1466 1467 if (backend_mode_ != SYNC) { 1468 if (configure_status_ == DataTypeManager::OK) { 1469 StartSyncingWithServer(); 1470 1471 // Backup is done after models are associated. 1472 if (backend_mode_ == BACKUP) 1473 backup_finished_ = true; 1474 1475 // Asynchronously check whether sync needs to start. 1476 base::MessageLoop::current()->PostTask( 1477 FROM_HERE, base::Bind(&ProfileSyncService::TryStartSyncAfterBackup, 1478 startup_controller_weak_factory_.GetWeakPtr())); 1479 } else if (!expect_sync_configuration_aborted_) { 1480 DVLOG(1) << "Backup/rollback backend failed to configure."; 1481 ShutdownImpl(syncer::STOP_SYNC); 1482 } 1483 1484 return; 1485 } 1486 1487 // We should have cleared our cached passphrase before we get here (in 1488 // OnBackendInitialized()). 1489 DCHECK(cached_passphrase_.empty()); 1490 1491 if (!sync_configure_start_time_.is_null()) { 1492 if (result.status == DataTypeManager::OK) { 1493 base::Time sync_configure_stop_time = base::Time::Now(); 1494 base::TimeDelta delta = sync_configure_stop_time - 1495 sync_configure_start_time_; 1496 if (is_first_time_sync_configure_) { 1497 UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceInitialConfigureTime", delta); 1498 } else { 1499 UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceSubsequentConfigureTime", 1500 delta); 1501 } 1502 } 1503 sync_configure_start_time_ = base::Time(); 1504 } 1505 1506 // Notify listeners that configuration is done. 1507 content::NotificationService::current()->Notify( 1508 chrome::NOTIFICATION_SYNC_CONFIGURE_DONE, 1509 content::Source<ProfileSyncService>(this), 1510 content::NotificationService::NoDetails()); 1511 1512 DVLOG(1) << "PSS OnConfigureDone called with status: " << configure_status_; 1513 // The possible status values: 1514 // ABORT - Configuration was aborted. This is not an error, if 1515 // initiated by user. 1516 // OK - Some or all types succeeded. 1517 // Everything else is an UnrecoverableError. So treat it as such. 1518 1519 // First handle the abort case. 1520 if (configure_status_ == DataTypeManager::ABORTED && 1521 expect_sync_configuration_aborted_) { 1522 DVLOG(0) << "ProfileSyncService::Observe Sync Configure aborted"; 1523 expect_sync_configuration_aborted_ = false; 1524 return; 1525 } 1526 1527 // Handle unrecoverable error. 1528 if (configure_status_ != DataTypeManager::OK) { 1529 // Something catastrophic had happened. We should only have one 1530 // error representing it. 1531 syncer::SyncError error = 1532 data_type_status_table_.GetUnrecoverableError(); 1533 DCHECK(error.IsSet()); 1534 std::string message = 1535 "Sync configuration failed with status " + 1536 DataTypeManager::ConfigureStatusToString(configure_status_) + 1537 " caused by " + 1538 syncer::ModelTypeSetToString( 1539 data_type_status_table_.GetUnrecoverableErrorTypes()) + 1540 ": " + error.message(); 1541 LOG(ERROR) << "ProfileSyncService error: " << message; 1542 OnInternalUnrecoverableError(error.location(), 1543 message, 1544 true, 1545 ERROR_REASON_CONFIGURATION_FAILURE); 1546 return; 1547 } 1548 1549 // We should never get in a state where we have no encrypted datatypes 1550 // enabled, and yet we still think we require a passphrase for decryption. 1551 DCHECK(!(IsPassphraseRequiredForDecryption() && 1552 !IsEncryptedDatatypeEnabled())); 1553 1554 // This must be done before we start syncing with the server to avoid 1555 // sending unencrypted data up on a first time sync. 1556 if (encryption_pending_) 1557 backend_->EnableEncryptEverything(); 1558 NotifyObservers(); 1559 1560 if (migrator_.get() && 1561 migrator_->state() != browser_sync::BackendMigrator::IDLE) { 1562 // Migration in progress. Let the migrator know we just finished 1563 // configuring something. It will be up to the migrator to call 1564 // StartSyncingWithServer() if migration is now finished. 1565 migrator_->OnConfigureDone(result); 1566 } else { 1567 StartSyncingWithServer(); 1568 } 1569} 1570 1571void ProfileSyncService::OnConfigureRetry() { 1572 // We should have cleared our cached passphrase before we get here (in 1573 // OnBackendInitialized()). 1574 DCHECK(cached_passphrase_.empty()); 1575 1576 OnSyncConfigureRetry(); 1577} 1578 1579void ProfileSyncService::OnConfigureStart() { 1580 sync_configure_start_time_ = base::Time::Now(); 1581 NotifyObservers(); 1582} 1583 1584ProfileSyncService::SyncStatusSummary 1585 ProfileSyncService::QuerySyncStatusSummary() { 1586 if (HasUnrecoverableError()) { 1587 return UNRECOVERABLE_ERROR; 1588 } else if (!backend_) { 1589 return NOT_ENABLED; 1590 } else if (backend_mode_ == BACKUP) { 1591 return BACKUP_USER_DATA; 1592 } else if (backend_mode_ == ROLLBACK) { 1593 return ROLLBACK_USER_DATA; 1594 } else if (backend_.get() && !HasSyncSetupCompleted()) { 1595 return SETUP_INCOMPLETE; 1596 } else if ( 1597 backend_.get() && HasSyncSetupCompleted() && 1598 directory_data_type_manager_.get() && 1599 directory_data_type_manager_->state() != DataTypeManager::CONFIGURED) { 1600 return DATATYPES_NOT_INITIALIZED; 1601 } else if (ShouldPushChanges()) { 1602 return INITIALIZED; 1603 } 1604 return UNKNOWN_ERROR; 1605} 1606 1607std::string ProfileSyncService::QuerySyncStatusSummaryString() { 1608 SyncStatusSummary status = QuerySyncStatusSummary(); 1609 1610 std::string config_status_str = 1611 configure_status_ != DataTypeManager::UNKNOWN ? 1612 DataTypeManager::ConfigureStatusToString(configure_status_) : ""; 1613 1614 switch (status) { 1615 case UNRECOVERABLE_ERROR: 1616 return "Unrecoverable error detected"; 1617 case NOT_ENABLED: 1618 return "Syncing not enabled"; 1619 case SETUP_INCOMPLETE: 1620 return "First time sync setup incomplete"; 1621 case DATATYPES_NOT_INITIALIZED: 1622 return "Datatypes not fully initialized"; 1623 case INITIALIZED: 1624 return "Sync service initialized"; 1625 case BACKUP_USER_DATA: 1626 return "Backing-up user data. Status: " + config_status_str; 1627 case ROLLBACK_USER_DATA: 1628 return "Restoring user data. Status: " + config_status_str; 1629 default: 1630 return "Status unknown: Internal error?"; 1631 } 1632} 1633 1634std::string ProfileSyncService::GetBackendInitializationStateString() const { 1635 return startup_controller_.GetBackendInitializationStateString(); 1636} 1637 1638bool ProfileSyncService::auto_start_enabled() const { 1639 return startup_controller_.auto_start_enabled(); 1640} 1641 1642bool ProfileSyncService::setup_in_progress() const { 1643 return startup_controller_.setup_in_progress(); 1644} 1645 1646bool ProfileSyncService::QueryDetailedSyncStatus( 1647 SyncBackendHost::Status* result) { 1648 if (backend_.get() && backend_initialized_) { 1649 *result = backend_->GetDetailedStatus(); 1650 return true; 1651 } else { 1652 SyncBackendHost::Status status; 1653 status.sync_protocol_error = last_actionable_error_; 1654 *result = status; 1655 return false; 1656 } 1657} 1658 1659const AuthError& ProfileSyncService::GetAuthError() const { 1660 return last_auth_error_; 1661} 1662 1663bool ProfileSyncService::FirstSetupInProgress() const { 1664 return !HasSyncSetupCompleted() && startup_controller_.setup_in_progress(); 1665} 1666 1667void ProfileSyncService::SetSetupInProgress(bool setup_in_progress) { 1668 // This method is a no-op if |setup_in_progress_| remains unchanged. 1669 if (startup_controller_.setup_in_progress() == setup_in_progress) 1670 return; 1671 1672 startup_controller_.set_setup_in_progress(setup_in_progress); 1673 if (!setup_in_progress && sync_initialized()) 1674 ReconfigureDatatypeManager(); 1675 NotifyObservers(); 1676} 1677 1678bool ProfileSyncService::sync_initialized() const { 1679 return backend_initialized_; 1680} 1681 1682bool ProfileSyncService::waiting_for_auth() const { 1683 return is_auth_in_progress_; 1684} 1685 1686const syncer::Experiments& ProfileSyncService::current_experiments() const { 1687 return current_experiments_; 1688} 1689 1690bool ProfileSyncService::HasUnrecoverableError() const { 1691 return unrecoverable_error_reason_ != ERROR_REASON_UNSET; 1692} 1693 1694bool ProfileSyncService::IsPassphraseRequired() const { 1695 return passphrase_required_reason_ != 1696 syncer::REASON_PASSPHRASE_NOT_REQUIRED; 1697} 1698 1699bool ProfileSyncService::IsPassphraseRequiredForDecryption() const { 1700 // If there is an encrypted datatype enabled and we don't have the proper 1701 // passphrase, we must prompt the user for a passphrase. The only way for the 1702 // user to avoid entering their passphrase is to disable the encrypted types. 1703 return IsEncryptedDatatypeEnabled() && IsPassphraseRequired(); 1704} 1705 1706base::string16 ProfileSyncService::GetLastSyncedTimeString() const { 1707 if (last_synced_time_.is_null()) 1708 return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER); 1709 1710 base::TimeDelta last_synced = base::Time::Now() - last_synced_time_; 1711 1712 if (last_synced < base::TimeDelta::FromMinutes(1)) 1713 return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW); 1714 1715 return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_ELAPSED, 1716 ui::TimeFormat::LENGTH_SHORT, last_synced); 1717} 1718 1719void ProfileSyncService::UpdateSelectedTypesHistogram( 1720 bool sync_everything, const syncer::ModelTypeSet chosen_types) const { 1721 if (!HasSyncSetupCompleted() || 1722 sync_everything != sync_prefs_.HasKeepEverythingSynced()) { 1723 UMA_HISTOGRAM_BOOLEAN("Sync.SyncEverything", sync_everything); 1724 } 1725 1726 // Only log the data types that are shown in the sync settings ui. 1727 // Note: the order of these types must match the ordering of 1728 // the respective types in ModelType 1729 const sync_driver::user_selectable_type::UserSelectableSyncType 1730 user_selectable_types[] = { 1731 sync_driver::user_selectable_type::BOOKMARKS, 1732 sync_driver::user_selectable_type::PREFERENCES, 1733 sync_driver::user_selectable_type::PASSWORDS, 1734 sync_driver::user_selectable_type::AUTOFILL, 1735 sync_driver::user_selectable_type::THEMES, 1736 sync_driver::user_selectable_type::TYPED_URLS, 1737 sync_driver::user_selectable_type::EXTENSIONS, 1738 sync_driver::user_selectable_type::APPS, 1739 sync_driver::user_selectable_type::PROXY_TABS 1740 }; 1741 1742 COMPILE_ASSERT(32 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram); 1743 1744 if (!sync_everything) { 1745 const syncer::ModelTypeSet current_types = GetPreferredDataTypes(); 1746 1747 syncer::ModelTypeSet type_set = syncer::UserSelectableTypes(); 1748 syncer::ModelTypeSet::Iterator it = type_set.First(); 1749 1750 DCHECK_EQ(arraysize(user_selectable_types), type_set.Size()); 1751 1752 for (size_t i = 0; i < arraysize(user_selectable_types) && it.Good(); 1753 ++i, it.Inc()) { 1754 const syncer::ModelType type = it.Get(); 1755 if (chosen_types.Has(type) && 1756 (!HasSyncSetupCompleted() || !current_types.Has(type))) { 1757 // Selected type has changed - log it. 1758 UMA_HISTOGRAM_ENUMERATION( 1759 "Sync.CustomSync", 1760 user_selectable_types[i], 1761 sync_driver::user_selectable_type::SELECTABLE_DATATYPE_COUNT + 1); 1762 } 1763 } 1764 } 1765} 1766 1767#if defined(OS_CHROMEOS) 1768void ProfileSyncService::RefreshSpareBootstrapToken( 1769 const std::string& passphrase) { 1770 sync_driver::SystemEncryptor encryptor; 1771 syncer::Cryptographer temp_cryptographer(&encryptor); 1772 // The first 2 params (hostname and username) doesn't have any effect here. 1773 syncer::KeyParams key_params = {"localhost", "dummy", passphrase}; 1774 1775 std::string bootstrap_token; 1776 if (!temp_cryptographer.AddKey(key_params)) { 1777 NOTREACHED() << "Failed to add key to cryptographer."; 1778 } 1779 temp_cryptographer.GetBootstrapToken(&bootstrap_token); 1780 sync_prefs_.SetSpareBootstrapToken(bootstrap_token); 1781} 1782#endif 1783 1784void ProfileSyncService::OnUserChoseDatatypes( 1785 bool sync_everything, 1786 syncer::ModelTypeSet chosen_types) { 1787 if (!backend_.get() && !HasUnrecoverableError()) { 1788 NOTREACHED(); 1789 return; 1790 } 1791 1792 UpdateSelectedTypesHistogram(sync_everything, chosen_types); 1793 sync_prefs_.SetKeepEverythingSynced(sync_everything); 1794 1795 if (directory_data_type_manager_.get()) 1796 directory_data_type_manager_->ResetDataTypeErrors(); 1797 ChangePreferredDataTypes(chosen_types); 1798 AcknowledgeSyncedTypes(); 1799 NotifyObservers(); 1800} 1801 1802void ProfileSyncService::ChangePreferredDataTypes( 1803 syncer::ModelTypeSet preferred_types) { 1804 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); 1811 1812 // Now reconfigure the DTM. 1813 ReconfigureDatatypeManager(); 1814 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. 1818} 1819 1820syncer::ModelTypeSet ProfileSyncService::GetActiveDataTypes() const { 1821 const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes(); 1822 const syncer::ModelTypeSet failed_types = 1823 data_type_status_table_.GetFailedTypes(); 1824 return Difference(preferred_types, failed_types); 1825} 1826 1827syncer::ModelTypeSet ProfileSyncService::GetPreferredDataTypes() const { 1828 const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes(); 1829 const syncer::ModelTypeSet preferred_types = 1830 sync_prefs_.GetPreferredDataTypes(registered_types); 1831 const syncer::ModelTypeSet enforced_types = 1832 Intersection(GetDataTypesFromPreferenceProviders(), registered_types); 1833 return Union(preferred_types, enforced_types); 1834} 1835 1836syncer::ModelTypeSet 1837ProfileSyncService::GetPreferredDirectoryDataTypes() const { 1838 const syncer::ModelTypeSet registered_directory_types = 1839 GetRegisteredDirectoryDataTypes(); 1840 const syncer::ModelTypeSet preferred_types = 1841 sync_prefs_.GetPreferredDataTypes(registered_directory_types); 1842 const syncer::ModelTypeSet enforced_types = 1843 Intersection(GetDataTypesFromPreferenceProviders(), 1844 registered_directory_types); 1845 return Union(preferred_types, enforced_types); 1846} 1847 1848syncer::ModelTypeSet 1849ProfileSyncService::GetPreferredNonBlockingDataTypes() const { 1850 return sync_prefs_.GetPreferredDataTypes(GetRegisteredNonBlockingDataTypes()); 1851} 1852 1853syncer::ModelTypeSet ProfileSyncService::GetForcedDataTypes() const { 1854 // TODO(treib,zea): When SyncPrefs also implements SyncTypePreferenceProvider, 1855 // we'll need another way to distinguish user-choosable types from 1856 // programmatically-enabled types. 1857 return GetDataTypesFromPreferenceProviders(); 1858} 1859 1860syncer::ModelTypeSet ProfileSyncService::GetRegisteredDataTypes() const { 1861 return Union(GetRegisteredDirectoryDataTypes(), 1862 GetRegisteredNonBlockingDataTypes()); 1863} 1864 1865syncer::ModelTypeSet 1866ProfileSyncService::GetRegisteredDirectoryDataTypes() const { 1867 syncer::ModelTypeSet registered_types; 1868 // The directory_data_type_controllers_ are determined by command-line flags; 1869 // that's effectively what controls the values returned here. 1870 for (DataTypeController::TypeMap::const_iterator it = 1871 directory_data_type_controllers_.begin(); 1872 it != directory_data_type_controllers_.end(); ++it) { 1873 registered_types.Put(it->first); 1874 } 1875 return registered_types; 1876} 1877 1878syncer::ModelTypeSet 1879ProfileSyncService::GetRegisteredNonBlockingDataTypes() const { 1880 return non_blocking_data_type_manager_.GetRegisteredTypes(); 1881} 1882 1883bool ProfileSyncService::IsUsingSecondaryPassphrase() const { 1884 syncer::PassphraseType passphrase_type = GetPassphraseType(); 1885 return passphrase_type == syncer::FROZEN_IMPLICIT_PASSPHRASE || 1886 passphrase_type == syncer::CUSTOM_PASSPHRASE; 1887} 1888 1889syncer::PassphraseType ProfileSyncService::GetPassphraseType() const { 1890 return backend_->GetPassphraseType(); 1891} 1892 1893base::Time ProfileSyncService::GetExplicitPassphraseTime() const { 1894 return backend_->GetExplicitPassphraseTime(); 1895} 1896 1897bool ProfileSyncService::IsCryptographerReady( 1898 const syncer::BaseTransaction* trans) const { 1899 return backend_.get() && backend_->IsCryptographerReady(trans); 1900} 1901 1902void ProfileSyncService::ConfigurePriorityDataTypes() { 1903 const syncer::ModelTypeSet priority_types = 1904 Intersection(GetPreferredDirectoryDataTypes(), 1905 syncer::PriorityUserTypes()); 1906 if (!priority_types.Empty()) { 1907 const syncer::ConfigureReason reason = HasSyncSetupCompleted() ? 1908 syncer::CONFIGURE_REASON_RECONFIGURATION : 1909 syncer::CONFIGURE_REASON_NEW_CLIENT; 1910 directory_data_type_manager_->Configure(priority_types, reason); 1911 } 1912} 1913 1914void ProfileSyncService::ConfigureDataTypeManager() { 1915 // Don't configure datatypes if the setup UI is still on the screen - this 1916 // is to help multi-screen setting UIs (like iOS) where they don't want to 1917 // start syncing data until the user is done configuring encryption options, 1918 // etc. ReconfigureDatatypeManager() will get called again once the UI calls 1919 // SetSetupInProgress(false). 1920 if (backend_mode_ == SYNC && startup_controller_.setup_in_progress()) 1921 return; 1922 1923 bool restart = false; 1924 if (!directory_data_type_manager_) { 1925 restart = true; 1926 directory_data_type_manager_.reset( 1927 factory_->CreateDataTypeManager(debug_info_listener_, 1928 &directory_data_type_controllers_, 1929 this, 1930 backend_.get(), 1931 this)); 1932 1933 // We create the migrator at the same time. 1934 migrator_.reset( 1935 new browser_sync::BackendMigrator( 1936 profile_->GetDebugName(), GetUserShare(), 1937 this, directory_data_type_manager_.get(), 1938 base::Bind(&ProfileSyncService::StartSyncingWithServer, 1939 base::Unretained(this)))); 1940 } 1941 1942 syncer::ModelTypeSet types; 1943 syncer::ConfigureReason reason = syncer::CONFIGURE_REASON_UNKNOWN; 1944 if (backend_mode_ == BACKUP || backend_mode_ == ROLLBACK) { 1945 types = syncer::BackupTypes(); 1946 reason = syncer::CONFIGURE_REASON_BACKUP_ROLLBACK; 1947 } else { 1948 types = GetPreferredDirectoryDataTypes(); 1949 if (!HasSyncSetupCompleted()) { 1950 reason = syncer::CONFIGURE_REASON_NEW_CLIENT; 1951 } else if (restart) { 1952 // Datatype downloads on restart are generally due to newly supported 1953 // datatypes (although it's also possible we're picking up where a failed 1954 // previous configuration left off). 1955 // TODO(sync): consider detecting configuration recovery and setting 1956 // the reason here appropriately. 1957 reason = syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE; 1958 } else { 1959 // The user initiated a reconfiguration (either to add or remove types). 1960 reason = syncer::CONFIGURE_REASON_RECONFIGURATION; 1961 } 1962 } 1963 1964 directory_data_type_manager_->Configure(types, reason); 1965} 1966 1967syncer::UserShare* ProfileSyncService::GetUserShare() const { 1968 if (backend_.get() && backend_initialized_) { 1969 return backend_->GetUserShare(); 1970 } 1971 NOTREACHED(); 1972 return NULL; 1973} 1974 1975syncer::sessions::SyncSessionSnapshot 1976ProfileSyncService::GetLastSessionSnapshot() const { 1977 if (HasSyncingBackend() && backend_initialized_) { 1978 return backend_->GetLastSessionSnapshot(); 1979 } 1980 return syncer::sessions::SyncSessionSnapshot(); 1981} 1982 1983bool ProfileSyncService::HasUnsyncedItems() const { 1984 if (HasSyncingBackend() && backend_initialized_) { 1985 return backend_->HasUnsyncedItems(); 1986 } 1987 NOTREACHED(); 1988 return false; 1989} 1990 1991browser_sync::BackendMigrator* 1992ProfileSyncService::GetBackendMigratorForTest() { 1993 return migrator_.get(); 1994} 1995 1996void ProfileSyncService::GetModelSafeRoutingInfo( 1997 syncer::ModelSafeRoutingInfo* out) const { 1998 if (backend_.get() && backend_initialized_) { 1999 backend_->GetModelSafeRoutingInfo(out); 2000 } else { 2001 NOTREACHED(); 2002 } 2003} 2004 2005base::Value* ProfileSyncService::GetTypeStatusMap() const { 2006 scoped_ptr<base::ListValue> result(new base::ListValue()); 2007 2008 if (!backend_.get() || !backend_initialized_) { 2009 return result.release(); 2010 } 2011 2012 DataTypeStatusTable::TypeErrorMap error_map = 2013 data_type_status_table_.GetAllErrors(); 2014 ModelTypeSet active_types; 2015 ModelTypeSet passive_types; 2016 ModelSafeRoutingInfo routing_info; 2017 backend_->GetModelSafeRoutingInfo(&routing_info); 2018 for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin(); 2019 it != routing_info.end(); ++it) { 2020 if (it->second == syncer::GROUP_PASSIVE) { 2021 passive_types.Put(it->first); 2022 } else { 2023 active_types.Put(it->first); 2024 } 2025 } 2026 2027 SyncBackendHost::Status detailed_status = backend_->GetDetailedStatus(); 2028 ModelTypeSet &throttled_types(detailed_status.throttled_types); 2029 ModelTypeSet registered = GetRegisteredDataTypes(); 2030 scoped_ptr<base::DictionaryValue> type_status_header( 2031 new base::DictionaryValue()); 2032 2033 type_status_header->SetString("name", "Model Type"); 2034 type_status_header->SetString("status", "header"); 2035 type_status_header->SetString("value", "Group Type"); 2036 type_status_header->SetString("num_entries", "Total Entries"); 2037 type_status_header->SetString("num_live", "Live Entries"); 2038 result->Append(type_status_header.release()); 2039 2040 scoped_ptr<base::DictionaryValue> type_status; 2041 for (ModelTypeSet::Iterator it = registered.First(); it.Good(); it.Inc()) { 2042 ModelType type = it.Get(); 2043 2044 type_status.reset(new base::DictionaryValue()); 2045 type_status->SetString("name", ModelTypeToString(type)); 2046 2047 if (error_map.find(type) != error_map.end()) { 2048 const syncer::SyncError &error = error_map.find(type)->second; 2049 DCHECK(error.IsSet()); 2050 switch (error.GetSeverity()) { 2051 case syncer::SyncError::SYNC_ERROR_SEVERITY_ERROR: { 2052 std::string error_text = "Error: " + error.location().ToString() + 2053 ", " + error.GetMessagePrefix() + error.message(); 2054 type_status->SetString("status", "error"); 2055 type_status->SetString("value", error_text); 2056 } 2057 break; 2058 case syncer::SyncError::SYNC_ERROR_SEVERITY_INFO: 2059 type_status->SetString("status", "disabled"); 2060 type_status->SetString("value", error.message()); 2061 break; 2062 default: 2063 NOTREACHED() << "Unexpected error severity."; 2064 break; 2065 } 2066 } else if (syncer::IsProxyType(type) && passive_types.Has(type)) { 2067 // Show a proxy type in "ok" state unless it is disabled by user. 2068 DCHECK(!throttled_types.Has(type)); 2069 type_status->SetString("status", "ok"); 2070 type_status->SetString("value", "Passive"); 2071 } else if (throttled_types.Has(type) && passive_types.Has(type)) { 2072 type_status->SetString("status", "warning"); 2073 type_status->SetString("value", "Passive, Throttled"); 2074 } else if (passive_types.Has(type)) { 2075 type_status->SetString("status", "warning"); 2076 type_status->SetString("value", "Passive"); 2077 } else if (throttled_types.Has(type)) { 2078 type_status->SetString("status", "warning"); 2079 type_status->SetString("value", "Throttled"); 2080 } else if (GetRegisteredNonBlockingDataTypes().Has(type)) { 2081 type_status->SetString("status", "ok"); 2082 type_status->SetString("value", "Non-Blocking"); 2083 } else if (active_types.Has(type)) { 2084 type_status->SetString("status", "ok"); 2085 type_status->SetString("value", "Active: " + 2086 ModelSafeGroupToString(routing_info[type])); 2087 } else { 2088 type_status->SetString("status", "warning"); 2089 type_status->SetString("value", "Disabled by User"); 2090 } 2091 2092 int live_count = detailed_status.num_entries_by_type[type] - 2093 detailed_status.num_to_delete_entries_by_type[type]; 2094 type_status->SetInteger("num_entries", 2095 detailed_status.num_entries_by_type[type]); 2096 type_status->SetInteger("num_live", live_count); 2097 2098 result->Append(type_status.release()); 2099 } 2100 return result.release(); 2101} 2102 2103void ProfileSyncService::DeactivateDataType(syncer::ModelType type) { 2104 if (!backend_) 2105 return; 2106 backend_->DeactivateDataType(type); 2107} 2108 2109void ProfileSyncService::ConsumeCachedPassphraseIfPossible() { 2110 // If no cached passphrase, or sync backend hasn't started up yet, just exit. 2111 // If the backend isn't running yet, OnBackendInitialized() will call this 2112 // method again after the backend starts up. 2113 if (cached_passphrase_.empty() || !sync_initialized()) 2114 return; 2115 2116 // Backend is up and running, so we can consume the cached passphrase. 2117 std::string passphrase = cached_passphrase_; 2118 cached_passphrase_.clear(); 2119 2120 // If we need a passphrase to decrypt data, try the cached passphrase. 2121 if (passphrase_required_reason() == syncer::REASON_DECRYPTION) { 2122 if (SetDecryptionPassphrase(passphrase)) { 2123 DVLOG(1) << "Cached passphrase successfully decrypted pending keys"; 2124 return; 2125 } 2126 } 2127 2128 // If we get here, we don't have pending keys (or at least, the passphrase 2129 // doesn't decrypt them) - just try to re-encrypt using the encryption 2130 // passphrase. 2131 if (!IsUsingSecondaryPassphrase()) 2132 SetEncryptionPassphrase(passphrase, IMPLICIT); 2133} 2134 2135void ProfileSyncService::RequestAccessToken() { 2136 // Only one active request at a time. 2137 if (access_token_request_ != NULL) 2138 return; 2139 request_access_token_retry_timer_.Stop(); 2140 OAuth2TokenService::ScopeSet oauth2_scopes; 2141 oauth2_scopes.insert(signin_->GetSyncScopeToUse()); 2142 2143 // Invalidate previous token, otherwise token service will return the same 2144 // token again. 2145 const std::string& account_id = signin_->GetAccountIdToUse(); 2146 if (!access_token_.empty()) { 2147 oauth2_token_service_->InvalidateToken( 2148 account_id, oauth2_scopes, access_token_); 2149 } 2150 2151 access_token_.clear(); 2152 2153 token_request_time_ = base::Time::Now(); 2154 token_receive_time_ = base::Time(); 2155 next_token_request_time_ = base::Time(); 2156 access_token_request_ = 2157 oauth2_token_service_->StartRequest(account_id, oauth2_scopes, this); 2158} 2159 2160void ProfileSyncService::SetEncryptionPassphrase(const std::string& passphrase, 2161 PassphraseType type) { 2162 // This should only be called when the backend has been initialized. 2163 DCHECK(sync_initialized()); 2164 DCHECK(!(type == IMPLICIT && IsUsingSecondaryPassphrase())) << 2165 "Data is already encrypted using an explicit passphrase"; 2166 DCHECK(!(type == EXPLICIT && 2167 passphrase_required_reason_ == syncer::REASON_DECRYPTION)) << 2168 "Can not set explicit passphrase when decryption is needed."; 2169 2170 DVLOG(1) << "Setting " << (type == EXPLICIT ? "explicit" : "implicit") 2171 << " passphrase for encryption."; 2172 if (passphrase_required_reason_ == syncer::REASON_ENCRYPTION) { 2173 // REASON_ENCRYPTION implies that the cryptographer does not have pending 2174 // keys. Hence, as long as we're not trying to do an invalid passphrase 2175 // change (e.g. explicit -> explicit or explicit -> implicit), we know this 2176 // will succeed. If for some reason a new encryption key arrives via 2177 // sync later, the SBH will trigger another OnPassphraseRequired(). 2178 passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED; 2179 NotifyObservers(); 2180 } 2181 backend_->SetEncryptionPassphrase(passphrase, type == EXPLICIT); 2182} 2183 2184bool ProfileSyncService::SetDecryptionPassphrase( 2185 const std::string& passphrase) { 2186 if (IsPassphraseRequired()) { 2187 DVLOG(1) << "Setting passphrase for decryption."; 2188 return backend_->SetDecryptionPassphrase(passphrase); 2189 } else { 2190 NOTREACHED() << "SetDecryptionPassphrase must not be called when " 2191 "IsPassphraseRequired() is false."; 2192 return false; 2193 } 2194} 2195 2196void ProfileSyncService::EnableEncryptEverything() { 2197 // Tests override sync_initialized() to always return true, so we 2198 // must check that instead of |backend_initialized_|. 2199 // TODO(akalin): Fix the above. :/ 2200 DCHECK(sync_initialized()); 2201 // TODO(atwilson): Persist the encryption_pending_ flag to address the various 2202 // problems around cancelling encryption in the background (crbug.com/119649). 2203 if (!encrypt_everything_) 2204 encryption_pending_ = true; 2205} 2206 2207bool ProfileSyncService::encryption_pending() const { 2208 // We may be called during the setup process before we're 2209 // initialized (via IsEncryptedDatatypeEnabled and 2210 // IsPassphraseRequiredForDecryption). 2211 return encryption_pending_; 2212} 2213 2214bool ProfileSyncService::EncryptEverythingEnabled() const { 2215 DCHECK(backend_initialized_); 2216 return encrypt_everything_ || encryption_pending_; 2217} 2218 2219syncer::ModelTypeSet ProfileSyncService::GetEncryptedDataTypes() const { 2220 DCHECK(encrypted_types_.Has(syncer::PASSWORDS)); 2221 // We may be called during the setup process before we're 2222 // initialized. In this case, we default to the sensitive types. 2223 return encrypted_types_; 2224} 2225 2226void ProfileSyncService::OnSyncManagedPrefChange(bool is_sync_managed) { 2227 NotifyObservers(); 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(); 2233 } 2234} 2235 2236void 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(); 2245 } 2246#if defined(OS_CHROMEOS) 2247 RefreshSpareBootstrapToken(password); 2248#endif 2249 if (!sync_initialized() || GetAuthError().state() != AuthError::NONE) { 2250 // Track the fact that we're still waiting for auth to complete. 2251 is_auth_in_progress_ = true; 2252 } 2253} 2254 2255void ProfileSyncService::GoogleSignedOut(const std::string& account_id, 2256 const std::string& username) { 2257 sync_disabled_by_admin_ = false; 2258 DisableForUser(); 2259 2260 if (browser_sync::BackupRollbackController::IsBackupEnabled()) { 2261 need_backup_ = true; 2262 backup_finished_ = false; 2263 } 2264} 2265 2266void ProfileSyncService::AddObserver( 2267 ProfileSyncServiceBase::Observer* observer) { 2268 observers_.AddObserver(observer); 2269} 2270 2271void ProfileSyncService::RemoveObserver( 2272 ProfileSyncServiceBase::Observer* observer) { 2273 observers_.RemoveObserver(observer); 2274} 2275 2276void ProfileSyncService::AddProtocolEventObserver( 2277 browser_sync::ProtocolEventObserver* observer) { 2278 protocol_event_observers_.AddObserver(observer); 2279 if (HasSyncingBackend()) { 2280 backend_->RequestBufferedProtocolEventsAndEnableForwarding(); 2281 } 2282} 2283 2284void 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(); 2290 } 2291} 2292 2293void 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(); 2299 } 2300} 2301 2302void 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(); 2308 } 2309} 2310 2311void ProfileSyncService::AddPreferenceProvider( 2312 SyncTypePreferenceProvider* provider) { 2313 DCHECK(!HasPreferenceProvider(provider)) 2314 << "Providers may only be added once!"; 2315 preference_providers_.insert(provider); 2316} 2317 2318void 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); 2323} 2324 2325bool ProfileSyncService::HasPreferenceProvider( 2326 SyncTypePreferenceProvider* provider) const { 2327 return preference_providers_.count(provider) > 0; 2328} 2329 2330namespace { 2331 2332class 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); 2338 2339 void OnReceivedNodesForTypes( 2340 const std::vector<syncer::ModelType>& types, 2341 ScopedVector<base::ListValue> scoped_node_lists); 2342 2343 private: 2344 friend class base::RefCountedThreadSafe<GetAllNodesRequestHelper>; 2345 virtual ~GetAllNodesRequestHelper(); 2346 2347 scoped_ptr<base::ListValue> result_accumulator_; 2348 2349 syncer::ModelTypeSet awaiting_types_; 2350 base::Callback<void(scoped_ptr<base::ListValue>)> callback_; 2351}; 2352 2353GetAllNodesRequestHelper::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) {} 2359 2360GetAllNodesRequestHelper::~GetAllNodesRequestHelper() { 2361 if (!awaiting_types_.Empty()) { 2362 DLOG(WARNING) 2363 << "GetAllNodesRequest deleted before request was fulfilled. " 2364 << "Missing types are: " << ModelTypeSetToString(awaiting_types_); 2365 } 2366} 2367 2368// Called when the set of nodes for a type or set of types has been returned. 2369// 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|. 2373void 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()); 2377 2378 // Take unsafe ownership of the node list. 2379 std::vector<base::ListValue*> node_lists; 2380 scoped_node_lists.release(&node_lists); 2381 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]; 2385 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()); 2391 2392 // Remember that this part of the request is satisfied. 2393 awaiting_types_.Remove(type); 2394 } 2395 2396 if (awaiting_types_.Empty()) { 2397 callback_.Run(result_accumulator_.Pass()); 2398 callback_.Reset(); 2399 } 2400} 2401 2402} // namespace 2403 2404void 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); 2410 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()); 2419 } 2420 helper->OnReceivedNodesForTypes(type_vector, empty_results.Pass()); 2421 } else { 2422 backend_->GetAllNodesForTypes( 2423 directory_types, 2424 base::Bind(&GetAllNodesRequestHelper::OnReceivedNodesForTypes, helper)); 2425 } 2426} 2427 2428bool ProfileSyncService::HasObserver( 2429 ProfileSyncServiceBase::Observer* observer) const { 2430 return observers_.HasObserver(observer); 2431} 2432 2433base::WeakPtr<syncer::JsController> ProfileSyncService::GetJsController() { 2434 return sync_js_controller_.AsWeakPtr(); 2435} 2436 2437void ProfileSyncService::SyncEvent(SyncEventCodes code) { 2438 UMA_HISTOGRAM_ENUMERATION("Sync.EventCodes", code, MAX_SYNC_EVENT_CODE); 2439} 2440 2441// static 2442bool 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); 2446} 2447 2448bool ProfileSyncService::IsManaged() const { 2449 return sync_prefs_.IsManaged() || sync_disabled_by_admin_; 2450} 2451 2452bool ProfileSyncService::ShouldPushChanges() { 2453 // True only after all bootstrapping has succeeded: the sync backend 2454 // is initialized, all enabled data types are consistent with one 2455 // another, and no unrecoverable error has transpired. 2456 if (HasUnrecoverableError()) 2457 return false; 2458 2459 if (!directory_data_type_manager_) 2460 return false; 2461 2462 return directory_data_type_manager_->state() == DataTypeManager::CONFIGURED; 2463} 2464 2465void ProfileSyncService::StopAndSuppress() { 2466 sync_prefs_.SetStartSuppressed(true); 2467 if (HasSyncingBackend()) { 2468 backend_->UnregisterInvalidationIds(); 2469 } 2470 ShutdownImpl(syncer::STOP_SYNC); 2471} 2472 2473bool ProfileSyncService::IsStartSuppressed() const { 2474 return sync_prefs_.IsStartSuppressed(); 2475} 2476 2477SigninManagerBase* ProfileSyncService::signin() const { 2478 if (!signin_) 2479 return NULL; 2480 return signin_->GetOriginal(); 2481} 2482 2483void ProfileSyncService::UnsuppressAndStart() { 2484 DCHECK(profile_); 2485 sync_prefs_.SetStartSuppressed(false); 2486 if (signin_.get() && !signin_->GetOriginal()->IsAuthenticated()) { 2487 signin_->GetOriginal()->SetAuthenticatedUsername( 2488 profile_->GetPrefs()->GetString(prefs::kGoogleServicesUsername)); 2489 } 2490 startup_controller_.TryStart(); 2491} 2492 2493void ProfileSyncService::AcknowledgeSyncedTypes() { 2494 sync_prefs_.AcknowledgeSyncedTypes(GetRegisteredDataTypes()); 2495} 2496 2497void ProfileSyncService::ReconfigureDatatypeManager() { 2498 // If we haven't initialized yet, don't configure the DTM as it could cause 2499 // association to start before a Directory has even been created. 2500 if (backend_initialized_) { 2501 DCHECK(backend_.get()); 2502 ConfigureDataTypeManager(); 2503 } else if (HasUnrecoverableError()) { 2504 // There is nothing more to configure. So inform the listeners, 2505 NotifyObservers(); 2506 2507 DVLOG(1) << "ConfigureDataTypeManager not invoked because of an " 2508 << "Unrecoverable error."; 2509 } else { 2510 DVLOG(0) << "ConfigureDataTypeManager not invoked because backend is not " 2511 << "initialized"; 2512 } 2513} 2514 2515syncer::ModelTypeSet ProfileSyncService::GetDataTypesFromPreferenceProviders() 2516 const { 2517 syncer::ModelTypeSet types; 2518 for (std::set<SyncTypePreferenceProvider*>::const_iterator it = 2519 preference_providers_.begin(); 2520 it != preference_providers_.end(); 2521 ++it) { 2522 types.PutAll((*it)->GetPreferredDataTypes()); 2523 } 2524 return types; 2525} 2526 2527const DataTypeStatusTable& ProfileSyncService::data_type_status_table() 2528 const { 2529 return data_type_status_table_; 2530} 2531 2532void ProfileSyncService::OnInternalUnrecoverableError( 2533 const tracked_objects::Location& from_here, 2534 const std::string& message, 2535 bool delete_sync_database, 2536 UnrecoverableErrorReason reason) { 2537 DCHECK(!HasUnrecoverableError()); 2538 unrecoverable_error_reason_ = reason; 2539 OnUnrecoverableErrorImpl(from_here, message, delete_sync_database); 2540} 2541 2542syncer::SyncManagerFactory::MANAGER_TYPE 2543ProfileSyncService::GetManagerType() const { 2544 switch (backend_mode_) { 2545 case SYNC: 2546 return syncer::SyncManagerFactory::NORMAL; 2547 case BACKUP: 2548 return syncer::SyncManagerFactory::BACKUP; 2549 case ROLLBACK: 2550 return syncer::SyncManagerFactory::ROLLBACK; 2551 case IDLE: 2552 NOTREACHED(); 2553 } 2554 return syncer::SyncManagerFactory::NORMAL; 2555} 2556 2557bool ProfileSyncService::IsRetryingAccessTokenFetchForTest() const { 2558 return request_access_token_retry_timer_.IsRunning(); 2559} 2560 2561std::string ProfileSyncService::GetAccessTokenForTest() const { 2562 return access_token_; 2563} 2564 2565WeakHandle<syncer::JsEventHandler> ProfileSyncService::GetJsEventHandler() { 2566 return MakeWeakHandle(sync_js_controller_.AsWeakPtr()); 2567} 2568 2569syncer::SyncableService* ProfileSyncService::GetSessionsSyncableService() { 2570 return sessions_sync_manager_.get(); 2571} 2572 2573syncer::SyncableService* ProfileSyncService::GetDeviceInfoSyncableService() { 2574 return device_info_sync_service_.get(); 2575} 2576 2577ProfileSyncService::SyncTokenStatus::SyncTokenStatus() 2578 : connection_status(syncer::CONNECTION_NOT_ATTEMPTED), 2579 last_get_token_error(GoogleServiceAuthError::AuthErrorNone()) {} 2580ProfileSyncService::SyncTokenStatus::~SyncTokenStatus() {} 2581 2582ProfileSyncService::SyncTokenStatus 2583ProfileSyncService::GetSyncTokenStatus() const { 2584 SyncTokenStatus status; 2585 status.connection_status_update_time = connection_status_update_time_; 2586 status.connection_status = connection_status_; 2587 status.token_request_time = token_request_time_; 2588 status.token_receive_time = token_receive_time_; 2589 status.last_get_token_error = last_get_token_error_; 2590 if (request_access_token_retry_timer_.IsRunning()) 2591 status.next_token_request_time = next_token_request_time_; 2592 return status; 2593} 2594 2595void ProfileSyncService::OverrideNetworkResourcesForTest( 2596 scoped_ptr<syncer::NetworkResources> network_resources) { 2597 network_resources_ = network_resources.Pass(); 2598} 2599 2600bool ProfileSyncService::HasSyncingBackend() const { 2601 return backend_mode_ != SYNC ? false : backend_ != NULL; 2602} 2603 2604void ProfileSyncService::UpdateFirstSyncTimePref() { 2605 if (signin_->GetEffectiveUsername().empty()) { 2606 // Clear if user's not signed in and rollback is done. 2607 if (backend_mode_ != ROLLBACK) 2608 sync_prefs_.ClearFirstSyncTime(); 2609 } else if (sync_prefs_.GetFirstSyncTime().is_null() && 2610 backend_mode_ == SYNC) { 2611 // Set if not set before and it's syncing now. 2612 sync_prefs_.SetFirstSyncTime(base::Time::Now()); 2613 } 2614} 2615 2616void ProfileSyncService::ClearBrowsingDataSinceFirstSync() { 2617 base::Time first_sync_time = sync_prefs_.GetFirstSyncTime(); 2618 if (first_sync_time.is_null()) 2619 return; 2620 2621 clear_browsing_data_.Run(browsing_data_remover_observer_, 2622 profile_, 2623 first_sync_time, 2624 base::Time::Now()); 2625} 2626 2627void ProfileSyncService::SetBrowsingDataRemoverObserverForTesting( 2628 BrowsingDataRemover::Observer* observer) { 2629 browsing_data_remover_observer_ = observer; 2630} 2631 2632void ProfileSyncService::SetClearingBrowseringDataForTesting( 2633 base::Callback<void(BrowsingDataRemover::Observer* observer, 2634 Profile*, 2635 base::Time, 2636 base::Time)> c) { 2637 clear_browsing_data_ = c; 2638} 2639 2640GURL ProfileSyncService::GetSyncServiceURL( 2641 const base::CommandLine& command_line) { 2642 // By default, dev, canary, and unbranded Chromium users will go to the 2643 // development servers. Development servers have more features than standard 2644 // sync servers. Users with officially-branded Chrome stable and beta builds 2645 // will go to the standard sync servers. 2646 GURL result(kDevServerUrl); 2647 2648 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); 2649 if (channel == chrome::VersionInfo::CHANNEL_STABLE || 2650 channel == chrome::VersionInfo::CHANNEL_BETA) { 2651 result = GURL(kSyncServerUrl); 2652 } 2653 2654 // Override the sync server URL from the command-line, if sync server 2655 // command-line argument exists. 2656 if (command_line.HasSwitch(switches::kSyncServiceURL)) { 2657 std::string value(command_line.GetSwitchValueASCII( 2658 switches::kSyncServiceURL)); 2659 if (!value.empty()) { 2660 GURL custom_sync_url(value); 2661 if (custom_sync_url.is_valid()) { 2662 result = custom_sync_url; 2663 } else { 2664 LOG(WARNING) << "The following sync URL specified at the command-line " 2665 << "is invalid: " << value; 2666 } 2667 } 2668 } 2669 return result; 2670} 2671 2672void ProfileSyncService::CheckSyncBackupIfNeeded() { 2673 DCHECK_EQ(backend_mode_, SYNC); 2674 2675#if defined(ENABLE_PRE_SYNC_BACKUP) 2676 // Check backup once a day. 2677 if (!last_backup_time_ && 2678 (last_synced_time_.is_null() || 2679 base::Time::Now() - last_synced_time_ >= 2680 base::TimeDelta::FromDays(1))) { 2681 // If sync thread is set, need to serialize check on sync thread after 2682 // closing backup DB. 2683 if (sync_thread_) { 2684 sync_thread_->message_loop_proxy()->PostTask( 2685 FROM_HERE, 2686 base::Bind(syncer::CheckSyncDbLastModifiedTime, 2687 profile_->GetPath().Append(kSyncBackupDataFolderName), 2688 base::MessageLoopProxy::current(), 2689 base::Bind(&ProfileSyncService::CheckSyncBackupCallback, 2690 weak_factory_.GetWeakPtr()))); 2691 } else { 2692 content::BrowserThread::PostTask( 2693 content::BrowserThread::FILE, FROM_HERE, 2694 base::Bind(syncer::CheckSyncDbLastModifiedTime, 2695 profile_->GetPath().Append(kSyncBackupDataFolderName), 2696 base::MessageLoopProxy::current(), 2697 base::Bind(&ProfileSyncService::CheckSyncBackupCallback, 2698 weak_factory_.GetWeakPtr()))); 2699 } 2700 } 2701#endif 2702} 2703 2704void ProfileSyncService::CheckSyncBackupCallback(base::Time backup_time) { 2705 last_backup_time_.reset(new base::Time(backup_time)); 2706 2707 DCHECK(device_info_sync_service_); 2708 device_info_sync_service_->UpdateLocalDeviceBackupTime(*last_backup_time_); 2709} 2710 2711void ProfileSyncService::TryStartSyncAfterBackup() { 2712 startup_controller_.Reset(GetRegisteredDataTypes()); 2713 startup_controller_.TryStart(); 2714} 2715 2716void ProfileSyncService::CleanUpBackup() { 2717 sync_prefs_.ClearFirstSyncTime(); 2718 profile_->GetIOTaskRunner()->PostTask( 2719 FROM_HERE, 2720 base::Bind(base::IgnoreResult(base::DeleteFile), 2721 profile_->GetPath().Append(kSyncBackupDataFolderName), 2722 true)); 2723} 2724 2725bool ProfileSyncService::NeedBackup() const { 2726 return need_backup_; 2727} 2728 2729base::Time ProfileSyncService::GetDeviceBackupTimeForTesting() const { 2730 return device_info_sync_service_->GetLocalDeviceBackupTime(); 2731} 2732