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