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