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