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