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