profile_sync_service.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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 <set> 10#include <utility> 11 12#include "base/basictypes.h" 13#include "base/bind.h" 14#include "base/callback.h" 15#include "base/command_line.h" 16#include "base/compiler_specific.h" 17#include "base/logging.h" 18#include "base/memory/ref_counted.h" 19#include "base/message_loop/message_loop.h" 20#include "base/metrics/histogram.h" 21#include "base/strings/string16.h" 22#include "base/strings/stringprintf.h" 23#include "base/threading/thread_restrictions.h" 24#include "build/build_config.h" 25#include "chrome/browser/browser_process.h" 26#include "chrome/browser/chrome_notification_types.h" 27#include "chrome/browser/defaults.h" 28#include "chrome/browser/net/chrome_cookie_notification_details.h" 29#include "chrome/browser/prefs/pref_service_syncable.h" 30#include "chrome/browser/profiles/profile.h" 31#include "chrome/browser/signin/about_signin_internals.h" 32#include "chrome/browser/signin/about_signin_internals_factory.h" 33#include "chrome/browser/signin/profile_oauth2_token_service.h" 34#include "chrome/browser/signin/signin_manager.h" 35#include "chrome/browser/signin/signin_manager_factory.h" 36#include "chrome/browser/signin/token_service.h" 37#include "chrome/browser/signin/token_service_factory.h" 38#include "chrome/browser/sync/backend_migrator.h" 39#include "chrome/browser/sync/glue/change_processor.h" 40#include "chrome/browser/sync/glue/chrome_encryptor.h" 41#include "chrome/browser/sync/glue/chrome_report_unrecoverable_error.h" 42#include "chrome/browser/sync/glue/data_type_controller.h" 43#include "chrome/browser/sync/glue/device_info.h" 44#include "chrome/browser/sync/glue/session_data_type_controller.h" 45#include "chrome/browser/sync/glue/session_model_associator.h" 46#include "chrome/browser/sync/glue/synced_device_tracker.h" 47#include "chrome/browser/sync/glue/typed_url_data_type_controller.h" 48#include "chrome/browser/sync/profile_sync_components_factory_impl.h" 49#include "chrome/browser/sync/sync_global_error.h" 50#include "chrome/browser/sync/user_selectable_sync_type.h" 51#include "chrome/browser/ui/browser.h" 52#include "chrome/browser/ui/browser_list.h" 53#include "chrome/browser/ui/browser_window.h" 54#include "chrome/browser/ui/global_error/global_error_service.h" 55#include "chrome/browser/ui/global_error/global_error_service_factory.h" 56#include "chrome/common/chrome_switches.h" 57#include "chrome/common/chrome_version_info.h" 58#include "chrome/common/pref_names.h" 59#include "chrome/common/url_constants.h" 60#include "components/user_prefs/pref_registry_syncable.h" 61#include "content/public/browser/notification_details.h" 62#include "content/public/browser/notification_service.h" 63#include "content/public/browser/notification_source.h" 64#include "google_apis/gaia/gaia_constants.h" 65#include "grit/generated_resources.h" 66#include "net/cookies/cookie_monster.h" 67#include "net/url_request/url_request_context_getter.h" 68#include "sync/api/sync_error.h" 69#include "sync/internal_api/public/configure_reason.h" 70#include "sync/internal_api/public/sync_encryption_handler.h" 71#include "sync/internal_api/public/util/experiments.h" 72#include "sync/internal_api/public/util/sync_string_conversions.h" 73#include "sync/js/js_arg_list.h" 74#include "sync/js/js_event_details.h" 75#include "sync/util/cryptographer.h" 76#include "ui/base/l10n/l10n_util.h" 77#include "ui/base/l10n/time_format.h" 78 79#if defined(ENABLE_MANAGED_USERS) 80#include "chrome/browser/managed_mode/managed_user_service.h" 81#endif 82 83#if defined(OS_ANDROID) 84#include "sync/internal_api/public/read_transaction.h" 85#endif 86 87using browser_sync::ChangeProcessor; 88using browser_sync::DataTypeController; 89using browser_sync::DataTypeManager; 90using browser_sync::FailedDataTypesHandler; 91using browser_sync::SyncBackendHost; 92using syncer::ModelType; 93using syncer::ModelTypeSet; 94using syncer::JsBackend; 95using syncer::JsController; 96using syncer::JsEventDetails; 97using syncer::JsEventHandler; 98using syncer::ModelSafeRoutingInfo; 99using syncer::SyncCredentials; 100using syncer::SyncProtocolError; 101using syncer::WeakHandle; 102 103typedef GoogleServiceAuthError AuthError; 104 105const char* ProfileSyncService::kSyncServerUrl = 106 "https://clients4.google.com/chrome-sync"; 107 108const char* ProfileSyncService::kDevServerUrl = 109 "https://clients4.google.com/chrome-sync/dev"; 110 111const char kSyncUnrecoverableErrorHistogram[] = 112 "Sync.UnrecoverableErrors"; 113 114const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = { 115 // Number of initial errors (in sequence) to ignore before applying 116 // exponential back-off rules. 117 0, 118 119 // Initial delay for exponential back-off in ms. 120 2000, 121 122 // Factor by which the waiting time will be multiplied. 123 2, 124 125 // Fuzzing percentage. ex: 10% will spread requests randomly 126 // between 90%-100% of the calculated time. 127 0.2, // 20% 128 129 // Maximum amount of time we are willing to delay our request in ms. 130 // TODO(pavely): crbug.com/246686 ProfileSyncService should retry 131 // RequestAccessToken on connection state change after backoff 132 1000 * 3600 * 4, // 4 hours. 133 134 // Time to keep an entry from being discarded even when it 135 // has no significant state, -1 to never discard. 136 -1, 137 138 // Don't use initial delay unless the last request was an error. 139 false, 140}; 141 142bool ShouldShowActionOnUI( 143 const syncer::SyncProtocolError& error) { 144 return (error.action != syncer::UNKNOWN_ACTION && 145 error.action != syncer::DISABLE_SYNC_ON_CLIENT && 146 error.action != syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT); 147} 148 149ProfileSyncService::ProfileSyncService( 150 ProfileSyncComponentsFactory* factory, 151 Profile* profile, 152 SigninManagerBase* signin_manager, 153 ProfileOAuth2TokenService* oauth2_token_service, 154 StartBehavior start_behavior) 155 : last_auth_error_(AuthError::AuthErrorNone()), 156 passphrase_required_reason_(syncer::REASON_PASSPHRASE_NOT_REQUIRED), 157 factory_(factory), 158 profile_(profile), 159 // |profile| may be NULL in unit tests. 160 sync_prefs_(profile_ ? profile_->GetPrefs() : NULL), 161 sync_service_url_(kDevServerUrl), 162 data_type_requested_sync_startup_(false), 163 is_first_time_sync_configure_(false), 164 backend_initialized_(false), 165 sync_disabled_by_admin_(false), 166 is_auth_in_progress_(false), 167 signin_(signin_manager), 168 unrecoverable_error_reason_(ERROR_REASON_UNSET), 169 weak_factory_(this), 170 expect_sync_configuration_aborted_(false), 171 encrypted_types_(syncer::SyncEncryptionHandler::SensitiveTypes()), 172 encrypt_everything_(false), 173 encryption_pending_(false), 174 auto_start_enabled_(start_behavior == AUTO_START), 175 configure_status_(DataTypeManager::UNKNOWN), 176 setup_in_progress_(false), 177 use_oauth2_token_(false), 178 oauth2_token_service_(oauth2_token_service), 179 request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy) { 180 // By default, dev, canary, and unbranded Chromium users will go to the 181 // development servers. Development servers have more features than standard 182 // sync servers. Users with officially-branded Chrome stable and beta builds 183 // will go to the standard sync servers. 184 // 185 // GetChannel hits the registry on Windows. See http://crbug.com/70380. 186 base::ThreadRestrictions::ScopedAllowIO allow_io; 187 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); 188 if (channel == chrome::VersionInfo::CHANNEL_STABLE || 189 channel == chrome::VersionInfo::CHANNEL_BETA) { 190 sync_service_url_ = GURL(kSyncServerUrl); 191 } 192} 193 194ProfileSyncService::~ProfileSyncService() { 195 sync_prefs_.RemoveSyncPrefObserver(this); 196 // Shutdown() should have been called before destruction. 197 CHECK(!backend_initialized_); 198} 199 200bool ProfileSyncService::IsSyncEnabledAndLoggedIn() { 201 // Exit if sync is disabled. 202 if (IsManaged() || sync_prefs_.IsStartSuppressed()) 203 return false; 204 205 // Sync is logged in if there is a non-empty effective username. 206 return !GetEffectiveUsername().empty(); 207} 208 209bool ProfileSyncService::IsOAuthRefreshTokenAvailable() { 210 // Function name doesn't reflect which token is checked. Function checks 211 // refresh token when use_oauth2_token_ is true (all platforms except android) 212 // and sync token otherwise (for android). 213 // TODO(pavely): Remove "else" part once use_oauth2_token_ is gone. 214 if (use_oauth2_token_) { 215 if (!oauth2_token_service_) 216 return false; 217 return oauth2_token_service_->RefreshTokenIsAvailable( 218 oauth2_token_service_->GetPrimaryAccountId()); 219 } else { 220 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); 221 if (!token_service) 222 return false; 223 224 return token_service->HasTokenForService(GaiaConstants::kSyncService); 225 } 226} 227 228void ProfileSyncService::Initialize() { 229 if (profile_) 230 SigninGlobalError::GetForProfile(profile_)->AddProvider(this); 231 232 InitSettings(); 233 234 // We clear this here (vs Shutdown) because we want to remember that an error 235 // happened on shutdown so we can display details (message, location) about it 236 // in about:sync. 237 ClearStaleErrors(); 238 239 sync_prefs_.AddSyncPrefObserver(this); 240 241 // For now, the only thing we can do through policy is to turn sync off. 242 if (IsManaged()) { 243 DisableForUser(); 244 return; 245 } 246 247 RegisterAuthNotifications(); 248 249 if (!HasSyncSetupCompleted() || GetEffectiveUsername().empty()) { 250 // Clean up in case of previous crash / setup abort / signout. 251 DisableForUser(); 252 } 253 254 TrySyncDatatypePrefRecovery(); 255 256 TryStart(); 257} 258 259void ProfileSyncService::TrySyncDatatypePrefRecovery() { 260 DCHECK(!sync_initialized()); 261 if (!HasSyncSetupCompleted()) 262 return; 263 264 // There was a bug where OnUserChoseDatatypes was not properly called on 265 // configuration (see crbug.com/154940). We detect this by checking whether 266 // kSyncKeepEverythingSynced has a default value. If so, and sync setup has 267 // completed, it means sync was not properly configured, so we manually 268 // set kSyncKeepEverythingSynced. 269 PrefService* const pref_service = profile_->GetPrefs(); 270 if (!pref_service) 271 return; 272 if (GetPreferredDataTypes().Size() > 1) 273 return; 274 275 const PrefService::Preference* keep_everything_synced = 276 pref_service->FindPreference(prefs::kSyncKeepEverythingSynced); 277 // This will be false if the preference was properly set or if it's controlled 278 // by policy. 279 if (!keep_everything_synced->IsDefaultValue()) 280 return; 281 282 // kSyncKeepEverythingSynced was not properly set. Set it and the preferred 283 // types now, before we configure. 284 UMA_HISTOGRAM_COUNTS("Sync.DatatypePrefRecovery", 1); 285 sync_prefs_.SetKeepEverythingSynced(true); 286 syncer::ModelTypeSet registered_types = GetRegisteredDataTypes(); 287 sync_prefs_.SetPreferredDataTypes(registered_types, 288 registered_types); 289} 290 291void ProfileSyncService::TryStart() { 292 if (!IsSyncEnabledAndLoggedIn()) 293 return; 294 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); 295 if (!token_service) 296 return; 297 // Don't start the backend if the token service hasn't finished loading tokens 298 // yet. Note if the backend is started before the sync token has been loaded, 299 // GetCredentials() will return bogus credentials. On auto_start platforms 300 // (like ChromeOS) we don't start sync until tokens are loaded, because the 301 // user can be "signed in" on those platforms long before the tokens get 302 // loaded, and we don't want to generate spurious auth errors. 303 if (!IsOAuthRefreshTokenAvailable() && 304 !(!auto_start_enabled_ && token_service->TokensLoadedFromDB())) { 305 return; 306 } 307 308 if (use_oauth2_token_) { 309 // If we got here then tokens are loaded and user logged in and sync is 310 // enabled. If OAuth refresh token is not available then something is wrong. 311 // When PSS requests access token, OAuth2TokenService will return error and 312 // PSS will show error to user asking to reauthenticate. 313 UMA_HISTOGRAM_BOOLEAN("Sync.RefreshTokenAvailable", 314 IsOAuthRefreshTokenAvailable()); 315 } 316 317 // If sync setup has completed we always start the backend. If the user is in 318 // the process of setting up now, we should start the backend to download 319 // account control state / encryption information). If autostart is enabled, 320 // but we haven't completed sync setup, we try to start sync anyway, since 321 // it's possible we crashed/shutdown after logging in but before the backend 322 // finished initializing the last time. 323 // 324 // However, the only time we actually need to start sync _immediately_ is if 325 // we haven't completed sync setup and the user is in the process of setting 326 // up - either they just signed in (for the first time) on an auto-start 327 // platform or they explicitly kicked off sync setup, and e.g we need to 328 // fetch account details like encryption state to populate UI. Otherwise, 329 // for performance reasons and maximizing parallelism at chrome startup, we 330 // defer the heavy lifting for sync init until things have calmed down. 331 if (HasSyncSetupCompleted()) { 332 if (!data_type_requested_sync_startup_) 333 StartUp(STARTUP_BACKEND_DEFERRED); 334 else if (start_up_time_.is_null()) 335 StartUp(STARTUP_IMMEDIATE); 336 else 337 StartUpSlowBackendComponents(); 338 } else if (setup_in_progress_ || auto_start_enabled_) { 339 // We haven't completed sync setup. Start immediately if the user explicitly 340 // kicked this off or we're supposed to automatically start syncing. 341 StartUp(STARTUP_IMMEDIATE); 342 } 343} 344 345void ProfileSyncService::StartSyncingWithServer() { 346 if (backend_) 347 backend_->StartSyncingWithServer(); 348} 349 350void ProfileSyncService::RegisterAuthNotifications() { 351 oauth2_token_service_->AddObserver(this); 352 353 registrar_.Add(this, 354 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, 355 content::Source<Profile>(profile_)); 356 registrar_.Add(this, 357 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, 358 content::Source<Profile>(profile_)); 359} 360 361void ProfileSyncService::UnregisterAuthNotifications() { 362 oauth2_token_service_->RemoveObserver(this); 363 registrar_.RemoveAll(); 364} 365 366void ProfileSyncService::RegisterDataTypeController( 367 DataTypeController* data_type_controller) { 368 DCHECK_EQ(data_type_controllers_.count(data_type_controller->type()), 0U); 369 data_type_controllers_[data_type_controller->type()] = 370 data_type_controller; 371} 372 373browser_sync::SessionModelAssociator* 374 ProfileSyncService::GetSessionModelAssociator() { 375 if (data_type_controllers_.find(syncer::SESSIONS) == 376 data_type_controllers_.end() || 377 data_type_controllers_.find(syncer::SESSIONS)->second->state() != 378 DataTypeController::RUNNING) { 379 return NULL; 380 } 381 return static_cast<browser_sync::SessionDataTypeController*>( 382 data_type_controllers_.find( 383 syncer::SESSIONS)->second.get())->GetModelAssociator(); 384} 385 386scoped_ptr<browser_sync::DeviceInfo> 387ProfileSyncService::GetLocalDeviceInfo() const { 388 if (backend_) { 389 browser_sync::SyncedDeviceTracker* device_tracker = 390 backend_->GetSyncedDeviceTracker(); 391 if (device_tracker) 392 return device_tracker->ReadLocalDeviceInfo(); 393 } 394 return scoped_ptr<browser_sync::DeviceInfo>(); 395} 396 397scoped_ptr<browser_sync::DeviceInfo> 398ProfileSyncService::GetDeviceInfo(const std::string& client_id) const { 399 if (backend_) { 400 browser_sync::SyncedDeviceTracker* device_tracker = 401 backend_->GetSyncedDeviceTracker(); 402 if (device_tracker) 403 return device_tracker->ReadDeviceInfo(client_id); 404 } 405 return scoped_ptr<browser_sync::DeviceInfo>(); 406} 407 408ScopedVector<browser_sync::DeviceInfo> 409 ProfileSyncService::GetAllSignedInDevices() const { 410 ScopedVector<browser_sync::DeviceInfo> devices; 411 if (backend_) { 412 browser_sync::SyncedDeviceTracker* device_tracker = 413 backend_->GetSyncedDeviceTracker(); 414 if (device_tracker) { 415 // TODO(lipalani) - Make device tracker return a scoped vector. 416 device_tracker->GetAllSyncedDeviceInfo(&devices); 417 } 418 } 419 return devices.Pass(); 420} 421 422// Notifies the observer of any device info changes. 423void ProfileSyncService::AddObserverForDeviceInfoChange( 424 browser_sync::SyncedDeviceTracker::Observer* observer) { 425 if (backend_) { 426 browser_sync::SyncedDeviceTracker* device_tracker = 427 backend_->GetSyncedDeviceTracker(); 428 if (device_tracker) { 429 device_tracker->AddObserver(observer); 430 } 431 } 432} 433 434// Removes the observer from device info change notification. 435void ProfileSyncService::RemoveObserverForDeviceInfoChange( 436 browser_sync::SyncedDeviceTracker::Observer* observer) { 437 if (backend_) { 438 browser_sync::SyncedDeviceTracker* device_tracker = 439 backend_->GetSyncedDeviceTracker(); 440 if (device_tracker) { 441 device_tracker->RemoveObserver(observer); 442 } 443 } 444} 445 446void ProfileSyncService::GetDataTypeControllerStates( 447 browser_sync::DataTypeController::StateMap* state_map) const { 448 for (browser_sync::DataTypeController::TypeMap::const_iterator iter = 449 data_type_controllers_.begin(); iter != data_type_controllers_.end(); 450 ++iter) 451 (*state_map)[iter->first] = iter->second.get()->state(); 452} 453 454void ProfileSyncService::InitSettings() { 455 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 456 457 // Override the sync server URL from the command-line, if sync server 458 // command-line argument exists. 459 if (command_line.HasSwitch(switches::kSyncServiceURL)) { 460 std::string value(command_line.GetSwitchValueASCII( 461 switches::kSyncServiceURL)); 462 if (!value.empty()) { 463 GURL custom_sync_url(value); 464 if (custom_sync_url.is_valid()) { 465 sync_service_url_ = custom_sync_url; 466 } else { 467 LOG(WARNING) << "The following sync URL specified at the command-line " 468 << "is invalid: " << value; 469 } 470 } 471 } 472 473 use_oauth2_token_ = !command_line.HasSwitch( 474 switches::kSyncDisableOAuth2Token); 475} 476 477SyncCredentials ProfileSyncService::GetCredentials() { 478 SyncCredentials credentials; 479 credentials.email = GetEffectiveUsername(); 480 DCHECK(!credentials.email.empty()); 481 if (use_oauth2_token_) { 482 credentials.sync_token = access_token_; 483 } else { 484 TokenService* service = TokenServiceFactory::GetForProfile(profile_); 485 if (service->HasTokenForService(GaiaConstants::kSyncService)) { 486 credentials.sync_token = service->GetTokenForService( 487 GaiaConstants::kSyncService); 488 } 489 } 490 491 if (credentials.sync_token.empty()) 492 credentials.sync_token = "credentials_lost"; 493 return credentials; 494} 495 496void ProfileSyncService::InitializeBackend(bool delete_stale_data) { 497 if (!backend_) { 498 NOTREACHED(); 499 return; 500 } 501 502 SyncCredentials credentials = GetCredentials(); 503 504 scoped_refptr<net::URLRequestContextGetter> request_context_getter( 505 profile_->GetRequestContext()); 506 507 if (delete_stale_data) 508 ClearStaleErrors(); 509 510 scoped_ptr<syncer::UnrecoverableErrorHandler> 511 backend_unrecoverable_error_handler( 512 new browser_sync::BackendUnrecoverableErrorHandler( 513 MakeWeakHandle(weak_factory_.GetWeakPtr()))); 514 515 backend_->Initialize( 516 this, 517 sync_thread_.Pass(), 518 GetJsEventHandler(), 519 sync_service_url_, 520 credentials, 521 delete_stale_data, 522 scoped_ptr<syncer::SyncManagerFactory>( 523 new syncer::SyncManagerFactory).Pass(), 524 backend_unrecoverable_error_handler.Pass(), 525 &browser_sync::ChromeReportUnrecoverableError); 526} 527 528void ProfileSyncService::CreateBackend() { 529 backend_.reset( 530 new SyncBackendHost(profile_->GetDebugName(), 531 profile_, sync_prefs_.AsWeakPtr())); 532} 533 534bool ProfileSyncService::IsEncryptedDatatypeEnabled() const { 535 if (encryption_pending()) 536 return true; 537 const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes(); 538 const syncer::ModelTypeSet encrypted_types = GetEncryptedDataTypes(); 539 DCHECK(encrypted_types.Has(syncer::PASSWORDS)); 540 return !Intersection(preferred_types, encrypted_types).Empty(); 541} 542 543void ProfileSyncService::OnSyncConfigureRetry() { 544 // Note: in order to handle auth failures that arise before the backend is 545 // initialized (e.g. from invalidation notifier, or downloading new control 546 // types), we have to gracefully handle configuration retries at all times. 547 // At this point an auth error badge should be shown, which once resolved 548 // will trigger a new sync cycle. 549 NotifyObservers(); 550} 551 552void ProfileSyncService::StartUp(StartUpDeferredOption deferred_option) { 553 // Don't start up multiple times. 554 if (backend_) { 555 DVLOG(1) << "Skipping bringing up backend host."; 556 return; 557 } 558 559 DCHECK(IsSyncEnabledAndLoggedIn()); 560 561 if (start_up_time_.is_null()) { 562 start_up_time_ = base::Time::Now(); 563 last_synced_time_ = sync_prefs_.GetLastSyncedTime(); 564 565#if defined(OS_CHROMEOS) 566 std::string bootstrap_token = sync_prefs_.GetEncryptionBootstrapToken(); 567 if (bootstrap_token.empty()) { 568 sync_prefs_.SetEncryptionBootstrapToken( 569 sync_prefs_.GetSpareBootstrapToken()); 570 } 571#endif 572 573#if !defined(OS_ANDROID) 574 if (!sync_global_error_) { 575 sync_global_error_.reset(new SyncGlobalError(this, signin())); 576 GlobalErrorServiceFactory::GetForProfile(profile_)->AddGlobalError( 577 sync_global_error_.get()); 578 AddObserver(sync_global_error_.get()); 579 } 580#endif 581 } else { 582 // We don't care to prevent multiple calls to StartUp in deferred mode 583 // because it's fast and has no side effects. 584 DCHECK_EQ(STARTUP_BACKEND_DEFERRED, deferred_option); 585 } 586 587 if (deferred_option == STARTUP_BACKEND_DEFERRED && 588 CommandLine::ForCurrentProcess()-> 589 HasSwitch(switches::kSyncEnableDeferredStartup)) { 590 return; 591 } 592 593 StartUpSlowBackendComponents(); 594} 595 596void ProfileSyncService::OnDataTypeRequestsSyncStartup( 597 syncer::ModelType type) { 598 DCHECK(syncer::UserTypes().Has(type)); 599 if (backend_.get()) { 600 DVLOG(1) << "A data type requested sync startup, but it looks like " 601 "something else beat it to the punch."; 602 return; 603 } 604 605 if (!GetActiveDataTypes().Has(type)) { 606 // We can get here as datatype SyncableServices are typically wired up 607 // to the native datatype even if sync isn't enabled. 608 DVLOG(1) << "Dropping sync startup request because type " 609 << syncer::ModelTypeToString(type) << "not enabled."; 610 return; 611 } 612 613 if (CommandLine::ForCurrentProcess()->HasSwitch( 614 switches::kSyncEnableDeferredStartup)) { 615 DVLOG(2) << "Data type requesting sync startup: " 616 << syncer::ModelTypeToString(type); 617 // Measure the time spent waiting for init and the type that triggered it. 618 // We could measure the time spent deferred on a per-datatype basis, but 619 // for now this is probably sufficient. 620 if (!start_up_time_.is_null()) { 621 // TODO(tim): Cache |type| and move this tracking to StartUp. I'd like 622 // to pull all the complicated init logic and state out of 623 // ProfileSyncService and have only a StartUp method, though. One step 624 // at a time. Bug 80149. 625 base::TimeDelta time_deferred = base::Time::Now() - start_up_time_; 626 UMA_HISTOGRAM_TIMES("Sync.Startup.TimeDeferred", time_deferred); 627 UMA_HISTOGRAM_ENUMERATION("Sync.Startup.TypeTriggeringInit", 628 ModelTypeToHistogramInt(type), 629 syncer::MODEL_TYPE_COUNT); 630 } 631 data_type_requested_sync_startup_ = true; 632 TryStart(); 633 } 634 DVLOG(2) << "Ignoring data type request for sync startup: " 635 << syncer::ModelTypeToString(type); 636} 637 638void ProfileSyncService::StartUpSlowBackendComponents() { 639 // Don't start up multiple times. 640 if (backend_) { 641 DVLOG(1) << "Skipping bringing up backend host."; 642 return; 643 } 644 645 DCHECK(IsSyncEnabledAndLoggedIn()); 646 CreateBackend(); 647 648 // Initialize the backend. Every time we start up a new SyncBackendHost, 649 // we'll want to start from a fresh SyncDB, so delete any old one that might 650 // be there. 651 InitializeBackend(!HasSyncSetupCompleted()); 652} 653 654void ProfileSyncService::OnGetTokenSuccess( 655 const OAuth2TokenService::Request* request, 656 const std::string& access_token, 657 const base::Time& expiration_time) { 658 DCHECK_EQ(access_token_request_, request); 659 access_token_request_.reset(); 660 // Reset backoff time after successful response. 661 request_access_token_backoff_.Reset(); 662 access_token_ = access_token; 663 if (backend_) 664 backend_->UpdateCredentials(GetCredentials()); 665 else 666 TryStart(); 667} 668 669void ProfileSyncService::OnGetTokenFailure( 670 const OAuth2TokenService::Request* request, 671 const GoogleServiceAuthError& error) { 672 DCHECK_EQ(access_token_request_, request); 673 DCHECK_NE(error.state(), GoogleServiceAuthError::NONE); 674 access_token_request_.reset(); 675 switch (error.state()) { 676 case GoogleServiceAuthError::CONNECTION_FAILED: 677 case GoogleServiceAuthError::SERVICE_UNAVAILABLE: { 678 // Transient error. Retry after some time. 679 request_access_token_backoff_.InformOfRequest(false); 680 request_access_token_retry_timer_.Start( 681 FROM_HERE, 682 request_access_token_backoff_.GetTimeUntilRelease(), 683 base::Bind(&ProfileSyncService::RequestAccessToken, 684 weak_factory_.GetWeakPtr())); 685 break; 686 } 687 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: { 688 // Report time since token was issued for invalid credentials error. 689 base::Time auth_token_time = 690 AboutSigninInternalsFactory::GetForProfile(profile_)-> 691 GetTokenTime(GaiaConstants::kGaiaOAuth2LoginRefreshToken); 692 if (!auth_token_time.is_null()) { 693 base::TimeDelta age = base::Time::Now() - auth_token_time; 694 if (age < base::TimeDelta::FromHours(1)) { 695 UMA_HISTOGRAM_CUSTOM_TIMES("Sync.AuthServerRejectedTokenAgeShort", 696 age, 697 base::TimeDelta::FromSeconds(1), 698 base::TimeDelta::FromHours(1), 699 50); 700 } 701 UMA_HISTOGRAM_COUNTS("Sync.AuthServerRejectedTokenAgeLong", 702 age.InDays()); 703 } 704 // Fallthrough. 705 } 706 default: { 707 // Show error to user. 708 UpdateAuthErrorState(error); 709 } 710 } 711} 712 713void ProfileSyncService::OnRefreshTokenAvailable( 714 const std::string& account_id) { 715 if (oauth2_token_service_->GetPrimaryAccountId() == account_id) 716 OnRefreshTokensLoaded(); 717} 718 719void ProfileSyncService::OnRefreshTokenRevoked( 720 const std::string& account_id) { 721 if (!IsOAuthRefreshTokenAvailable()) { 722 access_token_.clear(); 723 // The additional check around IsOAuthRefreshTokenAvailable() above 724 // prevents us sounding the alarm if we actually have a valid token but 725 // a refresh attempt by TokenService failed for any variety of reasons 726 // (e.g. flaky network). It's possible the token we do have is also 727 // invalid, but in that case we should already have (or can expect) an 728 // auth error sent from the sync backend. 729 UpdateAuthErrorState( 730 GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED)); 731 } 732} 733 734void ProfileSyncService::OnRefreshTokensLoaded() { 735 // This notification gets fired when TokenService loads the tokens 736 // from storage. 737 // Initialize the backend if sync is enabled. If the sync token was 738 // not loaded, GetCredentials() will generate invalid credentials to 739 // cause the backend to generate an auth error (crbug.com/121755). 740 if (backend_) { 741 RequestAccessToken(); 742 } else { 743 TryStart(); 744 } 745} 746 747void ProfileSyncService::Shutdown() { 748 UnregisterAuthNotifications(); 749 750 if (profile_) 751 SigninGlobalError::GetForProfile(profile_)->RemoveProvider(this); 752 753 ShutdownImpl(browser_sync::SyncBackendHost::STOP); 754 755 if (sync_thread_) 756 sync_thread_->Stop(); 757} 758 759void ProfileSyncService::ShutdownImpl( 760 browser_sync::SyncBackendHost::ShutdownOption option) { 761 if (!backend_) 762 return; 763 764 // First, we spin down the backend to stop change processing as soon as 765 // possible. 766 base::Time shutdown_start_time = base::Time::Now(); 767 backend_->StopSyncingForShutdown(); 768 769 // Stop all data type controllers, if needed. Note that until Stop 770 // completes, it is possible in theory to have a ChangeProcessor apply a 771 // change from a native model. In that case, it will get applied to the sync 772 // database (which doesn't get destroyed until we destroy the backend below) 773 // as an unsynced change. That will be persisted, and committed on restart. 774 if (data_type_manager_) { 775 if (data_type_manager_->state() != DataTypeManager::STOPPED) { 776 // When aborting as part of shutdown, we should expect an aborted sync 777 // configure result, else we'll dcheck when we try to read the sync error. 778 expect_sync_configuration_aborted_ = true; 779 data_type_manager_->Stop(); 780 } 781 data_type_manager_.reset(); 782 } 783 784 // Shutdown the migrator before the backend to ensure it doesn't pull a null 785 // snapshot. 786 migrator_.reset(); 787 sync_js_controller_.AttachJsBackend(WeakHandle<syncer::JsBackend>()); 788 789 // Move aside the backend so nobody else tries to use it while we are 790 // shutting it down. 791 scoped_ptr<SyncBackendHost> doomed_backend(backend_.release()); 792 if (doomed_backend) { 793 sync_thread_ = doomed_backend->Shutdown(option); 794 doomed_backend.reset(); 795 } 796 base::TimeDelta shutdown_time = base::Time::Now() - shutdown_start_time; 797 UMA_HISTOGRAM_TIMES("Sync.Shutdown.BackendDestroyedTime", shutdown_time); 798 799 weak_factory_.InvalidateWeakPtrs(); 800 801 // Clear various flags. 802 start_up_time_ = base::Time(); 803 expect_sync_configuration_aborted_ = false; 804 is_auth_in_progress_ = false; 805 backend_initialized_ = false; 806 cached_passphrase_.clear(); 807 encryption_pending_ = false; 808 encrypt_everything_ = false; 809 encrypted_types_ = syncer::SyncEncryptionHandler::SensitiveTypes(); 810 passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED; 811 request_access_token_retry_timer_.Stop(); 812 // Revert to "no auth error". 813 if (last_auth_error_.state() != GoogleServiceAuthError::NONE) 814 UpdateAuthErrorState(GoogleServiceAuthError::AuthErrorNone()); 815 816 if (sync_global_error_) { 817 GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveGlobalError( 818 sync_global_error_.get()); 819 RemoveObserver(sync_global_error_.get()); 820 sync_global_error_.reset(NULL); 821 } 822 823 NotifyObservers(); 824} 825 826void ProfileSyncService::DisableForUser() { 827 // Clear prefs (including SyncSetupHasCompleted) before shutting down so 828 // PSS clients don't think we're set up while we're shutting down. 829 sync_prefs_.ClearPreferences(); 830 ClearUnrecoverableError(); 831 ShutdownImpl(browser_sync::SyncBackendHost::DISABLE_AND_CLAIM_THREAD); 832} 833 834bool ProfileSyncService::HasSyncSetupCompleted() const { 835 return sync_prefs_.HasSyncSetupCompleted(); 836} 837 838void ProfileSyncService::SetSyncSetupCompleted() { 839 sync_prefs_.SetSyncSetupCompleted(); 840} 841 842void ProfileSyncService::UpdateLastSyncedTime() { 843 last_synced_time_ = base::Time::Now(); 844 sync_prefs_.SetLastSyncedTime(last_synced_time_); 845} 846 847void ProfileSyncService::NotifyObservers() { 848 FOR_EACH_OBSERVER(ProfileSyncServiceBase::Observer, observers_, 849 OnStateChanged()); 850 // TODO(akalin): Make an Observer subclass that listens and does the 851 // event routing. 852 sync_js_controller_.HandleJsEvent("onServiceStateChanged", JsEventDetails()); 853} 854 855void ProfileSyncService::NotifySyncCycleCompleted() { 856 FOR_EACH_OBSERVER(ProfileSyncServiceBase::Observer, observers_, 857 OnSyncCycleCompleted()); 858 sync_js_controller_.HandleJsEvent( 859 "onServiceStateChanged", JsEventDetails()); 860} 861 862void ProfileSyncService::ClearStaleErrors() { 863 ClearUnrecoverableError(); 864 last_actionable_error_ = SyncProtocolError(); 865 // Clear the data type errors as well. 866 failed_data_types_handler_.Reset(); 867} 868 869void ProfileSyncService::ClearUnrecoverableError() { 870 unrecoverable_error_reason_ = ERROR_REASON_UNSET; 871 unrecoverable_error_message_.clear(); 872 unrecoverable_error_location_ = tracked_objects::Location(); 873} 874 875void ProfileSyncService::RegisterNewDataType(syncer::ModelType data_type) { 876 if (data_type_controllers_.count(data_type) > 0) 877 return; 878 NOTREACHED(); 879} 880 881// An invariant has been violated. Transition to an error state where we try 882// to do as little work as possible, to avoid further corruption or crashes. 883void ProfileSyncService::OnUnrecoverableError( 884 const tracked_objects::Location& from_here, 885 const std::string& message) { 886 // Unrecoverable errors that arrive via the syncer::UnrecoverableErrorHandler 887 // interface are assumed to originate within the syncer. 888 unrecoverable_error_reason_ = ERROR_REASON_SYNCER; 889 OnUnrecoverableErrorImpl(from_here, message, true); 890} 891 892void ProfileSyncService::OnUnrecoverableErrorImpl( 893 const tracked_objects::Location& from_here, 894 const std::string& message, 895 bool delete_sync_database) { 896 DCHECK(HasUnrecoverableError()); 897 unrecoverable_error_message_ = message; 898 unrecoverable_error_location_ = from_here; 899 900 UMA_HISTOGRAM_ENUMERATION(kSyncUnrecoverableErrorHistogram, 901 unrecoverable_error_reason_, 902 ERROR_REASON_LIMIT); 903 NotifyObservers(); 904 std::string location; 905 from_here.Write(true, true, &location); 906 LOG(ERROR) 907 << "Unrecoverable error detected at " << location 908 << " -- ProfileSyncService unusable: " << message; 909 910 // Shut all data types down. 911 base::MessageLoop::current()->PostTask(FROM_HERE, 912 base::Bind(&ProfileSyncService::ShutdownImpl, 913 weak_factory_.GetWeakPtr(), 914 delete_sync_database ? 915 browser_sync::SyncBackendHost::DISABLE_AND_CLAIM_THREAD : 916 browser_sync::SyncBackendHost::STOP_AND_CLAIM_THREAD)); 917} 918 919// TODO(zea): Move this logic into the DataTypeController/DataTypeManager. 920void ProfileSyncService::DisableBrokenDatatype( 921 syncer::ModelType type, 922 const tracked_objects::Location& from_here, 923 std::string message) { 924 // First deactivate the type so that no further server changes are 925 // passed onto the change processor. 926 DeactivateDataType(type); 927 928 syncer::SyncError error(from_here, 929 syncer::SyncError::DATATYPE_ERROR, 930 message, 931 type); 932 933 std::map<syncer::ModelType, syncer::SyncError> errors; 934 errors[type] = error; 935 936 // Update this before posting a task. So if a configure happens before 937 // the task that we are going to post, this type would still be disabled. 938 failed_data_types_handler_.UpdateFailedDataTypes(errors); 939 940 base::MessageLoop::current()->PostTask(FROM_HERE, 941 base::Bind(&ProfileSyncService::ReconfigureDatatypeManager, 942 weak_factory_.GetWeakPtr())); 943} 944 945void ProfileSyncService::OnBackendInitialized( 946 const syncer::WeakHandle<syncer::JsBackend>& js_backend, 947 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>& 948 debug_info_listener, 949 bool success) { 950 is_first_time_sync_configure_ = !HasSyncSetupCompleted(); 951 952 if (is_first_time_sync_configure_) { 953 UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeFirstTimeSuccess", success); 954 } else { 955 UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeRestoreSuccess", success); 956 } 957 958 DCHECK(!start_up_time_.is_null()); 959 base::Time on_backend_initialized_time = base::Time::Now(); 960 base::TimeDelta delta = on_backend_initialized_time - start_up_time_; 961 if (is_first_time_sync_configure_) { 962 UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeFirstTime", delta); 963 } else { 964 UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeRestoreTime", delta); 965 } 966 967 if (!success) { 968 // Something went unexpectedly wrong. Play it safe: stop syncing at once 969 // and surface error UI to alert the user sync has stopped. 970 // Keep the directory around for now so that on restart we will retry 971 // again and potentially succeed in presence of transient file IO failures 972 // or permissions issues, etc. 973 // 974 // TODO(rlarocque): Consider making this UnrecoverableError less special. 975 // Unlike every other UnrecoverableError, it does not delete our sync data. 976 // This exception made sense at the time it was implemented, but our new 977 // directory corruption recovery mechanism makes it obsolete. By the time 978 // we get here, we will have already tried and failed to delete the 979 // directory. It would be no big deal if we tried to delete it again. 980 OnInternalUnrecoverableError(FROM_HERE, 981 "BackendInitialize failure", 982 false, 983 ERROR_REASON_BACKEND_INIT_FAILURE); 984 return; 985 } 986 987 backend_initialized_ = true; 988 989 sync_js_controller_.AttachJsBackend(js_backend); 990 debug_info_listener_ = debug_info_listener; 991 992 // If we have a cached passphrase use it to decrypt/encrypt data now that the 993 // backend is initialized. We want to call this before notifying observers in 994 // case this operation affects the "passphrase required" status. 995 ConsumeCachedPassphraseIfPossible(); 996 997 // The very first time the backend initializes is effectively the first time 998 // we can say we successfully "synced". last_synced_time_ will only be null 999 // in this case, because the pref wasn't restored on StartUp. 1000 if (last_synced_time_.is_null()) { 1001 UpdateLastSyncedTime(); 1002 } 1003 1004 if (auto_start_enabled_ && !FirstSetupInProgress()) { 1005 // Backend is initialized but we're not in sync setup, so this must be an 1006 // autostart - mark our sync setup as completed and we'll start syncing 1007 // below. 1008 SetSyncSetupCompleted(); 1009 } 1010 1011 // Check HasSyncSetupCompleted() before NotifyObservers() to avoid spurious 1012 // data type configuration because observer may flag setup as complete and 1013 // trigger data type configuration. 1014 if (HasSyncSetupCompleted()) { 1015 ConfigureDataTypeManager(); 1016 } else { 1017 DCHECK(FirstSetupInProgress()); 1018 } 1019 1020 NotifyObservers(); 1021} 1022 1023void ProfileSyncService::OnSyncCycleCompleted() { 1024 UpdateLastSyncedTime(); 1025 if (GetSessionModelAssociator()) { 1026 // Trigger garbage collection of old sessions now that we've downloaded 1027 // any new session data. TODO(zea): Have this be a notification the session 1028 // model associator listens too. Also consider somehow plumbing the current 1029 // server time as last reported by CheckServerReachable, so we don't have to 1030 // rely on the local clock, which may be off significantly. 1031 base::MessageLoop::current()->PostTask(FROM_HERE, 1032 base::Bind(&browser_sync::SessionModelAssociator::DeleteStaleSessions, 1033 GetSessionModelAssociator()->AsWeakPtr())); 1034 } 1035 DVLOG(2) << "Notifying observers sync cycle completed"; 1036 NotifySyncCycleCompleted(); 1037} 1038 1039void ProfileSyncService::OnExperimentsChanged( 1040 const syncer::Experiments& experiments) { 1041 if (current_experiments_.Matches(experiments)) 1042 return; 1043 1044 // If this is a first time sync for a client, this will be called before 1045 // OnBackendInitialized() to ensure the new datatypes are available at sync 1046 // setup. As a result, the migrator won't exist yet. This is fine because for 1047 // first time sync cases we're only concerned with making the datatype 1048 // available. 1049 if (migrator_.get() && 1050 migrator_->state() != browser_sync::BackendMigrator::IDLE) { 1051 DVLOG(1) << "Dropping OnExperimentsChanged due to migrator busy."; 1052 return; 1053 } 1054 1055 const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes(); 1056 syncer::ModelTypeSet to_add; 1057 const syncer::ModelTypeSet to_register = 1058 Difference(to_add, registered_types); 1059 DVLOG(2) << "OnExperimentsChanged called with types: " 1060 << syncer::ModelTypeSetToString(to_add); 1061 DVLOG(2) << "Enabling types: " << syncer::ModelTypeSetToString(to_register); 1062 1063 for (syncer::ModelTypeSet::Iterator it = to_register.First(); 1064 it.Good(); it.Inc()) { 1065 // Received notice to enable experimental type. Check if the type is 1066 // registered, and if not register a new datatype controller. 1067 RegisterNewDataType(it.Get()); 1068 } 1069 1070 // Check if the user has "Keep Everything Synced" enabled. If so, we want 1071 // to turn on all experimental types if they're not already on. Otherwise we 1072 // leave them off. 1073 // Note: if any types are already registered, we don't turn them on. This 1074 // covers the case where we're already in the process of reconfiguring 1075 // to turn an experimental type on. 1076 if (sync_prefs_.HasKeepEverythingSynced()) { 1077 // Mark all data types as preferred. 1078 sync_prefs_.SetPreferredDataTypes(registered_types, registered_types); 1079 1080 // Only automatically turn on types if we have already finished set up. 1081 // Otherwise, just leave the experimental types on by default. 1082 if (!to_register.Empty() && HasSyncSetupCompleted() && migrator_) { 1083 DVLOG(1) << "Dynamically enabling new datatypes: " 1084 << syncer::ModelTypeSetToString(to_register); 1085 OnMigrationNeededForTypes(to_register); 1086 } 1087 } 1088 1089 current_experiments_ = experiments; 1090} 1091 1092void ProfileSyncService::UpdateAuthErrorState(const AuthError& error) { 1093 is_auth_in_progress_ = false; 1094 last_auth_error_ = error; 1095 1096 // Fan the notification out to interested UI-thread components. Notify the 1097 // SigninGlobalError first so it reflects the latest auth state before we 1098 // notify observers. 1099 if (profile_) 1100 SigninGlobalError::GetForProfile(profile_)->AuthStatusChanged(); 1101 1102 NotifyObservers(); 1103} 1104 1105namespace { 1106 1107AuthError ConnectionStatusToAuthError( 1108 syncer::ConnectionStatus status) { 1109 switch (status) { 1110 case syncer::CONNECTION_OK: 1111 return AuthError::AuthErrorNone(); 1112 break; 1113 case syncer::CONNECTION_AUTH_ERROR: 1114 return AuthError(AuthError::INVALID_GAIA_CREDENTIALS); 1115 break; 1116 case syncer::CONNECTION_SERVER_ERROR: 1117 return AuthError(AuthError::CONNECTION_FAILED); 1118 break; 1119 default: 1120 NOTREACHED(); 1121 return AuthError(AuthError::CONNECTION_FAILED); 1122 } 1123} 1124 1125} // namespace 1126 1127void ProfileSyncService::OnConnectionStatusChange( 1128 syncer::ConnectionStatus status) { 1129 if (use_oauth2_token_ && status == syncer::CONNECTION_AUTH_ERROR) { 1130 // Sync server returned error indicating that access token is invalid. It 1131 // could be either expired or access is revoked. Let's request another 1132 // access token and if access is revoked then request for token will fail 1133 // with corresponding error. 1134 RequestAccessToken(); 1135 } else { 1136 const GoogleServiceAuthError auth_error = 1137 ConnectionStatusToAuthError(status); 1138 DVLOG(1) << "Connection status change: " << auth_error.ToString(); 1139 UpdateAuthErrorState(auth_error); 1140 } 1141} 1142 1143void ProfileSyncService::OnStopSyncingPermanently() { 1144 sync_prefs_.SetStartSuppressed(true); 1145 DisableForUser(); 1146} 1147 1148void ProfileSyncService::OnPassphraseRequired( 1149 syncer::PassphraseRequiredReason reason, 1150 const sync_pb::EncryptedData& pending_keys) { 1151 DCHECK(backend_.get()); 1152 DCHECK(backend_->IsNigoriEnabled()); 1153 1154 // TODO(lipalani) : add this check to other locations as well. 1155 if (HasUnrecoverableError()) { 1156 // When unrecoverable error is detected we post a task to shutdown the 1157 // backend. The task might not have executed yet. 1158 return; 1159 } 1160 1161 DVLOG(1) << "Passphrase required with reason: " 1162 << syncer::PassphraseRequiredReasonToString(reason); 1163 passphrase_required_reason_ = reason; 1164 1165 const syncer::ModelTypeSet types = GetPreferredDataTypes(); 1166 if (data_type_manager_) { 1167 // Reconfigure without the encrypted types (excluded implicitly via the 1168 // failed datatypes handler). 1169 data_type_manager_->Configure(types, 1170 syncer::CONFIGURE_REASON_CRYPTO); 1171 } 1172 1173 // Notify observers that the passphrase status may have changed. 1174 NotifyObservers(); 1175} 1176 1177void ProfileSyncService::OnPassphraseAccepted() { 1178 DVLOG(1) << "Received OnPassphraseAccepted."; 1179 1180 // If the pending keys were resolved via keystore, it's possible we never 1181 // consumed our cached passphrase. Clear it now. 1182 if (!cached_passphrase_.empty()) 1183 cached_passphrase_.clear(); 1184 1185 // Reset passphrase_required_reason_ since we know we no longer require the 1186 // passphrase. We do this here rather than down in ResolvePassphraseRequired() 1187 // because that can be called by OnPassphraseRequired() if no encrypted data 1188 // types are enabled, and we don't want to clobber the true passphrase error. 1189 passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED; 1190 1191 // Make sure the data types that depend on the passphrase are started at 1192 // this time. 1193 const syncer::ModelTypeSet types = GetPreferredDataTypes(); 1194 if (data_type_manager_) { 1195 // Re-enable any encrypted types if necessary. 1196 data_type_manager_->Configure(types, 1197 syncer::CONFIGURE_REASON_CRYPTO); 1198 } 1199 1200 NotifyObservers(); 1201} 1202 1203void ProfileSyncService::OnEncryptedTypesChanged( 1204 syncer::ModelTypeSet encrypted_types, 1205 bool encrypt_everything) { 1206 encrypted_types_ = encrypted_types; 1207 encrypt_everything_ = encrypt_everything; 1208 DVLOG(1) << "Encrypted types changed to " 1209 << syncer::ModelTypeSetToString(encrypted_types_) 1210 << " (encrypt everything is set to " 1211 << (encrypt_everything_ ? "true" : "false") << ")"; 1212 DCHECK(encrypted_types_.Has(syncer::PASSWORDS)); 1213 1214 // If sessions are encrypted, full history sync is not possible, and 1215 // delete directives are unnecessary. 1216 if (GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES) && 1217 encrypted_types_.Has(syncer::SESSIONS)) { 1218 DisableBrokenDatatype(syncer::HISTORY_DELETE_DIRECTIVES, 1219 FROM_HERE, 1220 "Delete directives not supported with encryption."); 1221 } 1222} 1223 1224void ProfileSyncService::OnEncryptionComplete() { 1225 DVLOG(1) << "Encryption complete"; 1226 if (encryption_pending_ && encrypt_everything_) { 1227 encryption_pending_ = false; 1228 // This is to nudge the integration tests when encryption is 1229 // finished. 1230 NotifyObservers(); 1231 } 1232} 1233 1234void ProfileSyncService::OnMigrationNeededForTypes( 1235 syncer::ModelTypeSet types) { 1236 DCHECK(backend_initialized_); 1237 DCHECK(data_type_manager_.get()); 1238 1239 // Migrator must be valid, because we don't sync until it is created and this 1240 // callback originates from a sync cycle. 1241 migrator_->MigrateTypes(types); 1242} 1243 1244void ProfileSyncService::OnActionableError(const SyncProtocolError& error) { 1245 last_actionable_error_ = error; 1246 DCHECK_NE(last_actionable_error_.action, 1247 syncer::UNKNOWN_ACTION); 1248 switch (error.action) { 1249 case syncer::UPGRADE_CLIENT: 1250 case syncer::CLEAR_USER_DATA_AND_RESYNC: 1251 case syncer::ENABLE_SYNC_ON_ACCOUNT: 1252 case syncer::STOP_AND_RESTART_SYNC: 1253 // TODO(lipalani) : if setup in progress we want to display these 1254 // actions in the popup. The current experience might not be optimal for 1255 // the user. We just dismiss the dialog. 1256 if (setup_in_progress_) { 1257 OnStopSyncingPermanently(); 1258 expect_sync_configuration_aborted_ = true; 1259 } 1260 // Trigger an unrecoverable error to stop syncing. 1261 OnInternalUnrecoverableError(FROM_HERE, 1262 last_actionable_error_.error_description, 1263 true, 1264 ERROR_REASON_ACTIONABLE_ERROR); 1265 break; 1266 case syncer::DISABLE_SYNC_ON_CLIENT: 1267 OnStopSyncingPermanently(); 1268#if !defined(OS_CHROMEOS) 1269 // On desktop Chrome, sign out the user after a dashboard clear. 1270 // TODO(rsimha): Revisit this for M30. See http://crbug.com/252049. 1271 if (!auto_start_enabled_) // Skip sign out on ChromeOS/Android. 1272 SigninManagerFactory::GetForProfile(profile_)->SignOut(); 1273#endif 1274 break; 1275 case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT: 1276 // Sync disabled by domain admin. we should stop syncing until next 1277 // restart. 1278 sync_disabled_by_admin_ = true; 1279 ShutdownImpl(browser_sync::SyncBackendHost::DISABLE_AND_CLAIM_THREAD); 1280 break; 1281 default: 1282 NOTREACHED(); 1283 } 1284 NotifyObservers(); 1285} 1286 1287void ProfileSyncService::OnConfigureDone( 1288 const browser_sync::DataTypeManager::ConfigureResult& result) { 1289 // We should have cleared our cached passphrase before we get here (in 1290 // OnBackendInitialized()). 1291 DCHECK(cached_passphrase_.empty()); 1292 1293 if (!sync_configure_start_time_.is_null()) { 1294 if (result.status == DataTypeManager::OK || 1295 result.status == DataTypeManager::PARTIAL_SUCCESS) { 1296 base::Time sync_configure_stop_time = base::Time::Now(); 1297 base::TimeDelta delta = sync_configure_stop_time - 1298 sync_configure_start_time_; 1299 if (is_first_time_sync_configure_) { 1300 UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceInitialConfigureTime", delta); 1301 } else { 1302 UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceSubsequentConfigureTime", 1303 delta); 1304 } 1305 } 1306 sync_configure_start_time_ = base::Time(); 1307 } 1308 1309 // Notify listeners that configuration is done. 1310 content::NotificationService::current()->Notify( 1311 chrome::NOTIFICATION_SYNC_CONFIGURE_DONE, 1312 content::Source<ProfileSyncService>(this), 1313 content::NotificationService::NoDetails()); 1314 1315 configure_status_ = result.status; 1316 DVLOG(1) << "PSS OnConfigureDone called with status: " << configure_status_; 1317 // The possible status values: 1318 // ABORT - Configuration was aborted. This is not an error, if 1319 // initiated by user. 1320 // OK - Everything succeeded. 1321 // PARTIAL_SUCCESS - Some datatypes failed to start. 1322 // Everything else is an UnrecoverableError. So treat it as such. 1323 1324 // First handle the abort case. 1325 if (configure_status_ == DataTypeManager::ABORTED && 1326 expect_sync_configuration_aborted_) { 1327 DVLOG(0) << "ProfileSyncService::Observe Sync Configure aborted"; 1328 expect_sync_configuration_aborted_ = false; 1329 return; 1330 } 1331 1332 // Handle unrecoverable error. 1333 if (configure_status_ != DataTypeManager::OK && 1334 configure_status_ != DataTypeManager::PARTIAL_SUCCESS) { 1335 // Something catastrophic had happened. We should only have one 1336 // error representing it. 1337 DCHECK_EQ(result.failed_data_types.size(), 1338 static_cast<unsigned int>(1)); 1339 syncer::SyncError error = result.failed_data_types.begin()->second; 1340 DCHECK(error.IsSet()); 1341 std::string message = 1342 "Sync configuration failed with status " + 1343 DataTypeManager::ConfigureStatusToString(configure_status_) + 1344 " during " + syncer::ModelTypeToString(error.model_type()) + 1345 ": " + error.message(); 1346 LOG(ERROR) << "ProfileSyncService error: " << message; 1347 OnInternalUnrecoverableError(error.location(), 1348 message, 1349 true, 1350 ERROR_REASON_CONFIGURATION_FAILURE); 1351 return; 1352 } 1353 1354 // We should never get in a state where we have no encrypted datatypes 1355 // enabled, and yet we still think we require a passphrase for decryption. 1356 DCHECK(!(IsPassphraseRequiredForDecryption() && 1357 !IsEncryptedDatatypeEnabled())); 1358 1359 // This must be done before we start syncing with the server to avoid 1360 // sending unencrypted data up on a first time sync. 1361 if (encryption_pending_) 1362 backend_->EnableEncryptEverything(); 1363 NotifyObservers(); 1364 1365 if (migrator_.get() && 1366 migrator_->state() != browser_sync::BackendMigrator::IDLE) { 1367 // Migration in progress. Let the migrator know we just finished 1368 // configuring something. It will be up to the migrator to call 1369 // StartSyncingWithServer() if migration is now finished. 1370 migrator_->OnConfigureDone(result); 1371 } else { 1372 StartSyncingWithServer(); 1373 } 1374} 1375 1376void ProfileSyncService::OnConfigureRetry() { 1377 // We should have cleared our cached passphrase before we get here (in 1378 // OnBackendInitialized()). 1379 DCHECK(cached_passphrase_.empty()); 1380 1381 OnSyncConfigureRetry(); 1382} 1383 1384void ProfileSyncService::OnConfigureStart() { 1385 sync_configure_start_time_ = base::Time::Now(); 1386 NotifyObservers(); 1387} 1388 1389ProfileSyncService::SyncStatusSummary 1390 ProfileSyncService::QuerySyncStatusSummary() { 1391 if (HasUnrecoverableError()) { 1392 return UNRECOVERABLE_ERROR; 1393 } else if (!backend_) { 1394 return NOT_ENABLED; 1395 } else if (backend_.get() && !HasSyncSetupCompleted()) { 1396 return SETUP_INCOMPLETE; 1397 } else if (backend_.get() && HasSyncSetupCompleted() && 1398 data_type_manager_.get() && 1399 data_type_manager_->state() != DataTypeManager::CONFIGURED) { 1400 return DATATYPES_NOT_INITIALIZED; 1401 } else if (ShouldPushChanges()) { 1402 return INITIALIZED; 1403 } 1404 return UNKNOWN_ERROR; 1405} 1406 1407std::string ProfileSyncService::QuerySyncStatusSummaryString() { 1408 SyncStatusSummary status = QuerySyncStatusSummary(); 1409 switch (status) { 1410 case UNRECOVERABLE_ERROR: 1411 return "Unrecoverable error detected"; 1412 case NOT_ENABLED: 1413 return "Syncing not enabled"; 1414 case SETUP_INCOMPLETE: 1415 return "First time sync setup incomplete"; 1416 case DATATYPES_NOT_INITIALIZED: 1417 return "Datatypes not fully initialized"; 1418 case INITIALIZED: 1419 return "Sync service initialized"; 1420 default: 1421 return "Status unknown: Internal error?"; 1422 } 1423} 1424 1425std::string ProfileSyncService::GetBackendInitializationStateString() const { 1426 if (sync_initialized()) 1427 return "Done"; 1428 else if (!start_up_time_.is_null()) 1429 return "Deferred"; 1430 else 1431 return "Not started"; 1432} 1433 1434bool ProfileSyncService::QueryDetailedSyncStatus( 1435 SyncBackendHost::Status* result) { 1436 if (backend_.get() && backend_initialized_) { 1437 *result = backend_->GetDetailedStatus(); 1438 return true; 1439 } else { 1440 SyncBackendHost::Status status; 1441 status.sync_protocol_error = last_actionable_error_; 1442 *result = status; 1443 return false; 1444 } 1445} 1446 1447const AuthError& ProfileSyncService::GetAuthError() const { 1448 return last_auth_error_; 1449} 1450 1451GoogleServiceAuthError ProfileSyncService::GetAuthStatus() const { 1452 // If waiting_for_auth() returns true, it means that ProfileSyncService has 1453 // detected that the user has just successfully completed gaia signin, but the 1454 // backend is yet to update its connection state. In such a case, we do not 1455 // want to continue surfacing an auth error to the UI via SigninGlobalError. 1456 // Otherwise, it will make for a confusing UX, since the user just re-entered 1457 // their credentials. See http://crbug.com/261317. 1458 if (waiting_for_auth()) 1459 return AuthError::AuthErrorNone(); 1460 return GetAuthError(); 1461} 1462 1463bool ProfileSyncService::FirstSetupInProgress() const { 1464 return !HasSyncSetupCompleted() && setup_in_progress_; 1465} 1466 1467void ProfileSyncService::SetSetupInProgress(bool setup_in_progress) { 1468 // This method is a no-op if |setup_in_progress_| remains unchanged. 1469 if (setup_in_progress_ == setup_in_progress) 1470 return; 1471 1472 setup_in_progress_ = setup_in_progress; 1473 if (!setup_in_progress && sync_initialized()) 1474 ReconfigureDatatypeManager(); 1475 NotifyObservers(); 1476} 1477 1478bool ProfileSyncService::sync_initialized() const { 1479 return backend_initialized_; 1480} 1481 1482bool ProfileSyncService::waiting_for_auth() const { 1483 return is_auth_in_progress_; 1484} 1485 1486const syncer::Experiments& ProfileSyncService::current_experiments() const { 1487 return current_experiments_; 1488} 1489 1490bool ProfileSyncService::HasUnrecoverableError() const { 1491 return unrecoverable_error_reason_ != ERROR_REASON_UNSET; 1492} 1493 1494bool ProfileSyncService::IsPassphraseRequired() const { 1495 return passphrase_required_reason_ != 1496 syncer::REASON_PASSPHRASE_NOT_REQUIRED; 1497} 1498 1499bool ProfileSyncService::IsPassphraseRequiredForDecryption() const { 1500 // If there is an encrypted datatype enabled and we don't have the proper 1501 // passphrase, we must prompt the user for a passphrase. The only way for the 1502 // user to avoid entering their passphrase is to disable the encrypted types. 1503 return IsEncryptedDatatypeEnabled() && IsPassphraseRequired(); 1504} 1505 1506string16 ProfileSyncService::GetLastSyncedTimeString() const { 1507 if (last_synced_time_.is_null()) 1508 return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER); 1509 1510 base::TimeDelta last_synced = base::Time::Now() - last_synced_time_; 1511 1512 if (last_synced < base::TimeDelta::FromMinutes(1)) 1513 return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW); 1514 1515 return ui::TimeFormat::TimeElapsed(last_synced); 1516} 1517 1518void ProfileSyncService::UpdateSelectedTypesHistogram( 1519 bool sync_everything, const syncer::ModelTypeSet chosen_types) const { 1520 if (!HasSyncSetupCompleted() || 1521 sync_everything != sync_prefs_.HasKeepEverythingSynced()) { 1522 UMA_HISTOGRAM_BOOLEAN("Sync.SyncEverything", sync_everything); 1523 } 1524 1525 // Only log the data types that are shown in the sync settings ui. 1526 // Note: the order of these types must match the ordering of 1527 // the respective types in ModelType 1528const browser_sync::user_selectable_type::UserSelectableSyncType 1529 user_selectable_types[] = { 1530 browser_sync::user_selectable_type::BOOKMARKS, 1531 browser_sync::user_selectable_type::PREFERENCES, 1532 browser_sync::user_selectable_type::PASSWORDS, 1533 browser_sync::user_selectable_type::AUTOFILL, 1534 browser_sync::user_selectable_type::THEMES, 1535 browser_sync::user_selectable_type::TYPED_URLS, 1536 browser_sync::user_selectable_type::EXTENSIONS, 1537 browser_sync::user_selectable_type::APPS, 1538 browser_sync::user_selectable_type::PROXY_TABS 1539 }; 1540 1541 COMPILE_ASSERT(28 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram); 1542 1543 if (!sync_everything) { 1544 const syncer::ModelTypeSet current_types = GetPreferredDataTypes(); 1545 1546 syncer::ModelTypeSet type_set = syncer::UserSelectableTypes(); 1547 syncer::ModelTypeSet::Iterator it = type_set.First(); 1548 1549 DCHECK_EQ(arraysize(user_selectable_types), type_set.Size()); 1550 1551 for (size_t i = 0; i < arraysize(user_selectable_types) && it.Good(); 1552 ++i, it.Inc()) { 1553 const syncer::ModelType type = it.Get(); 1554 if (chosen_types.Has(type) && 1555 (!HasSyncSetupCompleted() || !current_types.Has(type))) { 1556 // Selected type has changed - log it. 1557 UMA_HISTOGRAM_ENUMERATION( 1558 "Sync.CustomSync", 1559 user_selectable_types[i], 1560 browser_sync::user_selectable_type::SELECTABLE_DATATYPE_COUNT + 1); 1561 } 1562 } 1563 } 1564} 1565 1566#if defined(OS_CHROMEOS) 1567void ProfileSyncService::RefreshSpareBootstrapToken( 1568 const std::string& passphrase) { 1569 browser_sync::ChromeEncryptor encryptor; 1570 syncer::Cryptographer temp_cryptographer(&encryptor); 1571 // The first 2 params (hostname and username) doesn't have any effect here. 1572 syncer::KeyParams key_params = {"localhost", "dummy", passphrase}; 1573 1574 std::string bootstrap_token; 1575 if (!temp_cryptographer.AddKey(key_params)) { 1576 NOTREACHED() << "Failed to add key to cryptographer."; 1577 } 1578 temp_cryptographer.GetBootstrapToken(&bootstrap_token); 1579 sync_prefs_.SetSpareBootstrapToken(bootstrap_token); 1580} 1581#endif 1582 1583void ProfileSyncService::OnUserChoseDatatypes( 1584 bool sync_everything, 1585 syncer::ModelTypeSet chosen_types) { 1586 if (!backend_.get() && !HasUnrecoverableError()) { 1587 NOTREACHED(); 1588 return; 1589 } 1590 1591 UpdateSelectedTypesHistogram(sync_everything, chosen_types); 1592 sync_prefs_.SetKeepEverythingSynced(sync_everything); 1593 1594 failed_data_types_handler_.Reset(); 1595 if (GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES) && 1596 encrypted_types_.Has(syncer::SESSIONS)) { 1597 DisableBrokenDatatype(syncer::HISTORY_DELETE_DIRECTIVES, 1598 FROM_HERE, 1599 "Delete directives not supported with encryption."); 1600 } 1601 ChangePreferredDataTypes(chosen_types); 1602 AcknowledgeSyncedTypes(); 1603 NotifyObservers(); 1604} 1605 1606void ProfileSyncService::ChangePreferredDataTypes( 1607 syncer::ModelTypeSet preferred_types) { 1608 1609 DVLOG(1) << "ChangePreferredDataTypes invoked"; 1610 const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes(); 1611 const syncer::ModelTypeSet registered_preferred_types = 1612 Intersection(registered_types, preferred_types); 1613 sync_prefs_.SetPreferredDataTypes(registered_types, 1614 registered_preferred_types); 1615 1616 // Now reconfigure the DTM. 1617 ReconfigureDatatypeManager(); 1618} 1619 1620syncer::ModelTypeSet ProfileSyncService::GetActiveDataTypes() const { 1621 const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes(); 1622 const syncer::ModelTypeSet failed_types = 1623 failed_data_types_handler_.GetFailedTypes(); 1624 return Difference(preferred_types, failed_types); 1625} 1626 1627syncer::ModelTypeSet ProfileSyncService::GetPreferredDataTypes() const { 1628 const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes(); 1629 const syncer::ModelTypeSet preferred_types = 1630 sync_prefs_.GetPreferredDataTypes(registered_types); 1631 return preferred_types; 1632} 1633 1634syncer::ModelTypeSet ProfileSyncService::GetRegisteredDataTypes() const { 1635 syncer::ModelTypeSet registered_types; 1636 // The data_type_controllers_ are determined by command-line flags; that's 1637 // effectively what controls the values returned here. 1638 for (DataTypeController::TypeMap::const_iterator it = 1639 data_type_controllers_.begin(); 1640 it != data_type_controllers_.end(); ++it) { 1641 registered_types.Put(it->first); 1642 } 1643 return registered_types; 1644} 1645 1646bool ProfileSyncService::IsUsingSecondaryPassphrase() const { 1647 syncer::PassphraseType passphrase_type = GetPassphraseType(); 1648 return passphrase_type == syncer::FROZEN_IMPLICIT_PASSPHRASE || 1649 passphrase_type == syncer::CUSTOM_PASSPHRASE; 1650} 1651 1652syncer::PassphraseType ProfileSyncService::GetPassphraseType() const { 1653 return backend_->GetPassphraseType(); 1654} 1655 1656base::Time ProfileSyncService::GetExplicitPassphraseTime() const { 1657 return backend_->GetExplicitPassphraseTime(); 1658} 1659 1660bool ProfileSyncService::IsCryptographerReady( 1661 const syncer::BaseTransaction* trans) const { 1662 return backend_.get() && backend_->IsCryptographerReady(trans); 1663} 1664 1665SyncBackendHost* ProfileSyncService::GetBackendForTest() { 1666 // We don't check |backend_initialized_|; we assume the test class 1667 // knows what it's doing. 1668 return backend_.get(); 1669} 1670 1671void ProfileSyncService::ConfigurePriorityDataTypes() { 1672 const syncer::ModelTypeSet priority_types = 1673 Intersection(GetPreferredDataTypes(), syncer::PriorityUserTypes()); 1674 if (!priority_types.Empty()) { 1675 const syncer::ConfigureReason reason = HasSyncSetupCompleted() ? 1676 syncer::CONFIGURE_REASON_RECONFIGURATION : 1677 syncer::CONFIGURE_REASON_NEW_CLIENT; 1678 data_type_manager_->Configure(priority_types, reason); 1679 } 1680} 1681 1682void ProfileSyncService::ConfigureDataTypeManager() { 1683 // Don't configure datatypes if the setup UI is still on the screen - this 1684 // is to help multi-screen setting UIs (like iOS) where they don't want to 1685 // start syncing data until the user is done configuring encryption options, 1686 // etc. ReconfigureDatatypeManager() will get called again once the UI calls 1687 // SetSetupInProgress(false). 1688 if (setup_in_progress_) 1689 return; 1690 1691 bool restart = false; 1692 if (!data_type_manager_) { 1693 restart = true; 1694 data_type_manager_.reset( 1695 factory_->CreateDataTypeManager(debug_info_listener_, 1696 &data_type_controllers_, 1697 this, 1698 backend_.get(), 1699 this, 1700 &failed_data_types_handler_)); 1701 1702 // We create the migrator at the same time. 1703 migrator_.reset( 1704 new browser_sync::BackendMigrator( 1705 profile_->GetDebugName(), GetUserShare(), 1706 this, data_type_manager_.get(), 1707 base::Bind(&ProfileSyncService::StartSyncingWithServer, 1708 base::Unretained(this)))); 1709 } 1710 1711 const syncer::ModelTypeSet types = GetPreferredDataTypes(); 1712 syncer::ConfigureReason reason = syncer::CONFIGURE_REASON_UNKNOWN; 1713 if (!HasSyncSetupCompleted()) { 1714 reason = syncer::CONFIGURE_REASON_NEW_CLIENT; 1715 } else if (restart) { 1716 // Datatype downloads on restart are generally due to newly supported 1717 // datatypes (although it's also possible we're picking up where a failed 1718 // previous configuration left off). 1719 // TODO(sync): consider detecting configuration recovery and setting 1720 // the reason here appropriately. 1721 reason = syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE; 1722 } else { 1723 // The user initiated a reconfiguration (either to add or remove types). 1724 reason = syncer::CONFIGURE_REASON_RECONFIGURATION; 1725 } 1726 1727 data_type_manager_->Configure(types, reason); 1728} 1729 1730syncer::UserShare* ProfileSyncService::GetUserShare() const { 1731 if (backend_.get() && backend_initialized_) { 1732 return backend_->GetUserShare(); 1733 } 1734 NOTREACHED(); 1735 return NULL; 1736} 1737 1738syncer::sessions::SyncSessionSnapshot 1739 ProfileSyncService::GetLastSessionSnapshot() const { 1740 if (backend_.get() && backend_initialized_) { 1741 return backend_->GetLastSessionSnapshot(); 1742 } 1743 NOTREACHED(); 1744 return syncer::sessions::SyncSessionSnapshot(); 1745} 1746 1747bool ProfileSyncService::HasUnsyncedItems() const { 1748 if (backend_.get() && backend_initialized_) { 1749 return backend_->HasUnsyncedItems(); 1750 } 1751 NOTREACHED(); 1752 return false; 1753} 1754 1755browser_sync::BackendMigrator* 1756 ProfileSyncService::GetBackendMigratorForTest() { 1757 return migrator_.get(); 1758} 1759 1760void ProfileSyncService::GetModelSafeRoutingInfo( 1761 syncer::ModelSafeRoutingInfo* out) const { 1762 if (backend_.get() && backend_initialized_) { 1763 backend_->GetModelSafeRoutingInfo(out); 1764 } else { 1765 NOTREACHED(); 1766 } 1767} 1768 1769Value* ProfileSyncService::GetTypeStatusMap() const { 1770 scoped_ptr<ListValue> result(new ListValue()); 1771 1772 if (!backend_.get() || !backend_initialized_) { 1773 return result.release(); 1774 } 1775 1776 FailedDataTypesHandler::TypeErrorMap error_map = 1777 failed_data_types_handler_.GetAllErrors(); 1778 1779 ModelTypeSet active_types; 1780 ModelTypeSet passive_types; 1781 ModelSafeRoutingInfo routing_info; 1782 backend_->GetModelSafeRoutingInfo(&routing_info); 1783 for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin(); 1784 it != routing_info.end(); ++it) { 1785 if (it->second == syncer::GROUP_PASSIVE) { 1786 passive_types.Put(it->first); 1787 } else { 1788 active_types.Put(it->first); 1789 } 1790 } 1791 1792 SyncBackendHost::Status detailed_status = backend_->GetDetailedStatus(); 1793 ModelTypeSet &throttled_types(detailed_status.throttled_types); 1794 ModelTypeSet registered = GetRegisteredDataTypes(); 1795 scoped_ptr<DictionaryValue> type_status_header(new DictionaryValue()); 1796 1797 type_status_header->SetString("name", "Model Type"); 1798 type_status_header->SetString("status", "header"); 1799 type_status_header->SetString("value", "Group Type"); 1800 type_status_header->SetString("num_entries", "Total Entries"); 1801 type_status_header->SetString("num_live", "Live Entries"); 1802 result->Append(type_status_header.release()); 1803 1804 scoped_ptr<DictionaryValue> type_status; 1805 for (ModelTypeSet::Iterator it = registered.First(); it.Good(); it.Inc()) { 1806 ModelType type = it.Get(); 1807 1808 type_status.reset(new DictionaryValue()); 1809 type_status->SetString("name", ModelTypeToString(type)); 1810 1811 if (error_map.find(type) != error_map.end()) { 1812 const syncer::SyncError &error = error_map.find(type)->second; 1813 DCHECK(error.IsSet()); 1814 std::string error_text = "Error: " + error.location().ToString() + 1815 ", " + error.message(); 1816 type_status->SetString("status", "error"); 1817 type_status->SetString("value", error_text); 1818 } else if (throttled_types.Has(type) && passive_types.Has(type)) { 1819 type_status->SetString("status", "warning"); 1820 type_status->SetString("value", "Passive, Throttled"); 1821 } else if (passive_types.Has(type)) { 1822 type_status->SetString("status", "warning"); 1823 type_status->SetString("value", "Passive"); 1824 } else if (throttled_types.Has(type)) { 1825 type_status->SetString("status", "warning"); 1826 type_status->SetString("value", "Throttled"); 1827 } else if (active_types.Has(type)) { 1828 type_status->SetString("status", "ok"); 1829 type_status->SetString("value", "Active: " + 1830 ModelSafeGroupToString(routing_info[type])); 1831 } else { 1832 type_status->SetString("status", "warning"); 1833 type_status->SetString("value", "Disabled by User"); 1834 } 1835 1836 int live_count = detailed_status.num_entries_by_type[type] - 1837 detailed_status.num_to_delete_entries_by_type[type]; 1838 type_status->SetInteger("num_entries", 1839 detailed_status.num_entries_by_type[type]); 1840 type_status->SetInteger("num_live", live_count); 1841 1842 result->Append(type_status.release()); 1843 } 1844 return result.release(); 1845} 1846 1847void ProfileSyncService::ActivateDataType( 1848 syncer::ModelType type, syncer::ModelSafeGroup group, 1849 ChangeProcessor* change_processor) { 1850 if (!backend_) { 1851 NOTREACHED(); 1852 return; 1853 } 1854 DCHECK(backend_initialized_); 1855 backend_->ActivateDataType(type, group, change_processor); 1856} 1857 1858void ProfileSyncService::DeactivateDataType(syncer::ModelType type) { 1859 if (!backend_) 1860 return; 1861 backend_->DeactivateDataType(type); 1862} 1863 1864void ProfileSyncService::ConsumeCachedPassphraseIfPossible() { 1865 // If no cached passphrase, or sync backend hasn't started up yet, just exit. 1866 // If the backend isn't running yet, OnBackendInitialized() will call this 1867 // method again after the backend starts up. 1868 if (cached_passphrase_.empty() || !sync_initialized()) 1869 return; 1870 1871 // Backend is up and running, so we can consume the cached passphrase. 1872 std::string passphrase = cached_passphrase_; 1873 cached_passphrase_.clear(); 1874 1875 // If we need a passphrase to decrypt data, try the cached passphrase. 1876 if (passphrase_required_reason() == syncer::REASON_DECRYPTION) { 1877 if (SetDecryptionPassphrase(passphrase)) { 1878 DVLOG(1) << "Cached passphrase successfully decrypted pending keys"; 1879 return; 1880 } 1881 } 1882 1883 // If we get here, we don't have pending keys (or at least, the passphrase 1884 // doesn't decrypt them) - just try to re-encrypt using the encryption 1885 // passphrase. 1886 if (!IsUsingSecondaryPassphrase()) 1887 SetEncryptionPassphrase(passphrase, IMPLICIT); 1888} 1889 1890void ProfileSyncService::RequestAccessToken() { 1891 // Only one active request at a time. 1892 if (access_token_request_ != NULL) 1893 return; 1894 request_access_token_retry_timer_.Stop(); 1895 OAuth2TokenService::ScopeSet oauth2_scopes; 1896 if (profile_->IsManaged()) { 1897 oauth2_scopes.insert(GaiaConstants::kChromeSyncManagedOAuth2Scope); 1898 } else { 1899 oauth2_scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope); 1900 } 1901 1902 // Invalidate previous token, otherwise token service will return the same 1903 // token again. 1904 const std::string& account_id = oauth2_token_service_->GetPrimaryAccountId(); 1905 if (!access_token_.empty()) { 1906 oauth2_token_service_->InvalidateToken( 1907 account_id, oauth2_scopes, access_token_); 1908 } 1909 1910 access_token_.clear(); 1911 access_token_request_ = 1912 oauth2_token_service_->StartRequest(account_id, oauth2_scopes, this); 1913} 1914 1915void ProfileSyncService::SetEncryptionPassphrase(const std::string& passphrase, 1916 PassphraseType type) { 1917 // This should only be called when the backend has been initialized. 1918 DCHECK(sync_initialized()); 1919 DCHECK(!(type == IMPLICIT && IsUsingSecondaryPassphrase())) << 1920 "Data is already encrypted using an explicit passphrase"; 1921 DCHECK(!(type == EXPLICIT && 1922 passphrase_required_reason_ == syncer::REASON_DECRYPTION)) << 1923 "Can not set explicit passphrase when decryption is needed."; 1924 1925 DVLOG(1) << "Setting " << (type == EXPLICIT ? "explicit" : "implicit") 1926 << " passphrase for encryption."; 1927 if (passphrase_required_reason_ == syncer::REASON_ENCRYPTION) { 1928 // REASON_ENCRYPTION implies that the cryptographer does not have pending 1929 // keys. Hence, as long as we're not trying to do an invalid passphrase 1930 // change (e.g. explicit -> explicit or explicit -> implicit), we know this 1931 // will succeed. If for some reason a new encryption key arrives via 1932 // sync later, the SBH will trigger another OnPassphraseRequired(). 1933 passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED; 1934 NotifyObservers(); 1935 } 1936 backend_->SetEncryptionPassphrase(passphrase, type == EXPLICIT); 1937} 1938 1939bool ProfileSyncService::SetDecryptionPassphrase( 1940 const std::string& passphrase) { 1941 if (IsPassphraseRequired()) { 1942 DVLOG(1) << "Setting passphrase for decryption."; 1943 return backend_->SetDecryptionPassphrase(passphrase); 1944 } else { 1945 NOTREACHED() << "SetDecryptionPassphrase must not be called when " 1946 "IsPassphraseRequired() is false."; 1947 return false; 1948 } 1949} 1950 1951void ProfileSyncService::EnableEncryptEverything() { 1952 // Tests override sync_initialized() to always return true, so we 1953 // must check that instead of |backend_initialized_|. 1954 // TODO(akalin): Fix the above. :/ 1955 DCHECK(sync_initialized()); 1956 // TODO(atwilson): Persist the encryption_pending_ flag to address the various 1957 // problems around cancelling encryption in the background (crbug.com/119649). 1958 if (!encrypt_everything_) 1959 encryption_pending_ = true; 1960} 1961 1962bool ProfileSyncService::encryption_pending() const { 1963 // We may be called during the setup process before we're 1964 // initialized (via IsEncryptedDatatypeEnabled and 1965 // IsPassphraseRequiredForDecryption). 1966 return encryption_pending_; 1967} 1968 1969bool ProfileSyncService::EncryptEverythingEnabled() const { 1970 DCHECK(backend_initialized_); 1971 return encrypt_everything_ || encryption_pending_; 1972} 1973 1974syncer::ModelTypeSet ProfileSyncService::GetEncryptedDataTypes() const { 1975 DCHECK(encrypted_types_.Has(syncer::PASSWORDS)); 1976 // We may be called during the setup process before we're 1977 // initialized. In this case, we default to the sensitive types. 1978 return encrypted_types_; 1979} 1980 1981void ProfileSyncService::OnSyncManagedPrefChange(bool is_sync_managed) { 1982 NotifyObservers(); 1983 if (is_sync_managed) { 1984 DisableForUser(); 1985 } else { 1986 // Sync is no longer disabled by policy. Try starting it up if appropriate. 1987 TryStart(); 1988 } 1989} 1990 1991void ProfileSyncService::Observe(int type, 1992 const content::NotificationSource& source, 1993 const content::NotificationDetails& details) { 1994 switch (type) { 1995 case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL: { 1996 const GoogleServiceSigninSuccessDetails* successful = 1997 content::Details<const GoogleServiceSigninSuccessDetails>( 1998 details).ptr(); 1999 if (!sync_prefs_.IsStartSuppressed() && 2000 !successful->password.empty()) { 2001 cached_passphrase_ = successful->password; 2002 // Try to consume the passphrase we just cached. If the sync backend 2003 // is not running yet, the passphrase will remain cached until the 2004 // backend starts up. 2005 ConsumeCachedPassphraseIfPossible(); 2006 } 2007#if defined(OS_CHROMEOS) 2008 RefreshSpareBootstrapToken(successful->password); 2009#endif 2010 if (!sync_initialized() || 2011 GetAuthError().state() != AuthError::NONE) { 2012 // Track the fact that we're still waiting for auth to complete. 2013 is_auth_in_progress_ = true; 2014 2015 // The user has just successfully completed re-auth, so immediately 2016 // clear any auth error that was showing in the UI. If the backend is 2017 // yet to update its connection state, GetAuthStatus() will return 2018 // AuthError::NONE while |is_auth_in_progress_| is set to true. 2019 // See http://crbug.com/261317. 2020 if (profile_) 2021 SigninGlobalError::GetForProfile(profile_)->AuthStatusChanged(); 2022 } 2023 break; 2024 } 2025 case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: 2026 sync_disabled_by_admin_ = false; 2027 DisableForUser(); 2028 break; 2029 default: { 2030 NOTREACHED(); 2031 } 2032 } 2033} 2034 2035void ProfileSyncService::AddObserver( 2036 ProfileSyncServiceBase::Observer* observer) { 2037 observers_.AddObserver(observer); 2038} 2039 2040void ProfileSyncService::RemoveObserver( 2041 ProfileSyncServiceBase::Observer* observer) { 2042 observers_.RemoveObserver(observer); 2043} 2044 2045bool ProfileSyncService::HasObserver( 2046 ProfileSyncServiceBase::Observer* observer) const { 2047 return observers_.HasObserver(observer); 2048} 2049 2050base::WeakPtr<syncer::JsController> ProfileSyncService::GetJsController() { 2051 return sync_js_controller_.AsWeakPtr(); 2052} 2053 2054void ProfileSyncService::SyncEvent(SyncEventCodes code) { 2055 UMA_HISTOGRAM_ENUMERATION("Sync.EventCodes", code, MAX_SYNC_EVENT_CODE); 2056} 2057 2058// static 2059bool ProfileSyncService::IsSyncEnabled() { 2060 // We have switches::kEnableSync just in case we need to change back to 2061 // sync-disabled-by-default on a platform. 2062 return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableSync); 2063} 2064 2065bool ProfileSyncService::IsManaged() const { 2066 return sync_prefs_.IsManaged() || sync_disabled_by_admin_; 2067} 2068 2069bool ProfileSyncService::ShouldPushChanges() { 2070 // True only after all bootstrapping has succeeded: the sync backend 2071 // is initialized, all enabled data types are consistent with one 2072 // another, and no unrecoverable error has transpired. 2073 if (HasUnrecoverableError()) 2074 return false; 2075 2076 if (!data_type_manager_) 2077 return false; 2078 2079 return data_type_manager_->state() == DataTypeManager::CONFIGURED; 2080} 2081 2082void ProfileSyncService::StopAndSuppress() { 2083 sync_prefs_.SetStartSuppressed(true); 2084 if (backend_) { 2085 backend_->UnregisterInvalidationIds(); 2086 } 2087 ShutdownImpl(browser_sync::SyncBackendHost::STOP_AND_CLAIM_THREAD); 2088} 2089 2090bool ProfileSyncService::IsStartSuppressed() const { 2091 return sync_prefs_.IsStartSuppressed(); 2092} 2093 2094void ProfileSyncService::UnsuppressAndStart() { 2095 DCHECK(profile_); 2096 sync_prefs_.SetStartSuppressed(false); 2097 // Set username in SigninManager, as SigninManager::OnGetUserInfoSuccess 2098 // is never called for some clients. 2099 if (signin_ && signin_->GetAuthenticatedUsername().empty()) { 2100 signin_->SetAuthenticatedUsername(sync_prefs_.GetGoogleServicesUsername()); 2101 } 2102 TryStart(); 2103} 2104 2105void ProfileSyncService::AcknowledgeSyncedTypes() { 2106 sync_prefs_.AcknowledgeSyncedTypes(GetRegisteredDataTypes()); 2107} 2108 2109void ProfileSyncService::ReconfigureDatatypeManager() { 2110 // If we haven't initialized yet, don't configure the DTM as it could cause 2111 // association to start before a Directory has even been created. 2112 if (backend_initialized_) { 2113 DCHECK(backend_.get()); 2114 ConfigureDataTypeManager(); 2115 } else if (HasUnrecoverableError()) { 2116 // There is nothing more to configure. So inform the listeners, 2117 NotifyObservers(); 2118 2119 DVLOG(1) << "ConfigureDataTypeManager not invoked because of an " 2120 << "Unrecoverable error."; 2121 } else { 2122 DVLOG(0) << "ConfigureDataTypeManager not invoked because backend is not " 2123 << "initialized"; 2124 } 2125} 2126 2127const FailedDataTypesHandler& ProfileSyncService::failed_data_types_handler() 2128 const { 2129 return failed_data_types_handler_; 2130} 2131 2132void ProfileSyncService::OnInternalUnrecoverableError( 2133 const tracked_objects::Location& from_here, 2134 const std::string& message, 2135 bool delete_sync_database, 2136 UnrecoverableErrorReason reason) { 2137 DCHECK(!HasUnrecoverableError()); 2138 unrecoverable_error_reason_ = reason; 2139 OnUnrecoverableErrorImpl(from_here, message, delete_sync_database); 2140} 2141 2142std::string ProfileSyncService::GetEffectiveUsername() { 2143 if (profile_->IsManaged()) { 2144#if defined(ENABLE_MANAGED_USERS) 2145 DCHECK_EQ(std::string(), signin_->GetAuthenticatedUsername()); 2146 return ManagedUserService::GetManagedUserPseudoEmail(); 2147#else 2148 NOTREACHED(); 2149#endif 2150 } 2151 2152 return signin_->GetAuthenticatedUsername(); 2153} 2154 2155WeakHandle<syncer::JsEventHandler> ProfileSyncService::GetJsEventHandler() { 2156 return MakeWeakHandle(sync_js_controller_.AsWeakPtr()); 2157} 2158