profile_sync_service.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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/callback.h"
15#include "base/command_line.h"
16#include "base/compiler_specific.h"
17#include "base/logging.h"
18#include "base/memory/ref_counted.h"
19#include "base/message_loop.h"
20#include "base/metrics/histogram.h"
21#include "base/strings/string16.h"
22#include "base/strings/stringprintf.h"
23#include "base/threading/thread_restrictions.h"
24#include "build/build_config.h"
25#include "chrome/browser/browser_process.h"
26#include "chrome/browser/defaults.h"
27#include "chrome/browser/net/chrome_cookie_notification_details.h"
28#include "chrome/browser/prefs/pref_service_syncable.h"
29#include "chrome/browser/profiles/profile.h"
30#include "chrome/browser/signin/about_signin_internals.h"
31#include "chrome/browser/signin/about_signin_internals_factory.h"
32#include "chrome/browser/signin/profile_oauth2_token_service.h"
33#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
34#include "chrome/browser/signin/signin_manager.h"
35#include "chrome/browser/signin/signin_manager_factory.h"
36#include "chrome/browser/signin/token_service.h"
37#include "chrome/browser/signin/token_service_factory.h"
38#include "chrome/browser/sync/backend_migrator.h"
39#include "chrome/browser/sync/glue/change_processor.h"
40#include "chrome/browser/sync/glue/chrome_encryptor.h"
41#include "chrome/browser/sync/glue/chrome_report_unrecoverable_error.h"
42#include "chrome/browser/sync/glue/data_type_controller.h"
43#include "chrome/browser/sync/glue/device_info.h"
44#include "chrome/browser/sync/glue/session_data_type_controller.h"
45#include "chrome/browser/sync/glue/session_model_associator.h"
46#include "chrome/browser/sync/glue/synced_device_tracker.h"
47#include "chrome/browser/sync/glue/typed_url_data_type_controller.h"
48#include "chrome/browser/sync/profile_sync_components_factory_impl.h"
49#include "chrome/browser/sync/sync_global_error.h"
50#include "chrome/browser/sync/user_selectable_sync_type.h"
51#include "chrome/browser/ui/browser.h"
52#include "chrome/browser/ui/browser_list.h"
53#include "chrome/browser/ui/browser_window.h"
54#include "chrome/browser/ui/global_error/global_error_service.h"
55#include "chrome/browser/ui/global_error/global_error_service_factory.h"
56#include "chrome/common/chrome_notification_types.h"
57#include "chrome/common/chrome_switches.h"
58#include "chrome/common/chrome_version_info.h"
59#include "chrome/common/pref_names.h"
60#include "chrome/common/time_format.h"
61#include "chrome/common/url_constants.h"
62#include "components/user_prefs/pref_registry_syncable.h"
63#include "content/public/browser/notification_details.h"
64#include "content/public/browser/notification_service.h"
65#include "content/public/browser/notification_source.h"
66#include "google_apis/gaia/gaia_constants.h"
67#include "grit/generated_resources.h"
68#include "net/cookies/cookie_monster.h"
69#include "net/url_request/url_request_context_getter.h"
70#include "sync/api/sync_error.h"
71#include "sync/internal_api/public/configure_reason.h"
72#include "sync/internal_api/public/sync_encryption_handler.h"
73#include "sync/internal_api/public/util/experiments.h"
74#include "sync/internal_api/public/util/sync_string_conversions.h"
75#include "sync/js/js_arg_list.h"
76#include "sync/js/js_event_details.h"
77#include "sync/util/cryptographer.h"
78#include "ui/base/l10n/l10n_util.h"
79
80#if defined(ENABLE_MANAGED_USERS)
81#include "chrome/browser/managed_mode/managed_user_service.h"
82#endif
83
84#if defined(OS_ANDROID)
85#include "sync/internal_api/public/read_transaction.h"
86#endif
87
88using browser_sync::ChangeProcessor;
89using browser_sync::DataTypeController;
90using browser_sync::DataTypeManager;
91using browser_sync::FailedDataTypesHandler;
92using browser_sync::SyncBackendHost;
93using syncer::ModelType;
94using syncer::ModelTypeSet;
95using syncer::JsBackend;
96using syncer::JsController;
97using syncer::JsEventDetails;
98using syncer::JsEventHandler;
99using syncer::ModelSafeRoutingInfo;
100using syncer::SyncCredentials;
101using syncer::SyncProtocolError;
102using syncer::WeakHandle;
103
104typedef GoogleServiceAuthError AuthError;
105
106const char* ProfileSyncService::kSyncServerUrl =
107    "https://clients4.google.com/chrome-sync";
108
109const char* ProfileSyncService::kDevServerUrl =
110    "https://clients4.google.com/chrome-sync/dev";
111
112static const int kSyncClearDataTimeoutInSeconds = 60;  // 1 minute.
113
114static const char* kOAuth2Scopes[] = {
115  GaiaConstants::kChromeSyncOAuth2Scope,
116};
117
118static const char* kManagedOAuth2Scopes[] = {
119  GaiaConstants::kChromeSyncManagedOAuth2Scope
120};
121
122static const char* kSyncUnrecoverableErrorHistogram =
123    "Sync.UnrecoverableErrors";
124
125const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
126  // Number of initial errors (in sequence) to ignore before applying
127  // exponential back-off rules.
128  0,
129
130  // Initial delay for exponential back-off in ms.
131  2000,
132
133  // Factor by which the waiting time will be multiplied.
134  2,
135
136  // Fuzzing percentage. ex: 10% will spread requests randomly
137  // between 90%-100% of the calculated time.
138  0.2, // 20%
139
140  // Maximum amount of time we are willing to delay our request in ms.
141  // TODO(pavely): crbug.com/246686 ProfileSyncService should retry
142  // RequestAccessToken on connection state change after backoff
143  1000 * 3600 * 4, // 4 hours.
144
145  // Time to keep an entry from being discarded even when it
146  // has no significant state, -1 to never discard.
147  -1,
148
149  // Don't use initial delay unless the last request was an error.
150  false,
151};
152
153bool ShouldShowActionOnUI(
154    const syncer::SyncProtocolError& error) {
155  return (error.action != syncer::UNKNOWN_ACTION &&
156          error.action != syncer::DISABLE_SYNC_ON_CLIENT &&
157          error.action != syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT);
158}
159
160ProfileSyncService::ProfileSyncService(ProfileSyncComponentsFactory* factory,
161                                       Profile* profile,
162                                       SigninManagerBase* signin_manager,
163                                       StartBehavior start_behavior)
164    : last_auth_error_(AuthError::AuthErrorNone()),
165      passphrase_required_reason_(syncer::REASON_PASSPHRASE_NOT_REQUIRED),
166      factory_(factory),
167      profile_(profile),
168      // |profile| may be NULL in unit tests.
169      sync_prefs_(profile_ ? profile_->GetPrefs() : NULL),
170      sync_service_url_(kDevServerUrl),
171      data_type_requested_sync_startup_(false),
172      is_first_time_sync_configure_(false),
173      backend_initialized_(false),
174      sync_disabled_by_admin_(false),
175      is_auth_in_progress_(false),
176      signin_(signin_manager),
177      unrecoverable_error_reason_(ERROR_REASON_UNSET),
178      weak_factory_(this),
179      expect_sync_configuration_aborted_(false),
180      encrypted_types_(syncer::SyncEncryptionHandler::SensitiveTypes()),
181      encrypt_everything_(false),
182      encryption_pending_(false),
183      auto_start_enabled_(start_behavior == AUTO_START),
184      configure_status_(DataTypeManager::UNKNOWN),
185      setup_in_progress_(false),
186      request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy) {
187  // By default, dev, canary, and unbranded Chromium users will go to the
188  // development servers. Development servers have more features than standard
189  // sync servers. Users with officially-branded Chrome stable and beta builds
190  // will go to the standard sync servers.
191  //
192  // GetChannel hits the registry on Windows. See http://crbug.com/70380.
193  base::ThreadRestrictions::ScopedAllowIO allow_io;
194  chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
195  if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
196      channel == chrome::VersionInfo::CHANNEL_BETA) {
197    sync_service_url_ = GURL(kSyncServerUrl);
198  }
199  if (signin_)
200    signin_->signin_global_error()->AddProvider(this);
201}
202
203ProfileSyncService::~ProfileSyncService() {
204  sync_prefs_.RemoveSyncPrefObserver(this);
205  // Shutdown() should have been called before destruction.
206  CHECK(!backend_initialized_);
207}
208
209bool ProfileSyncService::IsSyncEnabledAndLoggedIn() {
210  // Exit if sync is disabled.
211  if (IsManaged() || sync_prefs_.IsStartSuppressed())
212    return false;
213
214  // Sync is logged in if there is a non-empty effective username.
215  return !GetEffectiveUsername().empty();
216}
217
218bool ProfileSyncService::IsOAuthRefreshTokenAvailable() {
219  // Function name doesn't reflect which token is checked. Function checks
220  // refresh token when use_oauth2_token_ is true (all platforms except android)
221  // and sync token otherwise (for android).
222  // TODO(pavely): Remove "else" part once use_oauth2_token_ is gone.
223  if (use_oauth2_token_) {
224    ProfileOAuth2TokenService* token_service =
225        ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
226    if (!token_service)
227      return false;
228    return token_service->RefreshTokenIsAvailable();
229  } else {
230    TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
231    if (!token_service)
232      return false;
233    return token_service->HasTokenForService(GaiaConstants::kSyncService);
234  }
235}
236
237void ProfileSyncService::Initialize() {
238  InitSettings();
239
240  // We clear this here (vs Shutdown) because we want to remember that an error
241  // happened on shutdown so we can display details (message, location) about it
242  // in about:sync.
243  ClearStaleErrors();
244
245  sync_prefs_.AddSyncPrefObserver(this);
246
247  // For now, the only thing we can do through policy is to turn sync off.
248  if (IsManaged()) {
249    DisableForUser();
250    return;
251  }
252
253  RegisterAuthNotifications();
254
255  if (!HasSyncSetupCompleted() || GetEffectiveUsername().empty()) {
256    // Clean up in case of previous crash / setup abort / signout.
257    DisableForUser();
258  }
259
260  TrySyncDatatypePrefRecovery();
261
262  TryStart();
263}
264
265void ProfileSyncService::TrySyncDatatypePrefRecovery() {
266  DCHECK(!sync_initialized());
267  if (!HasSyncSetupCompleted())
268    return;
269
270  // There was a bug where OnUserChoseDatatypes was not properly called on
271  // configuration (see crbug.com/154940). We detect this by checking whether
272  // kSyncKeepEverythingSynced has a default value. If so, and sync setup has
273  // completed, it means sync was not properly configured, so we manually
274  // set kSyncKeepEverythingSynced.
275  PrefService* const pref_service = profile_->GetPrefs();
276  if (!pref_service)
277    return;
278  if (GetPreferredDataTypes().Size() > 1)
279    return;
280
281  const PrefService::Preference* keep_everything_synced =
282      pref_service->FindPreference(prefs::kSyncKeepEverythingSynced);
283  // This will be false if the preference was properly set or if it's controlled
284  // by policy.
285  if (!keep_everything_synced->IsDefaultValue())
286    return;
287
288  // kSyncKeepEverythingSynced was not properly set. Set it and the preferred
289  // types now, before we configure.
290  UMA_HISTOGRAM_COUNTS("Sync.DatatypePrefRecovery", 1);
291  sync_prefs_.SetKeepEverythingSynced(true);
292  syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
293  sync_prefs_.SetPreferredDataTypes(registered_types,
294                                    registered_types);
295}
296
297void ProfileSyncService::TryStart() {
298  if (!IsSyncEnabledAndLoggedIn())
299    return;
300  TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
301  if (!token_service)
302    return;
303  // Don't start the backend if the token service hasn't finished loading tokens
304  // yet. Note if the backend is started before the sync token has been loaded,
305  // GetCredentials() will return bogus credentials. On auto_start platforms
306  // (like ChromeOS) we don't start sync until tokens are loaded, because the
307  // user can be "signed in" on those platforms long before the tokens get
308  // loaded, and we don't want to generate spurious auth errors.
309  if (!IsOAuthRefreshTokenAvailable() &&
310      !(!auto_start_enabled_ && token_service->TokensLoadedFromDB())) {
311    return;
312  }
313
314  if (use_oauth2_token_) {
315    // If we got here then tokens are loaded and user logged in and sync is
316    // enabled. If OAuth refresh token is not available then something is wrong.
317    // When PSS requests access token, OAuth2TokenService will return error and
318    // PSS will show error to user asking to reauthenticate.
319    UMA_HISTOGRAM_BOOLEAN("Sync.RefreshTokenAvailable",
320        IsOAuthRefreshTokenAvailable());
321  }
322
323  // If sync setup has completed we always start the backend. If the user is in
324  // the process of setting up now, we should start the backend to download
325  // account control state / encryption information). If autostart is enabled,
326  // but we haven't completed sync setup, we try to start sync anyway, since
327  // it's possible we crashed/shutdown after logging in but before the backend
328  // finished initializing the last time.
329  //
330  // However, the only time we actually need to start sync _immediately_ is if
331  // we haven't completed sync setup and the user is in the process of setting
332  // up - either they just signed in (for the first time) on an auto-start
333  // platform or they explicitly kicked off sync setup, and e.g we need to
334  // fetch account details like encryption state to populate UI. Otherwise,
335  // for performance reasons and maximizing parallelism at chrome startup, we
336  // defer the heavy lifting for sync init until things have calmed down.
337  if (HasSyncSetupCompleted()) {
338    if (!data_type_requested_sync_startup_)
339      StartUp(STARTUP_BACKEND_DEFERRED);
340    else if (start_up_time_.is_null())
341      StartUp(STARTUP_IMMEDIATE);
342    else
343      StartUpSlowBackendComponents();
344  } else if (setup_in_progress_ || auto_start_enabled_) {
345    // We haven't completed sync setup. Start immediately if the user explicitly
346    // kicked this off or we're supposed to automatically start syncing.
347    StartUp(STARTUP_IMMEDIATE);
348  }
349}
350
351void ProfileSyncService::StartSyncingWithServer() {
352  if (backend_)
353    backend_->StartSyncingWithServer();
354}
355
356void ProfileSyncService::RegisterAuthNotifications() {
357  TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
358  registrar_.Add(this,
359                 chrome::NOTIFICATION_TOKEN_AVAILABLE,
360                 content::Source<TokenService>(token_service));
361  registrar_.Add(this,
362                 chrome::NOTIFICATION_TOKEN_LOADING_FINISHED,
363                 content::Source<TokenService>(token_service));
364  registrar_.Add(this,
365                 chrome::NOTIFICATION_TOKEN_REQUEST_FAILED,
366                 content::Source<TokenService>(token_service));
367  registrar_.Add(this,
368                 chrome::NOTIFICATION_TOKENS_CLEARED,
369                 content::Source<TokenService>(token_service));
370  registrar_.Add(this,
371                 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
372                 content::Source<Profile>(profile_));
373  registrar_.Add(this,
374                 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
375                 content::Source<Profile>(profile_));
376}
377
378void ProfileSyncService::RegisterDataTypeController(
379    DataTypeController* data_type_controller) {
380  DCHECK_EQ(data_type_controllers_.count(data_type_controller->type()), 0U);
381  data_type_controllers_[data_type_controller->type()] =
382      data_type_controller;
383}
384
385browser_sync::SessionModelAssociator*
386    ProfileSyncService::GetSessionModelAssociator() {
387  if (data_type_controllers_.find(syncer::SESSIONS) ==
388      data_type_controllers_.end() ||
389      data_type_controllers_.find(syncer::SESSIONS)->second->state() !=
390      DataTypeController::RUNNING) {
391    return NULL;
392  }
393  return static_cast<browser_sync::SessionDataTypeController*>(
394      data_type_controllers_.find(
395      syncer::SESSIONS)->second.get())->GetModelAssociator();
396}
397
398scoped_ptr<browser_sync::DeviceInfo>
399ProfileSyncService::GetLocalDeviceInfo() const {
400  if (backend_) {
401    browser_sync::SyncedDeviceTracker* device_tracker =
402        backend_->GetSyncedDeviceTracker();
403    if (device_tracker)
404      return device_tracker->ReadLocalDeviceInfo();
405  }
406  return scoped_ptr<browser_sync::DeviceInfo>();
407}
408
409scoped_ptr<browser_sync::DeviceInfo>
410ProfileSyncService::GetDeviceInfo(const std::string& client_id) const {
411  if (backend_) {
412    browser_sync::SyncedDeviceTracker* device_tracker =
413        backend_->GetSyncedDeviceTracker();
414    if (device_tracker)
415      return device_tracker->ReadDeviceInfo(client_id);
416  }
417  return scoped_ptr<browser_sync::DeviceInfo>();
418}
419
420void ProfileSyncService::GetDataTypeControllerStates(
421  browser_sync::DataTypeController::StateMap* state_map) const {
422    for (browser_sync::DataTypeController::TypeMap::const_iterator iter =
423         data_type_controllers_.begin(); iter != data_type_controllers_.end();
424         ++iter)
425      (*state_map)[iter->first] = iter->second.get()->state();
426}
427
428void ProfileSyncService::InitSettings() {
429  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
430
431  // Override the sync server URL from the command-line, if sync server
432  // command-line argument exists.
433  if (command_line.HasSwitch(switches::kSyncServiceURL)) {
434    std::string value(command_line.GetSwitchValueASCII(
435        switches::kSyncServiceURL));
436    if (!value.empty()) {
437      GURL custom_sync_url(value);
438      if (custom_sync_url.is_valid()) {
439        sync_service_url_ = custom_sync_url;
440      } else {
441        LOG(WARNING) << "The following sync URL specified at the command-line "
442                     << "is invalid: " << value;
443      }
444    }
445  }
446
447  use_oauth2_token_ = !command_line.HasSwitch(
448      switches::kSyncDisableOAuth2Token);
449}
450
451SyncCredentials ProfileSyncService::GetCredentials() {
452  SyncCredentials credentials;
453  credentials.email = GetEffectiveUsername();
454  DCHECK(!credentials.email.empty());
455  if (use_oauth2_token_) {
456    credentials.sync_token = access_token_;
457  } else {
458    TokenService* service = TokenServiceFactory::GetForProfile(profile_);
459    if (service->HasTokenForService(GaiaConstants::kSyncService)) {
460      credentials.sync_token = service->GetTokenForService(
461          GaiaConstants::kSyncService);
462    }
463  }
464
465  if (credentials.sync_token.empty())
466    credentials.sync_token = "credentials_lost";
467  return credentials;
468}
469
470void ProfileSyncService::InitializeBackend(bool delete_stale_data) {
471  if (!backend_) {
472    NOTREACHED();
473    return;
474  }
475
476  SyncCredentials credentials = GetCredentials();
477
478  scoped_refptr<net::URLRequestContextGetter> request_context_getter(
479      profile_->GetRequestContext());
480
481  if (delete_stale_data)
482    ClearStaleErrors();
483
484  backend_unrecoverable_error_handler_.reset(
485    new browser_sync::BackendUnrecoverableErrorHandler(
486        MakeWeakHandle(weak_factory_.GetWeakPtr())));
487
488  backend_->Initialize(
489      this,
490      MakeWeakHandle(sync_js_controller_.AsWeakPtr()),
491      sync_service_url_,
492      credentials,
493      delete_stale_data,
494      &sync_manager_factory_,
495      backend_unrecoverable_error_handler_.get(),
496      &browser_sync::ChromeReportUnrecoverableError);
497}
498
499void ProfileSyncService::CreateBackend() {
500  backend_.reset(
501      new SyncBackendHost(profile_->GetDebugName(),
502                          profile_, sync_prefs_.AsWeakPtr()));
503}
504
505bool ProfileSyncService::IsEncryptedDatatypeEnabled() const {
506  if (encryption_pending())
507    return true;
508  const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes();
509  const syncer::ModelTypeSet encrypted_types = GetEncryptedDataTypes();
510  DCHECK(encrypted_types.Has(syncer::PASSWORDS));
511  return !Intersection(preferred_types, encrypted_types).Empty();
512}
513
514void ProfileSyncService::OnSyncConfigureRetry() {
515  // Note: in order to handle auth failures that arise before the backend is
516  // initialized (e.g. from invalidation notifier, or downloading new control
517  // types), we have to gracefully handle configuration retries at all times.
518  // At this point an auth error badge should be shown, which once resolved
519  // will trigger a new sync cycle.
520  NotifyObservers();
521}
522
523void ProfileSyncService::StartUp(StartUpDeferredOption deferred_option) {
524  // Don't start up multiple times.
525  if (backend_) {
526    DVLOG(1) << "Skipping bringing up backend host.";
527    return;
528  }
529
530  DCHECK(IsSyncEnabledAndLoggedIn());
531
532  if (use_oauth2_token_ && access_token_.empty()) {
533    RequestAccessToken();
534    return;
535  }
536
537  if (start_up_time_.is_null()) {
538    start_up_time_ = base::Time::Now();
539    last_synced_time_ = sync_prefs_.GetLastSyncedTime();
540
541#if defined(OS_CHROMEOS)
542    std::string bootstrap_token = sync_prefs_.GetEncryptionBootstrapToken();
543    if (bootstrap_token.empty()) {
544      sync_prefs_.SetEncryptionBootstrapToken(
545          sync_prefs_.GetSpareBootstrapToken());
546    }
547#endif
548
549    if (!sync_global_error_) {
550#if !defined(OS_ANDROID)
551      sync_global_error_.reset(new SyncGlobalError(this, signin()));
552#endif
553      GlobalErrorServiceFactory::GetForProfile(profile_)->AddGlobalError(
554          sync_global_error_.get());
555      AddObserver(sync_global_error_.get());
556    }
557  } else {
558    // We don't care to prevent multiple calls to StartUp in deferred mode
559    // because it's fast and has no side effects.
560    DCHECK_EQ(STARTUP_BACKEND_DEFERRED, deferred_option);
561  }
562
563  if (deferred_option == STARTUP_BACKEND_DEFERRED &&
564      CommandLine::ForCurrentProcess()->
565          HasSwitch(switches::kSyncEnableDeferredStartup)) {
566    return;
567  }
568
569  StartUpSlowBackendComponents();
570}
571
572void ProfileSyncService::OnDataTypeRequestsSyncStartup(
573    syncer::ModelType type) {
574  DCHECK(syncer::UserTypes().Has(type));
575  if (backend_.get()) {
576    DVLOG(1) << "A data type requested sync startup, but it looks like "
577                "something else beat it to the punch.";
578    return;
579  }
580
581  if (!GetActiveDataTypes().Has(type)) {
582    // We can get here as datatype SyncableServices are typically wired up
583    // to the native datatype even if sync isn't enabled.
584    DVLOG(1) << "Dropping sync startup request because type "
585             << syncer::ModelTypeToString(type) << "not enabled.";
586    return;
587  }
588
589  if (CommandLine::ForCurrentProcess()->HasSwitch(
590          switches::kSyncEnableDeferredStartup)) {
591    DVLOG(2) << "Data type requesting sync startup: "
592             << syncer::ModelTypeToString(type);
593    // Measure the time spent waiting for init and the type that triggered it.
594    // We could measure the time spent deferred on a per-datatype basis, but
595    // for now this is probably sufficient.
596    if (!start_up_time_.is_null()) {
597      // TODO(tim): Cache |type| and move this tracking to StartUp.  I'd like
598      // to pull all the complicated init logic and state out of
599      // ProfileSyncService and have only a StartUp method, though. One step
600      // at a time. Bug 80149.
601      base::TimeDelta time_deferred = base::Time::Now() - start_up_time_;
602      UMA_HISTOGRAM_TIMES("Sync.Startup.TimeDeferred", time_deferred);
603      UMA_HISTOGRAM_ENUMERATION("Sync.Startup.TypeTriggeringInit",
604                                ModelTypeToHistogramInt(type),
605                                syncer::MODEL_TYPE_COUNT);
606    }
607    data_type_requested_sync_startup_ = true;
608    TryStart();
609  }
610  DVLOG(2) << "Ignoring data type request for sync startup: "
611           << syncer::ModelTypeToString(type);
612}
613
614void ProfileSyncService::StartUpSlowBackendComponents() {
615  // Don't start up multiple times.
616  if (backend_) {
617    DVLOG(1) << "Skipping bringing up backend host.";
618    return;
619  }
620
621  DCHECK(IsSyncEnabledAndLoggedIn());
622  CreateBackend();
623
624  // Initialize the backend.  Every time we start up a new SyncBackendHost,
625  // we'll want to start from a fresh SyncDB, so delete any old one that might
626  // be there.
627  InitializeBackend(!HasSyncSetupCompleted());
628}
629
630void ProfileSyncService::OnGetTokenSuccess(
631    const OAuth2TokenService::Request* request,
632    const std::string& access_token,
633    const base::Time& expiration_time) {
634  DCHECK_EQ(access_token_request_, request);
635  access_token_request_.reset();
636  // Reset backoff time after successful response.
637  request_access_token_backoff_.Reset();
638  access_token_ = access_token;
639  if (backend_)
640    backend_->UpdateCredentials(GetCredentials());
641  else
642    TryStart();
643}
644
645void ProfileSyncService::OnGetTokenFailure(
646    const OAuth2TokenService::Request* request,
647    const GoogleServiceAuthError& error) {
648  DCHECK_EQ(access_token_request_, request);
649  DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
650  access_token_request_.reset();
651  switch (error.state()) {
652    case GoogleServiceAuthError::CONNECTION_FAILED:
653    case GoogleServiceAuthError::SERVICE_UNAVAILABLE: {
654      // Transient error. Retry after some time.
655      request_access_token_backoff_.InformOfRequest(false);
656      request_access_token_retry_timer_.Start(
657            FROM_HERE,
658            request_access_token_backoff_.GetTimeUntilRelease(),
659            base::Bind(&ProfileSyncService::RequestAccessToken,
660                        weak_factory_.GetWeakPtr()));
661      break;
662    }
663    case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
664      // Report time since token was issued for invalid credentials error.
665      // TODO(pavely): crbug.com/246817 Collect UMA histogram for auth token
666      // rejections from invalidation service.
667      base::Time auth_token_time =
668          AboutSigninInternalsFactory::GetForProfile(profile_)->
669              GetTokenTime(GaiaConstants::kGaiaOAuth2LoginRefreshToken);
670      if (!auth_token_time.is_null()) {
671        base::TimeDelta age = base::Time::Now() - auth_token_time;
672        if (age < base::TimeDelta::FromHours(1)) {
673          UMA_HISTOGRAM_CUSTOM_TIMES("Sync.AuthServerRejectedTokenAgeShort",
674                                     age,
675                                     base::TimeDelta::FromSeconds(1),
676                                     base::TimeDelta::FromHours(1),
677                                     50);
678        }
679        UMA_HISTOGRAM_COUNTS("Sync.AuthServerRejectedTokenAgeLong",
680                             age.InDays());
681      }
682      // Fallthrough.
683    }
684    default: {
685      // Show error to user.
686      UpdateAuthErrorState(error);
687    }
688  }
689}
690
691void ProfileSyncService::Shutdown() {
692  if (signin_)
693    signin_->signin_global_error()->RemoveProvider(this);
694
695  ShutdownImpl(false);
696}
697
698void ProfileSyncService::ShutdownImpl(bool sync_disabled) {
699  // First, we spin down the backend and wait for it to stop syncing completely
700  // before we Stop the data type manager.  This is to avoid a late sync cycle
701  // applying changes to the sync db that wouldn't get applied via
702  // ChangeProcessors, leading to back-from-the-dead bugs.
703  base::Time shutdown_start_time = base::Time::Now();
704  if (backend_) {
705    backend_->StopSyncingForShutdown();
706  }
707
708  // Stop all data type controllers, if needed.  Note that until Stop
709  // completes, it is possible in theory to have a ChangeProcessor apply a
710  // change from a native model.  In that case, it will get applied to the sync
711  // database (which doesn't get destroyed until we destroy the backend below)
712  // as an unsynced change.  That will be persisted, and committed on restart.
713  if (data_type_manager_) {
714    if (data_type_manager_->state() != DataTypeManager::STOPPED) {
715      // When aborting as part of shutdown, we should expect an aborted sync
716      // configure result, else we'll dcheck when we try to read the sync error.
717      expect_sync_configuration_aborted_ = true;
718      data_type_manager_->Stop();
719    }
720    data_type_manager_.reset();
721  }
722
723  // Shutdown the migrator before the backend to ensure it doesn't pull a null
724  // snapshot.
725  migrator_.reset();
726  sync_js_controller_.AttachJsBackend(WeakHandle<syncer::JsBackend>());
727
728  // Move aside the backend so nobody else tries to use it while we are
729  // shutting it down.
730  scoped_ptr<SyncBackendHost> doomed_backend(backend_.release());
731  if (doomed_backend) {
732    doomed_backend->Shutdown(sync_disabled);
733
734    doomed_backend.reset();
735  }
736  base::TimeDelta shutdown_time = base::Time::Now() - shutdown_start_time;
737  UMA_HISTOGRAM_TIMES("Sync.Shutdown.BackendDestroyedTime", shutdown_time);
738
739  weak_factory_.InvalidateWeakPtrs();
740
741  // Clear various flags.
742  start_up_time_ = base::Time();
743  expect_sync_configuration_aborted_ = false;
744  is_auth_in_progress_ = false;
745  backend_initialized_ = false;
746  cached_passphrase_.clear();
747  encryption_pending_ = false;
748  encrypt_everything_ = false;
749  encrypted_types_ = syncer::SyncEncryptionHandler::SensitiveTypes();
750  passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
751  request_access_token_retry_timer_.Stop();
752  // Revert to "no auth error".
753  if (last_auth_error_.state() != GoogleServiceAuthError::NONE)
754    UpdateAuthErrorState(GoogleServiceAuthError::AuthErrorNone());
755
756  if (sync_global_error_) {
757    GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveGlobalError(
758        sync_global_error_.get());
759    RemoveObserver(sync_global_error_.get());
760    sync_global_error_.reset(NULL);
761  }
762
763  NotifyObservers();
764}
765
766void ProfileSyncService::DisableForUser() {
767  // Clear prefs (including SyncSetupHasCompleted) before shutting down so
768  // PSS clients don't think we're set up while we're shutting down.
769  sync_prefs_.ClearPreferences();
770  ClearUnrecoverableError();
771  ShutdownImpl(true);
772}
773
774bool ProfileSyncService::HasSyncSetupCompleted() const {
775  return sync_prefs_.HasSyncSetupCompleted();
776}
777
778void ProfileSyncService::SetSyncSetupCompleted() {
779  sync_prefs_.SetSyncSetupCompleted();
780}
781
782void ProfileSyncService::UpdateLastSyncedTime() {
783  last_synced_time_ = base::Time::Now();
784  sync_prefs_.SetLastSyncedTime(last_synced_time_);
785}
786
787void ProfileSyncService::NotifyObservers() {
788  FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
789  // TODO(akalin): Make an Observer subclass that listens and does the
790  // event routing.
791  sync_js_controller_.HandleJsEvent("onServiceStateChanged", JsEventDetails());
792}
793
794void ProfileSyncService::NotifySyncCycleCompleted() {
795  FOR_EACH_OBSERVER(Observer, observers_, OnSyncCycleCompleted());
796  sync_js_controller_.HandleJsEvent(
797      "onServiceStateChanged", JsEventDetails());
798}
799
800void ProfileSyncService::ClearStaleErrors() {
801  ClearUnrecoverableError();
802  last_actionable_error_ = SyncProtocolError();
803  // Clear the data type errors as well.
804  failed_data_types_handler_.Reset();
805}
806
807void ProfileSyncService::ClearUnrecoverableError() {
808  unrecoverable_error_reason_ = ERROR_REASON_UNSET;
809  unrecoverable_error_message_.clear();
810  unrecoverable_error_location_ = tracked_objects::Location();
811}
812
813void ProfileSyncService::RegisterNewDataType(syncer::ModelType data_type) {
814  if (data_type_controllers_.count(data_type) > 0)
815    return;
816  NOTREACHED();
817}
818
819// An invariant has been violated.  Transition to an error state where we try
820// to do as little work as possible, to avoid further corruption or crashes.
821void ProfileSyncService::OnUnrecoverableError(
822    const tracked_objects::Location& from_here,
823    const std::string& message) {
824  // Unrecoverable errors that arrive via the syncer::UnrecoverableErrorHandler
825  // interface are assumed to originate within the syncer.
826  unrecoverable_error_reason_ = ERROR_REASON_SYNCER;
827  OnUnrecoverableErrorImpl(from_here, message, true);
828}
829
830void ProfileSyncService::OnUnrecoverableErrorImpl(
831    const tracked_objects::Location& from_here,
832    const std::string& message,
833    bool delete_sync_database) {
834  DCHECK(HasUnrecoverableError());
835  unrecoverable_error_message_ = message;
836  unrecoverable_error_location_ = from_here;
837
838  UMA_HISTOGRAM_ENUMERATION(kSyncUnrecoverableErrorHistogram,
839                            unrecoverable_error_reason_,
840                            ERROR_REASON_LIMIT);
841  NotifyObservers();
842  std::string location;
843  from_here.Write(true, true, &location);
844  LOG(ERROR)
845      << "Unrecoverable error detected at " << location
846      << " -- ProfileSyncService unusable: " << message;
847
848  // Shut all data types down.
849  base::MessageLoop::current()->PostTask(FROM_HERE,
850      base::Bind(&ProfileSyncService::ShutdownImpl, weak_factory_.GetWeakPtr(),
851                 delete_sync_database));
852}
853
854// TODO(zea): Move this logic into the DataTypeController/DataTypeManager.
855void ProfileSyncService::DisableBrokenDatatype(
856    syncer::ModelType type,
857    const tracked_objects::Location& from_here,
858    std::string message) {
859  // First deactivate the type so that no further server changes are
860  // passed onto the change processor.
861  DeactivateDataType(type);
862
863  syncer::SyncError error(from_here,
864                          syncer::SyncError::DATATYPE_ERROR,
865                          message,
866                          type);
867
868  std::map<syncer::ModelType, syncer::SyncError> errors;
869  errors[type] = error;
870
871  // Update this before posting a task. So if a configure happens before
872  // the task that we are going to post, this type would still be disabled.
873  failed_data_types_handler_.UpdateFailedDataTypes(errors);
874
875  base::MessageLoop::current()->PostTask(FROM_HERE,
876      base::Bind(&ProfileSyncService::ReconfigureDatatypeManager,
877                 weak_factory_.GetWeakPtr()));
878}
879
880void ProfileSyncService::OnBackendInitialized(
881    const syncer::WeakHandle<syncer::JsBackend>& js_backend,
882    const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
883        debug_info_listener,
884    bool success) {
885  is_first_time_sync_configure_ = !HasSyncSetupCompleted();
886
887  if (is_first_time_sync_configure_) {
888    UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeFirstTimeSuccess", success);
889  } else {
890    UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeRestoreSuccess", success);
891  }
892
893  DCHECK(!start_up_time_.is_null());
894  base::Time on_backend_initialized_time = base::Time::Now();
895  base::TimeDelta delta = on_backend_initialized_time - start_up_time_;
896  if (is_first_time_sync_configure_) {
897    UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeFirstTime", delta);
898  } else {
899    UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeRestoreTime", delta);
900  }
901
902  if (!success) {
903    // Something went unexpectedly wrong.  Play it safe: stop syncing at once
904    // and surface error UI to alert the user sync has stopped.
905    // Keep the directory around for now so that on restart we will retry
906    // again and potentially succeed in presence of transient file IO failures
907    // or permissions issues, etc.
908    //
909    // TODO(rlarocque): Consider making this UnrecoverableError less special.
910    // Unlike every other UnrecoverableError, it does not delete our sync data.
911    // This exception made sense at the time it was implemented, but our new
912    // directory corruption recovery mechanism makes it obsolete.  By the time
913    // we get here, we will have already tried and failed to delete the
914    // directory.  It would be no big deal if we tried to delete it again.
915    OnInternalUnrecoverableError(FROM_HERE,
916                                 "BackendInitialize failure",
917                                 false,
918                                 ERROR_REASON_BACKEND_INIT_FAILURE);
919    return;
920  }
921
922  backend_initialized_ = true;
923
924  sync_js_controller_.AttachJsBackend(js_backend);
925  debug_info_listener_ = debug_info_listener;
926
927  // If we have a cached passphrase use it to decrypt/encrypt data now that the
928  // backend is initialized. We want to call this before notifying observers in
929  // case this operation affects the "passphrase required" status.
930  ConsumeCachedPassphraseIfPossible();
931
932  // The very first time the backend initializes is effectively the first time
933  // we can say we successfully "synced".  last_synced_time_ will only be null
934  // in this case, because the pref wasn't restored on StartUp.
935  if (last_synced_time_.is_null()) {
936    UpdateLastSyncedTime();
937  }
938
939  if (auto_start_enabled_ && !FirstSetupInProgress()) {
940    // Backend is initialized but we're not in sync setup, so this must be an
941    // autostart - mark our sync setup as completed and we'll start syncing
942    // below.
943    SetSyncSetupCompleted();
944  }
945
946  // Check HasSyncSetupCompleted() before NotifyObservers() to avoid spurious
947  // data type configuration because observer may flag setup as complete and
948  // trigger data type configuration.
949  if (HasSyncSetupCompleted()) {
950    ConfigureDataTypeManager();
951  } else {
952    DCHECK(FirstSetupInProgress());
953  }
954
955  NotifyObservers();
956}
957
958void ProfileSyncService::OnSyncCycleCompleted() {
959  UpdateLastSyncedTime();
960  if (GetSessionModelAssociator()) {
961    // Trigger garbage collection of old sessions now that we've downloaded
962    // any new session data. TODO(zea): Have this be a notification the session
963    // model associator listens too. Also consider somehow plumbing the current
964    // server time as last reported by CheckServerReachable, so we don't have to
965    // rely on the local clock, which may be off significantly.
966    base::MessageLoop::current()->PostTask(FROM_HERE,
967        base::Bind(&browser_sync::SessionModelAssociator::DeleteStaleSessions,
968                   GetSessionModelAssociator()->AsWeakPtr()));
969  }
970  DVLOG(2) << "Notifying observers sync cycle completed";
971  NotifySyncCycleCompleted();
972}
973
974void ProfileSyncService::OnExperimentsChanged(
975    const syncer::Experiments& experiments) {
976  if (current_experiments_.Matches(experiments))
977    return;
978
979  // If this is a first time sync for a client, this will be called before
980  // OnBackendInitialized() to ensure the new datatypes are available at sync
981  // setup. As a result, the migrator won't exist yet. This is fine because for
982  // first time sync cases we're only concerned with making the datatype
983  // available.
984  if (migrator_.get() &&
985      migrator_->state() != browser_sync::BackendMigrator::IDLE) {
986    DVLOG(1) << "Dropping OnExperimentsChanged due to migrator busy.";
987    return;
988  }
989
990  const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
991  syncer::ModelTypeSet to_add;
992  const syncer::ModelTypeSet to_register =
993      Difference(to_add, registered_types);
994  DVLOG(2) << "OnExperimentsChanged called with types: "
995           << syncer::ModelTypeSetToString(to_add);
996  DVLOG(2) << "Enabling types: " << syncer::ModelTypeSetToString(to_register);
997
998  for (syncer::ModelTypeSet::Iterator it = to_register.First();
999       it.Good(); it.Inc()) {
1000    // Received notice to enable experimental type. Check if the type is
1001    // registered, and if not register a new datatype controller.
1002    RegisterNewDataType(it.Get());
1003  }
1004
1005  // Check if the user has "Keep Everything Synced" enabled. If so, we want
1006  // to turn on all experimental types if they're not already on. Otherwise we
1007  // leave them off.
1008  // Note: if any types are already registered, we don't turn them on. This
1009  // covers the case where we're already in the process of reconfiguring
1010  // to turn an experimental type on.
1011  if (sync_prefs_.HasKeepEverythingSynced()) {
1012    // Mark all data types as preferred.
1013    sync_prefs_.SetPreferredDataTypes(registered_types, registered_types);
1014
1015    // Only automatically turn on types if we have already finished set up.
1016    // Otherwise, just leave the experimental types on by default.
1017    if (!to_register.Empty() && HasSyncSetupCompleted() && migrator_) {
1018      DVLOG(1) << "Dynamically enabling new datatypes: "
1019               << syncer::ModelTypeSetToString(to_register);
1020      OnMigrationNeededForTypes(to_register);
1021    }
1022  }
1023
1024  if (experiments.favicon_sync)
1025    profile_->GetPrefs()->SetBoolean(prefs::kSyncFaviconsEnabled, true);
1026
1027  current_experiments_ = experiments;
1028}
1029
1030void ProfileSyncService::UpdateAuthErrorState(const AuthError& error) {
1031  is_auth_in_progress_ = false;
1032  last_auth_error_ = error;
1033
1034  // Fan the notification out to interested UI-thread components. Notify the
1035  // SigninGlobalError first so it reflects the latest auth state before we
1036  // notify observers.
1037  if (signin())
1038    signin()->signin_global_error()->AuthStatusChanged();
1039  NotifyObservers();
1040}
1041
1042namespace {
1043
1044AuthError ConnectionStatusToAuthError(
1045    syncer::ConnectionStatus status) {
1046  switch (status) {
1047    case syncer::CONNECTION_OK:
1048      return AuthError::AuthErrorNone();
1049      break;
1050    case syncer::CONNECTION_AUTH_ERROR:
1051      return AuthError(AuthError::INVALID_GAIA_CREDENTIALS);
1052      break;
1053    case syncer::CONNECTION_SERVER_ERROR:
1054      return AuthError(AuthError::CONNECTION_FAILED);
1055      break;
1056    default:
1057      NOTREACHED();
1058      return AuthError(AuthError::CONNECTION_FAILED);
1059  }
1060}
1061
1062}  // namespace
1063
1064void ProfileSyncService::OnConnectionStatusChange(
1065    syncer::ConnectionStatus status) {
1066  if (use_oauth2_token_ && status == syncer::CONNECTION_AUTH_ERROR) {
1067    // Sync server returned error indicating that access token is invalid. It
1068    // could be either expired or access is revoked. Let's request another
1069    // access token and if access is revoked then request for token will fail
1070    // with corresponding error.
1071    RequestAccessToken();
1072  } else {
1073    const GoogleServiceAuthError auth_error =
1074        ConnectionStatusToAuthError(status);
1075    DVLOG(1) << "Connection status change: " << auth_error.ToString();
1076    UpdateAuthErrorState(auth_error);
1077  }
1078}
1079
1080void ProfileSyncService::OnStopSyncingPermanently() {
1081  sync_prefs_.SetStartSuppressed(true);
1082  DisableForUser();
1083}
1084
1085void ProfileSyncService::OnPassphraseRequired(
1086    syncer::PassphraseRequiredReason reason,
1087    const sync_pb::EncryptedData& pending_keys) {
1088  DCHECK(backend_.get());
1089  DCHECK(backend_->IsNigoriEnabled());
1090
1091  // TODO(lipalani) : add this check to other locations as well.
1092  if (HasUnrecoverableError()) {
1093    // When unrecoverable error is detected we post a task to shutdown the
1094    // backend. The task might not have executed yet.
1095    return;
1096  }
1097
1098  DVLOG(1) << "Passphrase required with reason: "
1099           << syncer::PassphraseRequiredReasonToString(reason);
1100  passphrase_required_reason_ = reason;
1101
1102  const syncer::ModelTypeSet types = GetPreferredDataTypes();
1103  if (data_type_manager_) {
1104    // Reconfigure without the encrypted types (excluded implicitly via the
1105    // failed datatypes handler).
1106    data_type_manager_->Configure(types,
1107                                  syncer::CONFIGURE_REASON_CRYPTO);
1108  }
1109
1110  // Notify observers that the passphrase status may have changed.
1111  NotifyObservers();
1112}
1113
1114void ProfileSyncService::OnPassphraseAccepted() {
1115  DVLOG(1) << "Received OnPassphraseAccepted.";
1116
1117  // If the pending keys were resolved via keystore, it's possible we never
1118  // consumed our cached passphrase. Clear it now.
1119  if (!cached_passphrase_.empty())
1120    cached_passphrase_.clear();
1121
1122  // Reset passphrase_required_reason_ since we know we no longer require the
1123  // passphrase. We do this here rather than down in ResolvePassphraseRequired()
1124  // because that can be called by OnPassphraseRequired() if no encrypted data
1125  // types are enabled, and we don't want to clobber the true passphrase error.
1126  passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
1127
1128  // Make sure the data types that depend on the passphrase are started at
1129  // this time.
1130  const syncer::ModelTypeSet types = GetPreferredDataTypes();
1131  if (data_type_manager_) {
1132    // Re-enable any encrypted types if necessary.
1133    data_type_manager_->Configure(types,
1134                                  syncer::CONFIGURE_REASON_CRYPTO);
1135  }
1136
1137  NotifyObservers();
1138}
1139
1140void ProfileSyncService::OnEncryptedTypesChanged(
1141    syncer::ModelTypeSet encrypted_types,
1142    bool encrypt_everything) {
1143  encrypted_types_ = encrypted_types;
1144  encrypt_everything_ = encrypt_everything;
1145  DVLOG(1) << "Encrypted types changed to "
1146           << syncer::ModelTypeSetToString(encrypted_types_)
1147           << " (encrypt everything is set to "
1148           << (encrypt_everything_ ? "true" : "false") << ")";
1149  DCHECK(encrypted_types_.Has(syncer::PASSWORDS));
1150
1151  // If sessions are encrypted, full history sync is not possible, and
1152  // delete directives are unnecessary.
1153  if (GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES) &&
1154      encrypted_types_.Has(syncer::SESSIONS)) {
1155    DisableBrokenDatatype(syncer::HISTORY_DELETE_DIRECTIVES,
1156                          FROM_HERE,
1157                          "Delete directives not supported with encryption.");
1158  }
1159}
1160
1161void ProfileSyncService::OnEncryptionComplete() {
1162  DVLOG(1) << "Encryption complete";
1163  if (encryption_pending_ && encrypt_everything_) {
1164    encryption_pending_ = false;
1165    // This is to nudge the integration tests when encryption is
1166    // finished.
1167    NotifyObservers();
1168  }
1169}
1170
1171void ProfileSyncService::OnMigrationNeededForTypes(
1172    syncer::ModelTypeSet types) {
1173  DCHECK(backend_initialized_);
1174  DCHECK(data_type_manager_.get());
1175
1176  // Migrator must be valid, because we don't sync until it is created and this
1177  // callback originates from a sync cycle.
1178  migrator_->MigrateTypes(types);
1179}
1180
1181void ProfileSyncService::OnActionableError(const SyncProtocolError& error) {
1182  last_actionable_error_ = error;
1183  DCHECK_NE(last_actionable_error_.action,
1184            syncer::UNKNOWN_ACTION);
1185  switch (error.action) {
1186    case syncer::UPGRADE_CLIENT:
1187    case syncer::CLEAR_USER_DATA_AND_RESYNC:
1188    case syncer::ENABLE_SYNC_ON_ACCOUNT:
1189    case syncer::STOP_AND_RESTART_SYNC:
1190      // TODO(lipalani) : if setup in progress we want to display these
1191      // actions in the popup. The current experience might not be optimal for
1192      // the user. We just dismiss the dialog.
1193      if (setup_in_progress_) {
1194        OnStopSyncingPermanently();
1195        expect_sync_configuration_aborted_ = true;
1196      }
1197      // Trigger an unrecoverable error to stop syncing.
1198      OnInternalUnrecoverableError(FROM_HERE,
1199                                   last_actionable_error_.error_description,
1200                                   true,
1201                                   ERROR_REASON_ACTIONABLE_ERROR);
1202      break;
1203    case syncer::DISABLE_SYNC_ON_CLIENT:
1204      OnStopSyncingPermanently();
1205#if !defined(OS_CHROMEOS)
1206      // On desktop Chrome, sign out the user after a dashboard clear.
1207      // TODO(rsimha): Revisit this for M30. See http://crbug.com/252049.
1208      if (!auto_start_enabled_)  // Skip sign out on ChromeOS/Android.
1209        SigninManagerFactory::GetForProfile(profile_)->SignOut();
1210#endif
1211      break;
1212    case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT:
1213      // Sync disabled by domain admin. we should stop syncing until next
1214      // restart.
1215      sync_disabled_by_admin_ = true;
1216      ShutdownImpl(true);
1217      break;
1218    default:
1219      NOTREACHED();
1220  }
1221  NotifyObservers();
1222}
1223
1224void ProfileSyncService::OnConfigureDone(
1225    const browser_sync::DataTypeManager::ConfigureResult& result) {
1226  // We should have cleared our cached passphrase before we get here (in
1227  // OnBackendInitialized()).
1228  DCHECK(cached_passphrase_.empty());
1229
1230  if (!sync_configure_start_time_.is_null()) {
1231    if (result.status == DataTypeManager::OK ||
1232        result.status == DataTypeManager::PARTIAL_SUCCESS) {
1233      base::Time sync_configure_stop_time = base::Time::Now();
1234      base::TimeDelta delta = sync_configure_stop_time -
1235          sync_configure_start_time_;
1236      if (is_first_time_sync_configure_) {
1237        UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceInitialConfigureTime", delta);
1238      } else {
1239        UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceSubsequentConfigureTime",
1240                                  delta);
1241      }
1242    }
1243    sync_configure_start_time_ = base::Time();
1244  }
1245
1246  // Notify listeners that configuration is done.
1247  content::NotificationService::current()->Notify(
1248      chrome::NOTIFICATION_SYNC_CONFIGURE_DONE,
1249      content::Source<ProfileSyncService>(this),
1250      content::NotificationService::NoDetails());
1251
1252  configure_status_ = result.status;
1253  DVLOG(1) << "PSS OnConfigureDone called with status: " << configure_status_;
1254  // The possible status values:
1255  //    ABORT - Configuration was aborted. This is not an error, if
1256  //            initiated by user.
1257  //    OK - Everything succeeded.
1258  //    PARTIAL_SUCCESS - Some datatypes failed to start.
1259  //    Everything else is an UnrecoverableError. So treat it as such.
1260
1261  // First handle the abort case.
1262  if (configure_status_ == DataTypeManager::ABORTED &&
1263      expect_sync_configuration_aborted_) {
1264    DVLOG(0) << "ProfileSyncService::Observe Sync Configure aborted";
1265    expect_sync_configuration_aborted_ = false;
1266    return;
1267  }
1268
1269  // Handle unrecoverable error.
1270  if (configure_status_ != DataTypeManager::OK &&
1271      configure_status_ != DataTypeManager::PARTIAL_SUCCESS) {
1272    // Something catastrophic had happened. We should only have one
1273    // error representing it.
1274    DCHECK_EQ(result.failed_data_types.size(),
1275              static_cast<unsigned int>(1));
1276    syncer::SyncError error = result.failed_data_types.begin()->second;
1277    DCHECK(error.IsSet());
1278    std::string message =
1279        "Sync configuration failed with status " +
1280        DataTypeManager::ConfigureStatusToString(configure_status_) +
1281        " during " + syncer::ModelTypeToString(error.model_type()) +
1282        ": " + error.message();
1283    LOG(ERROR) << "ProfileSyncService error: " << message;
1284    OnInternalUnrecoverableError(error.location(),
1285                                 message,
1286                                 true,
1287                                 ERROR_REASON_CONFIGURATION_FAILURE);
1288    return;
1289  }
1290
1291  // We should never get in a state where we have no encrypted datatypes
1292  // enabled, and yet we still think we require a passphrase for decryption.
1293  DCHECK(!(IsPassphraseRequiredForDecryption() &&
1294           !IsEncryptedDatatypeEnabled()));
1295
1296  // This must be done before we start syncing with the server to avoid
1297  // sending unencrypted data up on a first time sync.
1298  if (encryption_pending_)
1299    backend_->EnableEncryptEverything();
1300  NotifyObservers();
1301
1302  if (migrator_.get() &&
1303      migrator_->state() != browser_sync::BackendMigrator::IDLE) {
1304    // Migration in progress.  Let the migrator know we just finished
1305    // configuring something.  It will be up to the migrator to call
1306    // StartSyncingWithServer() if migration is now finished.
1307    migrator_->OnConfigureDone(result);
1308  } else {
1309    StartSyncingWithServer();
1310  }
1311}
1312
1313void ProfileSyncService::OnConfigureRetry() {
1314  // We should have cleared our cached passphrase before we get here (in
1315  // OnBackendInitialized()).
1316  DCHECK(cached_passphrase_.empty());
1317
1318  OnSyncConfigureRetry();
1319}
1320
1321void ProfileSyncService::OnConfigureStart() {
1322  sync_configure_start_time_ = base::Time::Now();
1323  content::NotificationService::current()->Notify(
1324      chrome::NOTIFICATION_SYNC_CONFIGURE_START,
1325      content::Source<ProfileSyncService>(this),
1326      content::NotificationService::NoDetails());
1327  NotifyObservers();
1328}
1329
1330std::string ProfileSyncService::QuerySyncStatusSummary() {
1331  if (HasUnrecoverableError()) {
1332    return "Unrecoverable error detected";
1333  } else if (!backend_) {
1334    return "Syncing not enabled";
1335  } else if (backend_.get() && !HasSyncSetupCompleted()) {
1336    return "First time sync setup incomplete";
1337  } else if (backend_.get() && HasSyncSetupCompleted() &&
1338             data_type_manager_.get() &&
1339             data_type_manager_->state() != DataTypeManager::CONFIGURED) {
1340    return "Datatypes not fully initialized";
1341  } else if (ShouldPushChanges()) {
1342    return "Sync service initialized";
1343  } else {
1344    return "Status unknown: Internal error?";
1345  }
1346}
1347
1348std::string ProfileSyncService::GetBackendInitializationStateString() const {
1349  if (sync_initialized())
1350    return "Done";
1351  else if (!start_up_time_.is_null())
1352    return "Deferred";
1353  else
1354    return "Not started";
1355}
1356
1357bool ProfileSyncService::QueryDetailedSyncStatus(
1358    SyncBackendHost::Status* result) {
1359  if (backend_.get() && backend_initialized_) {
1360    *result = backend_->GetDetailedStatus();
1361    return true;
1362  } else {
1363    SyncBackendHost::Status status;
1364    status.sync_protocol_error = last_actionable_error_;
1365    *result = status;
1366    return false;
1367  }
1368}
1369
1370const AuthError& ProfileSyncService::GetAuthError() const {
1371  return last_auth_error_;
1372}
1373
1374GoogleServiceAuthError ProfileSyncService::GetAuthStatus() const {
1375  return GetAuthError();
1376}
1377
1378bool ProfileSyncService::FirstSetupInProgress() const {
1379  return !HasSyncSetupCompleted() && setup_in_progress_;
1380}
1381
1382void ProfileSyncService::SetSetupInProgress(bool setup_in_progress) {
1383  // This method is a no-op if |setup_in_progress_| remains unchanged.
1384  if (setup_in_progress_ == setup_in_progress)
1385    return;
1386
1387  setup_in_progress_ = setup_in_progress;
1388  if (!setup_in_progress && sync_initialized())
1389    ReconfigureDatatypeManager();
1390  NotifyObservers();
1391}
1392
1393bool ProfileSyncService::sync_initialized() const {
1394  return backend_initialized_;
1395}
1396
1397bool ProfileSyncService::waiting_for_auth() const {
1398  return is_auth_in_progress_;
1399}
1400
1401const syncer::Experiments& ProfileSyncService::current_experiments() const {
1402  return current_experiments_;
1403}
1404
1405bool ProfileSyncService::HasUnrecoverableError() const {
1406  return unrecoverable_error_reason_ != ERROR_REASON_UNSET;
1407}
1408
1409bool ProfileSyncService::IsPassphraseRequired() const {
1410  return passphrase_required_reason_ !=
1411      syncer::REASON_PASSPHRASE_NOT_REQUIRED;
1412}
1413
1414bool ProfileSyncService::IsPassphraseRequiredForDecryption() const {
1415  // If there is an encrypted datatype enabled and we don't have the proper
1416  // passphrase, we must prompt the user for a passphrase. The only way for the
1417  // user to avoid entering their passphrase is to disable the encrypted types.
1418  return IsEncryptedDatatypeEnabled() && IsPassphraseRequired();
1419}
1420
1421string16 ProfileSyncService::GetLastSyncedTimeString() const {
1422  if (last_synced_time_.is_null())
1423    return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER);
1424
1425  base::TimeDelta last_synced = base::Time::Now() - last_synced_time_;
1426
1427  if (last_synced < base::TimeDelta::FromMinutes(1))
1428    return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW);
1429
1430  return TimeFormat::TimeElapsed(last_synced);
1431}
1432
1433void ProfileSyncService::UpdateSelectedTypesHistogram(
1434    bool sync_everything, const syncer::ModelTypeSet chosen_types) const {
1435  if (!HasSyncSetupCompleted() ||
1436      sync_everything != sync_prefs_.HasKeepEverythingSynced()) {
1437    UMA_HISTOGRAM_BOOLEAN("Sync.SyncEverything", sync_everything);
1438  }
1439
1440  // Only log the data types that are shown in the sync settings ui.
1441  // Note: the order of these types must match the ordering of
1442  // the respective types in ModelType
1443const browser_sync::user_selectable_type::UserSelectableSyncType
1444      user_selectable_types[] = {
1445    browser_sync::user_selectable_type::BOOKMARKS,
1446    browser_sync::user_selectable_type::PREFERENCES,
1447    browser_sync::user_selectable_type::PASSWORDS,
1448    browser_sync::user_selectable_type::AUTOFILL,
1449    browser_sync::user_selectable_type::THEMES,
1450    browser_sync::user_selectable_type::TYPED_URLS,
1451    browser_sync::user_selectable_type::EXTENSIONS,
1452    browser_sync::user_selectable_type::APPS,
1453    browser_sync::user_selectable_type::PROXY_TABS
1454  };
1455
1456  COMPILE_ASSERT(28 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram);
1457
1458  if (!sync_everything) {
1459    const syncer::ModelTypeSet current_types = GetPreferredDataTypes();
1460
1461    syncer::ModelTypeSet type_set = syncer::UserSelectableTypes();
1462    syncer::ModelTypeSet::Iterator it = type_set.First();
1463
1464    DCHECK_EQ(arraysize(user_selectable_types), type_set.Size());
1465
1466    for (size_t i = 0; i < arraysize(user_selectable_types) && it.Good();
1467         ++i, it.Inc()) {
1468      const syncer::ModelType type = it.Get();
1469      if (chosen_types.Has(type) &&
1470          (!HasSyncSetupCompleted() || !current_types.Has(type))) {
1471        // Selected type has changed - log it.
1472        UMA_HISTOGRAM_ENUMERATION(
1473            "Sync.CustomSync",
1474            user_selectable_types[i],
1475            browser_sync::user_selectable_type::SELECTABLE_DATATYPE_COUNT + 1);
1476      }
1477    }
1478  }
1479}
1480
1481#if defined(OS_CHROMEOS)
1482void ProfileSyncService::RefreshSpareBootstrapToken(
1483    const std::string& passphrase) {
1484  browser_sync::ChromeEncryptor encryptor;
1485  syncer::Cryptographer temp_cryptographer(&encryptor);
1486  // The first 2 params (hostname and username) doesn't have any effect here.
1487  syncer::KeyParams key_params = {"localhost", "dummy", passphrase};
1488
1489  std::string bootstrap_token;
1490  if (!temp_cryptographer.AddKey(key_params)) {
1491    NOTREACHED() << "Failed to add key to cryptographer.";
1492  }
1493  temp_cryptographer.GetBootstrapToken(&bootstrap_token);
1494  sync_prefs_.SetSpareBootstrapToken(bootstrap_token);
1495}
1496#endif
1497
1498void ProfileSyncService::OnUserChoseDatatypes(
1499    bool sync_everything,
1500    syncer::ModelTypeSet chosen_types) {
1501  if (!backend_.get() && !HasUnrecoverableError()) {
1502    NOTREACHED();
1503    return;
1504  }
1505
1506  UpdateSelectedTypesHistogram(sync_everything, chosen_types);
1507  sync_prefs_.SetKeepEverythingSynced(sync_everything);
1508
1509  failed_data_types_handler_.Reset();
1510  if (GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES) &&
1511      encrypted_types_.Has(syncer::SESSIONS)) {
1512    DisableBrokenDatatype(syncer::HISTORY_DELETE_DIRECTIVES,
1513                          FROM_HERE,
1514                          "Delete directives not supported with encryption.");
1515  }
1516  ChangePreferredDataTypes(chosen_types);
1517  AcknowledgeSyncedTypes();
1518  NotifyObservers();
1519}
1520
1521void ProfileSyncService::ChangePreferredDataTypes(
1522    syncer::ModelTypeSet preferred_types) {
1523
1524  DVLOG(1) << "ChangePreferredDataTypes invoked";
1525  const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
1526  const syncer::ModelTypeSet registered_preferred_types =
1527      Intersection(registered_types, preferred_types);
1528  sync_prefs_.SetPreferredDataTypes(registered_types,
1529                                    registered_preferred_types);
1530
1531  // Now reconfigure the DTM.
1532  ReconfigureDatatypeManager();
1533}
1534
1535syncer::ModelTypeSet ProfileSyncService::GetActiveDataTypes() const {
1536  const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes();
1537  const syncer::ModelTypeSet failed_types =
1538      failed_data_types_handler_.GetFailedTypes();
1539  return Difference(preferred_types, failed_types);
1540}
1541
1542syncer::ModelTypeSet ProfileSyncService::GetPreferredDataTypes() const {
1543  const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
1544  const syncer::ModelTypeSet preferred_types =
1545      sync_prefs_.GetPreferredDataTypes(registered_types);
1546  return preferred_types;
1547}
1548
1549syncer::ModelTypeSet ProfileSyncService::GetRegisteredDataTypes() const {
1550  syncer::ModelTypeSet registered_types;
1551  // The data_type_controllers_ are determined by command-line flags; that's
1552  // effectively what controls the values returned here.
1553  for (DataTypeController::TypeMap::const_iterator it =
1554       data_type_controllers_.begin();
1555       it != data_type_controllers_.end(); ++it) {
1556    registered_types.Put(it->first);
1557  }
1558  return registered_types;
1559}
1560
1561bool ProfileSyncService::IsUsingSecondaryPassphrase() const {
1562  syncer::PassphraseType passphrase_type = GetPassphraseType();
1563  return passphrase_type == syncer::FROZEN_IMPLICIT_PASSPHRASE ||
1564         passphrase_type == syncer::CUSTOM_PASSPHRASE;
1565}
1566
1567syncer::PassphraseType ProfileSyncService::GetPassphraseType() const {
1568  return backend_->GetPassphraseType();
1569}
1570
1571base::Time ProfileSyncService::GetExplicitPassphraseTime() const {
1572  return backend_->GetExplicitPassphraseTime();
1573}
1574
1575bool ProfileSyncService::IsCryptographerReady(
1576    const syncer::BaseTransaction* trans) const {
1577  return backend_.get() && backend_->IsCryptographerReady(trans);
1578}
1579
1580SyncBackendHost* ProfileSyncService::GetBackendForTest() {
1581  // We don't check |backend_initialized_|; we assume the test class
1582  // knows what it's doing.
1583  return backend_.get();
1584}
1585
1586void ProfileSyncService::ConfigurePriorityDataTypes() {
1587  const syncer::ModelTypeSet priority_types =
1588      Intersection(GetPreferredDataTypes(), syncer::PriorityUserTypes());
1589  if (!priority_types.Empty()) {
1590    const syncer::ConfigureReason reason = HasSyncSetupCompleted() ?
1591        syncer::CONFIGURE_REASON_RECONFIGURATION :
1592        syncer::CONFIGURE_REASON_NEW_CLIENT;
1593    data_type_manager_->Configure(priority_types, reason);
1594  }
1595}
1596
1597void ProfileSyncService::ConfigureDataTypeManager() {
1598  // Don't configure datatypes if the setup UI is still on the screen - this
1599  // is to help multi-screen setting UIs (like iOS) where they don't want to
1600  // start syncing data until the user is done configuring encryption options,
1601  // etc. ReconfigureDatatypeManager() will get called again once the UI calls
1602  // SetSetupInProgress(false).
1603  if (setup_in_progress_)
1604    return;
1605
1606  bool restart = false;
1607  if (!data_type_manager_) {
1608    restart = true;
1609    data_type_manager_.reset(
1610        factory_->CreateDataTypeManager(debug_info_listener_,
1611                                        &data_type_controllers_,
1612                                        this,
1613                                        backend_.get(),
1614                                        this,
1615                                        &failed_data_types_handler_));
1616
1617    // We create the migrator at the same time.
1618    migrator_.reset(
1619        new browser_sync::BackendMigrator(
1620            profile_->GetDebugName(), GetUserShare(),
1621            this, data_type_manager_.get(),
1622            base::Bind(&ProfileSyncService::StartSyncingWithServer,
1623                       base::Unretained(this))));
1624  }
1625
1626  const syncer::ModelTypeSet types = GetPreferredDataTypes();
1627  syncer::ConfigureReason reason = syncer::CONFIGURE_REASON_UNKNOWN;
1628  if (!HasSyncSetupCompleted()) {
1629    reason = syncer::CONFIGURE_REASON_NEW_CLIENT;
1630  } else if (restart) {
1631    // Datatype downloads on restart are generally due to newly supported
1632    // datatypes (although it's also possible we're picking up where a failed
1633    // previous configuration left off).
1634    // TODO(sync): consider detecting configuration recovery and setting
1635    // the reason here appropriately.
1636    reason = syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
1637  } else {
1638    // The user initiated a reconfiguration (either to add or remove types).
1639    reason = syncer::CONFIGURE_REASON_RECONFIGURATION;
1640  }
1641
1642  data_type_manager_->Configure(types, reason);
1643}
1644
1645syncer::UserShare* ProfileSyncService::GetUserShare() const {
1646  if (backend_.get() && backend_initialized_) {
1647    return backend_->GetUserShare();
1648  }
1649  NOTREACHED();
1650  return NULL;
1651}
1652
1653syncer::sessions::SyncSessionSnapshot
1654    ProfileSyncService::GetLastSessionSnapshot() const {
1655  if (backend_.get() && backend_initialized_) {
1656    return backend_->GetLastSessionSnapshot();
1657  }
1658  NOTREACHED();
1659  return syncer::sessions::SyncSessionSnapshot();
1660}
1661
1662bool ProfileSyncService::HasUnsyncedItems() const {
1663  if (backend_.get() && backend_initialized_) {
1664    return backend_->HasUnsyncedItems();
1665  }
1666  NOTREACHED();
1667  return false;
1668}
1669
1670browser_sync::BackendMigrator*
1671    ProfileSyncService::GetBackendMigratorForTest() {
1672  return migrator_.get();
1673}
1674
1675void ProfileSyncService::GetModelSafeRoutingInfo(
1676    syncer::ModelSafeRoutingInfo* out) const {
1677  if (backend_.get() && backend_initialized_) {
1678    backend_->GetModelSafeRoutingInfo(out);
1679  } else {
1680    NOTREACHED();
1681  }
1682}
1683
1684Value* ProfileSyncService::GetTypeStatusMap() const {
1685  scoped_ptr<ListValue> result(new ListValue());
1686
1687  if (!backend_.get() || !backend_initialized_) {
1688    return result.release();
1689  }
1690
1691  FailedDataTypesHandler::TypeErrorMap error_map =
1692      failed_data_types_handler_.GetAllErrors();
1693
1694  ModelTypeSet active_types;
1695  ModelTypeSet passive_types;
1696  ModelSafeRoutingInfo routing_info;
1697  backend_->GetModelSafeRoutingInfo(&routing_info);
1698  for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
1699       it != routing_info.end(); ++it) {
1700    if (it->second == syncer::GROUP_PASSIVE) {
1701      passive_types.Put(it->first);
1702    } else {
1703      active_types.Put(it->first);
1704    }
1705  }
1706
1707  SyncBackendHost::Status detailed_status = backend_->GetDetailedStatus();
1708  ModelTypeSet &throttled_types(detailed_status.throttled_types);
1709  ModelTypeSet registered = GetRegisteredDataTypes();
1710  scoped_ptr<DictionaryValue> type_status_header(new DictionaryValue());
1711
1712  type_status_header->SetString("name", "Model Type");
1713  type_status_header->SetString("status", "header");
1714  type_status_header->SetString("value", "Group Type");
1715  type_status_header->SetString("num_entries", "Total Entries");
1716  type_status_header->SetString("num_live", "Live Entries");
1717  result->Append(type_status_header.release());
1718
1719  scoped_ptr<DictionaryValue> type_status;
1720  for (ModelTypeSet::Iterator it = registered.First(); it.Good(); it.Inc()) {
1721    ModelType type = it.Get();
1722
1723    type_status.reset(new DictionaryValue());
1724    type_status->SetString("name", ModelTypeToString(type));
1725
1726    if (error_map.find(type) != error_map.end()) {
1727      const syncer::SyncError &error = error_map.find(type)->second;
1728      DCHECK(error.IsSet());
1729      std::string error_text = "Error: " + error.location().ToString() +
1730          ", " + error.message();
1731      type_status->SetString("status", "error");
1732      type_status->SetString("value", error_text);
1733    } else if (throttled_types.Has(type) && passive_types.Has(type)) {
1734      type_status->SetString("status", "warning");
1735      type_status->SetString("value", "Passive, Throttled");
1736    } else if (passive_types.Has(type)) {
1737      type_status->SetString("status", "warning");
1738      type_status->SetString("value", "Passive");
1739    } else if (throttled_types.Has(type)) {
1740      type_status->SetString("status", "warning");
1741      type_status->SetString("value", "Throttled");
1742    } else if (active_types.Has(type)) {
1743      type_status->SetString("status", "ok");
1744      type_status->SetString("value", "Active: " +
1745                             ModelSafeGroupToString(routing_info[type]));
1746    } else {
1747      type_status->SetString("status", "warning");
1748      type_status->SetString("value", "Disabled by User");
1749    }
1750
1751    int live_count = detailed_status.num_entries_by_type[type] -
1752        detailed_status.num_to_delete_entries_by_type[type];
1753    type_status->SetInteger("num_entries",
1754                            detailed_status.num_entries_by_type[type]);
1755    type_status->SetInteger("num_live", live_count);
1756
1757    result->Append(type_status.release());
1758  }
1759  return result.release();
1760}
1761
1762void ProfileSyncService::ActivateDataType(
1763    syncer::ModelType type, syncer::ModelSafeGroup group,
1764    ChangeProcessor* change_processor) {
1765  if (!backend_) {
1766    NOTREACHED();
1767    return;
1768  }
1769  DCHECK(backend_initialized_);
1770  backend_->ActivateDataType(type, group, change_processor);
1771}
1772
1773void ProfileSyncService::DeactivateDataType(syncer::ModelType type) {
1774  if (!backend_)
1775    return;
1776  backend_->DeactivateDataType(type);
1777}
1778
1779void ProfileSyncService::ConsumeCachedPassphraseIfPossible() {
1780  // If no cached passphrase, or sync backend hasn't started up yet, just exit.
1781  // If the backend isn't running yet, OnBackendInitialized() will call this
1782  // method again after the backend starts up.
1783  if (cached_passphrase_.empty() || !sync_initialized())
1784    return;
1785
1786  // Backend is up and running, so we can consume the cached passphrase.
1787  std::string passphrase = cached_passphrase_;
1788  cached_passphrase_.clear();
1789
1790  // If we need a passphrase to decrypt data, try the cached passphrase.
1791  if (passphrase_required_reason() == syncer::REASON_DECRYPTION) {
1792    if (SetDecryptionPassphrase(passphrase)) {
1793      DVLOG(1) << "Cached passphrase successfully decrypted pending keys";
1794      return;
1795    }
1796  }
1797
1798  // If we get here, we don't have pending keys (or at least, the passphrase
1799  // doesn't decrypt them) - just try to re-encrypt using the encryption
1800  // passphrase.
1801  if (!IsUsingSecondaryPassphrase())
1802    SetEncryptionPassphrase(passphrase, IMPLICIT);
1803}
1804
1805void ProfileSyncService::RequestAccessToken() {
1806  // Only one active request at a time.
1807  if (access_token_request_ != NULL)
1808    return;
1809  request_access_token_retry_timer_.Stop();
1810  OAuth2TokenService::ScopeSet oauth2_scopes;
1811  bool is_managed = false;
1812#if defined(ENABLE_MANAGED_USERS)
1813  is_managed = ManagedUserService::ProfileIsManaged(profile_);
1814#endif
1815  if (is_managed) {
1816    for (size_t i = 0; i < arraysize(kManagedOAuth2Scopes); i++)
1817      oauth2_scopes.insert(kManagedOAuth2Scopes[i]);
1818  } else {
1819    for (size_t i = 0; i < arraysize(kOAuth2Scopes); i++)
1820      oauth2_scopes.insert(kOAuth2Scopes[i]);
1821  }
1822
1823  OAuth2TokenService* token_service =
1824      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
1825  // Invalidate previous token, otherwise token service will return the same
1826  // token again.
1827  token_service->InvalidateToken(oauth2_scopes, access_token_);
1828  access_token_.clear();
1829  access_token_request_ = token_service->StartRequest(oauth2_scopes, this);
1830}
1831
1832void ProfileSyncService::SetEncryptionPassphrase(const std::string& passphrase,
1833                                                 PassphraseType type) {
1834  // This should only be called when the backend has been initialized.
1835  DCHECK(sync_initialized());
1836  DCHECK(!(type == IMPLICIT && IsUsingSecondaryPassphrase())) <<
1837      "Data is already encrypted using an explicit passphrase";
1838  DCHECK(!(type == EXPLICIT &&
1839           passphrase_required_reason_ == syncer::REASON_DECRYPTION)) <<
1840         "Can not set explicit passphrase when decryption is needed.";
1841
1842  DVLOG(1) << "Setting " << (type == EXPLICIT ? "explicit" : "implicit")
1843           << " passphrase for encryption.";
1844  if (passphrase_required_reason_ == syncer::REASON_ENCRYPTION) {
1845    // REASON_ENCRYPTION implies that the cryptographer does not have pending
1846    // keys. Hence, as long as we're not trying to do an invalid passphrase
1847    // change (e.g. explicit -> explicit or explicit -> implicit), we know this
1848    // will succeed. If for some reason a new encryption key arrives via
1849    // sync later, the SBH will trigger another OnPassphraseRequired().
1850    passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
1851    NotifyObservers();
1852  }
1853  backend_->SetEncryptionPassphrase(passphrase, type == EXPLICIT);
1854}
1855
1856bool ProfileSyncService::SetDecryptionPassphrase(
1857    const std::string& passphrase) {
1858  if (IsPassphraseRequired()) {
1859    DVLOG(1) << "Setting passphrase for decryption.";
1860    return backend_->SetDecryptionPassphrase(passphrase);
1861  } else {
1862    NOTREACHED() << "SetDecryptionPassphrase must not be called when "
1863                    "IsPassphraseRequired() is false.";
1864    return false;
1865  }
1866}
1867
1868void ProfileSyncService::EnableEncryptEverything() {
1869  // Tests override sync_initialized() to always return true, so we
1870  // must check that instead of |backend_initialized_|.
1871  // TODO(akalin): Fix the above. :/
1872  DCHECK(sync_initialized());
1873  // TODO(atwilson): Persist the encryption_pending_ flag to address the various
1874  // problems around cancelling encryption in the background (crbug.com/119649).
1875  if (!encrypt_everything_)
1876    encryption_pending_ = true;
1877}
1878
1879bool ProfileSyncService::encryption_pending() const {
1880  // We may be called during the setup process before we're
1881  // initialized (via IsEncryptedDatatypeEnabled and
1882  // IsPassphraseRequiredForDecryption).
1883  return encryption_pending_;
1884}
1885
1886bool ProfileSyncService::EncryptEverythingEnabled() const {
1887  DCHECK(backend_initialized_);
1888  return encrypt_everything_ || encryption_pending_;
1889}
1890
1891syncer::ModelTypeSet ProfileSyncService::GetEncryptedDataTypes() const {
1892  DCHECK(encrypted_types_.Has(syncer::PASSWORDS));
1893  // We may be called during the setup process before we're
1894  // initialized.  In this case, we default to the sensitive types.
1895  return encrypted_types_;
1896}
1897
1898void ProfileSyncService::OnSyncManagedPrefChange(bool is_sync_managed) {
1899  NotifyObservers();
1900  if (is_sync_managed) {
1901    DisableForUser();
1902  } else {
1903    // Sync is no longer disabled by policy. Try starting it up if appropriate.
1904    TryStart();
1905  }
1906}
1907
1908void ProfileSyncService::Observe(int type,
1909                                 const content::NotificationSource& source,
1910                                 const content::NotificationDetails& details) {
1911  const char* sync_token_service = use_oauth2_token_ ?
1912      GaiaConstants::kGaiaOAuth2LoginRefreshToken : GaiaConstants::kSyncService;
1913  switch (type) {
1914    case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL: {
1915      const GoogleServiceSigninSuccessDetails* successful =
1916          content::Details<const GoogleServiceSigninSuccessDetails>(
1917              details).ptr();
1918      if (!sync_prefs_.IsStartSuppressed() &&
1919          !successful->password.empty()) {
1920        cached_passphrase_ = successful->password;
1921        // Try to consume the passphrase we just cached. If the sync backend
1922        // is not running yet, the passphrase will remain cached until the
1923        // backend starts up.
1924        ConsumeCachedPassphraseIfPossible();
1925      }
1926#if defined(OS_CHROMEOS)
1927      RefreshSpareBootstrapToken(successful->password);
1928#endif
1929      if (!sync_initialized() ||
1930          GetAuthError().state() != AuthError::NONE) {
1931        // Track the fact that we're still waiting for auth to complete.
1932        is_auth_in_progress_ = true;
1933      }
1934      break;
1935    }
1936    case chrome::NOTIFICATION_TOKEN_REQUEST_FAILED: {
1937      // TODO(atwilson): sync shouldn't report refresh token request failures.
1938      // TokenService should do that instead.
1939      const TokenService::TokenRequestFailedDetails& token_details =
1940          *(content::Details<const TokenService::TokenRequestFailedDetails>(
1941              details).ptr());
1942      if (token_details.service() == sync_token_service &&
1943          !IsOAuthRefreshTokenAvailable()) {
1944        // The additional check around IsOAuthRefreshTokenAvailable() above
1945        // prevents us sounding the alarm if we actually have a valid token but
1946        // a refresh attempt by TokenService failed for any variety of reasons
1947        // (e.g. flaky network). It's possible the token we do have is also
1948        // invalid, but in that case we should already have (or can expect) an
1949        // auth error sent from the sync backend.
1950        AuthError error(AuthError::INVALID_GAIA_CREDENTIALS);
1951        UpdateAuthErrorState(error);
1952      }
1953      break;
1954    }
1955    case chrome::NOTIFICATION_TOKEN_AVAILABLE: {
1956      // TODO(atwilson): Listen for notifications on OAuth2TokenService
1957      // (crbug.com/243737)
1958      const TokenService::TokenAvailableDetails& token_details =
1959          *(content::Details<const TokenService::TokenAvailableDetails>(
1960              details).ptr());
1961      if (token_details.service() != sync_token_service)
1962        break;
1963    } // Fall through.
1964    case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: {
1965      // This notification gets fired when TokenService loads the tokens
1966      // from storage.
1967      // Initialize the backend if sync is enabled. If the sync token was
1968      // not loaded, GetCredentials() will generate invalid credentials to
1969      // cause the backend to generate an auth error (crbug.com/121755).
1970      if (backend_) {
1971        if (use_oauth2_token_)
1972          RequestAccessToken();
1973        else
1974          backend_->UpdateCredentials(GetCredentials());
1975      } else {
1976        TryStart();
1977      }
1978      break;
1979    }
1980    case chrome::NOTIFICATION_TOKENS_CLEARED: {
1981      // GetCredentials() will generate invalid credentials to cause the backend
1982      // to generate an auth error.
1983      access_token_.clear();
1984      if (backend_)
1985        backend_->UpdateCredentials(GetCredentials());
1986      break;
1987    }
1988    case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT:
1989      sync_disabled_by_admin_ = false;
1990      DisableForUser();
1991      break;
1992    default: {
1993      NOTREACHED();
1994    }
1995  }
1996}
1997
1998void ProfileSyncService::AddObserver(Observer* observer) {
1999  observers_.AddObserver(observer);
2000}
2001
2002void ProfileSyncService::RemoveObserver(Observer* observer) {
2003  observers_.RemoveObserver(observer);
2004}
2005
2006bool ProfileSyncService::HasObserver(Observer* observer) const {
2007  return observers_.HasObserver(observer);
2008}
2009
2010base::WeakPtr<syncer::JsController> ProfileSyncService::GetJsController() {
2011  return sync_js_controller_.AsWeakPtr();
2012}
2013
2014void ProfileSyncService::SyncEvent(SyncEventCodes code) {
2015  UMA_HISTOGRAM_ENUMERATION("Sync.EventCodes", code, MAX_SYNC_EVENT_CODE);
2016}
2017
2018// static
2019bool ProfileSyncService::IsSyncEnabled() {
2020  // We have switches::kEnableSync just in case we need to change back to
2021  // sync-disabled-by-default on a platform.
2022  return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableSync);
2023}
2024
2025bool ProfileSyncService::IsManaged() const {
2026  return sync_prefs_.IsManaged() || sync_disabled_by_admin_;
2027}
2028
2029bool ProfileSyncService::ShouldPushChanges() {
2030  // True only after all bootstrapping has succeeded: the sync backend
2031  // is initialized, all enabled data types are consistent with one
2032  // another, and no unrecoverable error has transpired.
2033  if (HasUnrecoverableError())
2034    return false;
2035
2036  if (!data_type_manager_)
2037    return false;
2038
2039  return data_type_manager_->state() == DataTypeManager::CONFIGURED;
2040}
2041
2042void ProfileSyncService::StopAndSuppress() {
2043  sync_prefs_.SetStartSuppressed(true);
2044  ShutdownImpl(false);
2045}
2046
2047bool ProfileSyncService::IsStartSuppressed() const {
2048  return sync_prefs_.IsStartSuppressed();
2049}
2050
2051void ProfileSyncService::UnsuppressAndStart() {
2052  DCHECK(profile_);
2053  sync_prefs_.SetStartSuppressed(false);
2054  // Set username in SigninManager, as SigninManager::OnGetUserInfoSuccess
2055  // is never called for some clients.
2056  if (signin_ && signin_->GetAuthenticatedUsername().empty()) {
2057    signin_->SetAuthenticatedUsername(sync_prefs_.GetGoogleServicesUsername());
2058  }
2059  TryStart();
2060}
2061
2062void ProfileSyncService::AcknowledgeSyncedTypes() {
2063  sync_prefs_.AcknowledgeSyncedTypes(GetRegisteredDataTypes());
2064}
2065
2066void ProfileSyncService::ReconfigureDatatypeManager() {
2067  // If we haven't initialized yet, don't configure the DTM as it could cause
2068  // association to start before a Directory has even been created.
2069  if (backend_initialized_) {
2070    DCHECK(backend_.get());
2071    ConfigureDataTypeManager();
2072  } else if (HasUnrecoverableError()) {
2073    // There is nothing more to configure. So inform the listeners,
2074    NotifyObservers();
2075
2076    DVLOG(1) << "ConfigureDataTypeManager not invoked because of an "
2077             << "Unrecoverable error.";
2078  } else {
2079    DVLOG(0) << "ConfigureDataTypeManager not invoked because backend is not "
2080             << "initialized";
2081  }
2082}
2083
2084const FailedDataTypesHandler& ProfileSyncService::failed_data_types_handler()
2085    const {
2086  return failed_data_types_handler_;
2087}
2088
2089void ProfileSyncService::OnInternalUnrecoverableError(
2090    const tracked_objects::Location& from_here,
2091    const std::string& message,
2092    bool delete_sync_database,
2093    UnrecoverableErrorReason reason) {
2094  DCHECK(!HasUnrecoverableError());
2095  unrecoverable_error_reason_ = reason;
2096  OnUnrecoverableErrorImpl(from_here, message, delete_sync_database);
2097}
2098
2099std::string ProfileSyncService::GetEffectiveUsername() {
2100#if defined(ENABLE_MANAGED_USERS)
2101  if (ManagedUserService::ProfileIsManaged(profile_)) {
2102    DCHECK_EQ(std::string(), signin_->GetAuthenticatedUsername());
2103    return ManagedUserService::GetManagedUserPseudoEmail();
2104  }
2105#endif
2106
2107  return signin_->GetAuthenticatedUsername();
2108}
2109