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