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