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