• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 <stddef.h>
8 #include <map>
9 #include <ostream>
10 #include <set>
11 #include <utility>
12 
13 #include "base/basictypes.h"
14 #include "base/command_line.h"
15 #include "base/compiler_specific.h"
16 #include "base/logging.h"
17 #include "base/memory/ref_counted.h"
18 #include "base/message_loop.h"
19 #include "base/metrics/histogram.h"
20 #include "base/string16.h"
21 #include "base/stringprintf.h"
22 #include "base/task.h"
23 #include "base/threading/thread_restrictions.h"
24 #include "chrome/browser/net/gaia/token_service.h"
25 #include "chrome/browser/platform_util.h"
26 #include "chrome/browser/prefs/pref_service.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/sync/backend_migrator.h"
29 #include "chrome/browser/sync/engine/syncapi.h"
30 #include "chrome/browser/sync/glue/change_processor.h"
31 #include "chrome/browser/sync/glue/data_type_controller.h"
32 #include "chrome/browser/sync/glue/data_type_manager.h"
33 #include "chrome/browser/sync/glue/session_data_type_controller.h"
34 #include "chrome/browser/sync/js_arg_list.h"
35 #include "chrome/browser/sync/profile_sync_factory.h"
36 #include "chrome/browser/sync/signin_manager.h"
37 #include "chrome/browser/ui/browser.h"
38 #include "chrome/browser/ui/browser_list.h"
39 #include "chrome/common/chrome_switches.h"
40 #include "chrome/common/net/gaia/gaia_constants.h"
41 #include "chrome/common/pref_names.h"
42 #include "chrome/common/time_format.h"
43 #include "chrome/common/url_constants.h"
44 #include "content/common/notification_details.h"
45 #include "content/common/notification_source.h"
46 #include "content/common/notification_type.h"
47 #include "grit/generated_resources.h"
48 #include "ui/base/l10n/l10n_util.h"
49 #include "ui/gfx/native_widget_types.h"
50 
51 using browser_sync::ChangeProcessor;
52 using browser_sync::DataTypeController;
53 using browser_sync::DataTypeManager;
54 using browser_sync::SyncBackendHost;
55 using sync_api::SyncCredentials;
56 
57 typedef GoogleServiceAuthError AuthError;
58 
59 const char* ProfileSyncService::kSyncServerUrl =
60     "https://clients4.google.com/chrome-sync";
61 
62 const char* ProfileSyncService::kDevServerUrl =
63     "https://clients4.google.com/chrome-sync/dev";
64 
65 static const int kSyncClearDataTimeoutInSeconds = 60;  // 1 minute.
66 
ProfileSyncService(ProfileSyncFactory * factory,Profile * profile,const std::string & cros_user)67 ProfileSyncService::ProfileSyncService(ProfileSyncFactory* factory,
68                                        Profile* profile,
69                                        const std::string& cros_user)
70     : last_auth_error_(AuthError::None()),
71       observed_passphrase_required_(false),
72       passphrase_required_for_decryption_(false),
73       passphrase_migration_in_progress_(false),
74       factory_(factory),
75       profile_(profile),
76       cros_user_(cros_user),
77       sync_service_url_(kDevServerUrl),
78       backend_initialized_(false),
79       is_auth_in_progress_(false),
80       wizard_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
81       unrecoverable_error_detected_(false),
82       scoped_runnable_method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
83       expect_sync_configuration_aborted_(false),
84       clear_server_data_state_(CLEAR_NOT_STARTED) {
85   registrar_.Add(this,
86                  NotificationType::SYNC_DATA_TYPES_UPDATED,
87                  Source<Profile>(profile));
88 
89   // By default, dev & chromium users will go to the development servers.
90   // Dev servers have more features than standard sync servers.
91   // Chrome stable and beta builds will go to the standard sync servers.
92 #if defined(GOOGLE_CHROME_BUILD)
93   // GetVersionStringModifier hits the registry. See http://crbug.com/70380.
94   base::ThreadRestrictions::ScopedAllowIO allow_io;
95   // For stable, this is "". For dev, this is "dev". For beta, this is "beta".
96   // For daily, this is "canary build".
97   // For Linux Chromium builds, this could be anything depending on the
98   // distribution, so always direct those users to dev server urls.
99   // If this is an official build, it will always be one of the above.
100   std::string channel = platform_util::GetVersionStringModifier();
101   if (channel.empty() || channel == "beta") {
102     sync_service_url_ = GURL(kSyncServerUrl);
103   }
104 #endif
105 
106   tried_implicit_gaia_remove_when_bug_62103_fixed_ = false;
107 }
108 
~ProfileSyncService()109 ProfileSyncService::~ProfileSyncService() {
110   Shutdown(false);
111 }
112 
AreCredentialsAvailable()113 bool ProfileSyncService::AreCredentialsAvailable() {
114   if (IsManaged()) {
115     return false;
116   }
117 
118   // CrOS user is always logged in. Chrome uses signin_ to check logged in.
119   if (!cros_user_.empty() || !signin_->GetUsername().empty()) {
120     // TODO(chron): Verify CrOS unit test behavior.
121     if (profile()->GetTokenService() &&
122         profile()->GetTokenService()->HasTokenForService(
123             GaiaConstants::kSyncService)) {
124       return true;
125     }
126   }
127   return false;
128 }
129 
Initialize()130 void ProfileSyncService::Initialize() {
131   InitSettings();
132   RegisterPreferences();
133 
134   // Watch the preference that indicates sync is managed so we can take
135   // appropriate action.
136   pref_sync_managed_.Init(prefs::kSyncManaged, profile_->GetPrefs(), this);
137 
138   // For now, the only thing we can do through policy is to turn sync off.
139   if (IsManaged()) {
140     DisableForUser();
141     return;
142   }
143 
144   RegisterAuthNotifications();
145 
146   // In Chrome, we integrate a SigninManager which works with the sync
147   // setup wizard to kick off the TokenService. CrOS does its own plumbing
148   // for the TokenService.
149   if (cros_user_.empty()) {
150     // Will load tokens from DB and broadcast Token events after.
151     // Note: We rely on signin_ != NULL unless !cros_user_.empty().
152     signin_.reset(new SigninManager());
153     signin_->Initialize(profile_);
154   }
155 
156   if (!HasSyncSetupCompleted()) {
157     DisableForUser();  // Clean up in case of previous crash / setup abort.
158 
159     // Under ChromeOS, just autostart it anyway if creds are here and start
160     // is not being suppressed by preferences.
161     if (!cros_user_.empty() &&
162         !profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart) &&
163         AreCredentialsAvailable()) {
164       StartUp();
165     }
166   } else if (AreCredentialsAvailable()) {
167     // If we have credentials and sync setup finished, autostart the backend.
168     // Note that if we haven't finished setting up sync, backend bring up will
169     // be done by the wizard.
170     StartUp();
171   }
172 }
173 
RegisterAuthNotifications()174 void ProfileSyncService::RegisterAuthNotifications() {
175   registrar_.Add(this,
176                  NotificationType::TOKEN_AVAILABLE,
177                  Source<TokenService>(profile_->GetTokenService()));
178   registrar_.Add(this,
179                  NotificationType::TOKEN_LOADING_FINISHED,
180                  Source<TokenService>(profile_->GetTokenService()));
181   registrar_.Add(this,
182                  NotificationType::GOOGLE_SIGNIN_SUCCESSFUL,
183                  Source<Profile>(profile_));
184   registrar_.Add(this,
185                  NotificationType::GOOGLE_SIGNIN_FAILED,
186                  Source<Profile>(profile_));
187 }
188 
RegisterDataTypeController(DataTypeController * data_type_controller)189 void ProfileSyncService::RegisterDataTypeController(
190     DataTypeController* data_type_controller) {
191   DCHECK_EQ(data_type_controllers_.count(data_type_controller->type()), 0U);
192   data_type_controllers_[data_type_controller->type()] =
193       data_type_controller;
194 }
195 
196 browser_sync::SessionModelAssociator*
GetSessionModelAssociator()197     ProfileSyncService::GetSessionModelAssociator() {
198   if (data_type_controllers_.find(syncable::SESSIONS) ==
199       data_type_controllers_.end() ||
200       data_type_controllers_.find(syncable::SESSIONS)->second->state() !=
201       DataTypeController::RUNNING) {
202     return NULL;
203   }
204   return static_cast<browser_sync::SessionDataTypeController*>(
205       data_type_controllers_.find(
206       syncable::SESSIONS)->second.get())->GetModelAssociator();
207 }
208 
ResetClearServerDataState()209 void ProfileSyncService::ResetClearServerDataState() {
210   clear_server_data_state_ = CLEAR_NOT_STARTED;
211 }
212 
213 ProfileSyncService::ClearServerDataState
GetClearServerDataState()214     ProfileSyncService::GetClearServerDataState() {
215   return clear_server_data_state_;
216 }
217 
GetDataTypeControllerStates(browser_sync::DataTypeController::StateMap * state_map) const218 void ProfileSyncService::GetDataTypeControllerStates(
219   browser_sync::DataTypeController::StateMap* state_map) const {
220     for (browser_sync::DataTypeController::TypeMap::const_iterator iter =
221          data_type_controllers_.begin(); iter != data_type_controllers_.end();
222          ++iter)
223       (*state_map)[iter->first] = iter->second.get()->state();
224 }
225 
InitSettings()226 void ProfileSyncService::InitSettings() {
227   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
228 
229   // Override the sync server URL from the command-line, if sync server
230   // command-line argument exists.
231   if (command_line.HasSwitch(switches::kSyncServiceURL)) {
232     std::string value(command_line.GetSwitchValueASCII(
233         switches::kSyncServiceURL));
234     if (!value.empty()) {
235       GURL custom_sync_url(value);
236       if (custom_sync_url.is_valid()) {
237         sync_service_url_ = custom_sync_url;
238       } else {
239         LOG(WARNING) << "The following sync URL specified at the command-line "
240                      << "is invalid: " << value;
241       }
242     }
243   }
244 }
245 
RegisterPreferences()246 void ProfileSyncService::RegisterPreferences() {
247   PrefService* pref_service = profile_->GetPrefs();
248   if (pref_service->FindPreference(prefs::kSyncLastSyncedTime))
249     return;
250   pref_service->RegisterInt64Pref(prefs::kSyncLastSyncedTime, 0);
251   pref_service->RegisterBooleanPref(prefs::kSyncHasSetupCompleted, false);
252   pref_service->RegisterBooleanPref(prefs::kSyncSuppressStart, false);
253 
254   // If you've never synced before, or if you're using Chrome OS, all datatypes
255   // are on by default.
256   // TODO(nick): Perhaps a better model would be to always default to false,
257   // and explicitly call SetDataTypes() when the user shows the wizard.
258 #if defined(OS_CHROMEOS)
259   bool enable_by_default = true;
260 #else
261   bool enable_by_default =
262       !pref_service->HasPrefPath(prefs::kSyncHasSetupCompleted);
263 #endif
264 
265   pref_service->RegisterBooleanPref(prefs::kSyncBookmarks, true);
266   pref_service->RegisterBooleanPref(prefs::kSyncPasswords, enable_by_default);
267   pref_service->RegisterBooleanPref(prefs::kSyncPreferences, enable_by_default);
268   pref_service->RegisterBooleanPref(prefs::kSyncAutofill, enable_by_default);
269   pref_service->RegisterBooleanPref(prefs::kSyncThemes, enable_by_default);
270   pref_service->RegisterBooleanPref(prefs::kSyncTypedUrls, enable_by_default);
271   pref_service->RegisterBooleanPref(prefs::kSyncExtensions, enable_by_default);
272   pref_service->RegisterBooleanPref(prefs::kSyncApps, enable_by_default);
273   pref_service->RegisterBooleanPref(prefs::kSyncSessions, enable_by_default);
274   pref_service->RegisterBooleanPref(prefs::kKeepEverythingSynced,
275       enable_by_default);
276   pref_service->RegisterBooleanPref(prefs::kSyncManaged, false);
277   pref_service->RegisterStringPref(prefs::kEncryptionBootstrapToken, "");
278 
279   pref_service->RegisterBooleanPref(prefs::kSyncAutofillProfile,
280       enable_by_default);
281 }
282 
ClearPreferences()283 void ProfileSyncService::ClearPreferences() {
284   PrefService* pref_service = profile_->GetPrefs();
285   pref_service->ClearPref(prefs::kSyncLastSyncedTime);
286   pref_service->ClearPref(prefs::kSyncHasSetupCompleted);
287   pref_service->ClearPref(prefs::kEncryptionBootstrapToken);
288 
289   // TODO(nick): The current behavior does not clear e.g. prefs::kSyncBookmarks.
290   // Is that really what we want?
291   pref_service->ScheduleSavePersistentPrefs();
292 }
293 
GetCredentials()294 SyncCredentials ProfileSyncService::GetCredentials() {
295   SyncCredentials credentials;
296   credentials.email = !cros_user_.empty() ? cros_user_ : signin_->GetUsername();
297   DCHECK(!credentials.email.empty());
298   TokenService* service = profile_->GetTokenService();
299   credentials.sync_token = service->GetTokenForService(
300       GaiaConstants::kSyncService);
301   return credentials;
302 }
303 
InitializeBackend(bool delete_sync_data_folder)304 void ProfileSyncService::InitializeBackend(bool delete_sync_data_folder) {
305   if (!backend_.get()) {
306     NOTREACHED();
307     return;
308   }
309 
310   syncable::ModelTypeSet types;
311   // If sync setup hasn't finished, we don't want to initialize routing info
312   // for any data types so that we don't download updates for types that the
313   // user chooses not to sync on the first DownloadUpdatesCommand.
314   if (HasSyncSetupCompleted()) {
315     GetPreferredDataTypes(&types);
316   }
317 
318   SyncCredentials credentials = GetCredentials();
319 
320   backend_->Initialize(this,
321                        sync_service_url_,
322                        types,
323                        profile_->GetRequestContext(),
324                        credentials,
325                        delete_sync_data_folder);
326 }
327 
CreateBackend()328 void ProfileSyncService::CreateBackend() {
329   backend_.reset(new SyncBackendHost(profile_));
330 }
331 
IsEncryptedDatatypeEnabled() const332 bool ProfileSyncService::IsEncryptedDatatypeEnabled() const {
333   return !encrypted_types_.empty();
334 }
335 
StartUp()336 void ProfileSyncService::StartUp() {
337   // Don't start up multiple times.
338   if (backend_.get()) {
339     VLOG(1) << "Skipping bringing up backend host.";
340     return;
341   }
342 
343   DCHECK(AreCredentialsAvailable());
344 
345   last_synced_time_ = base::Time::FromInternalValue(
346       profile_->GetPrefs()->GetInt64(prefs::kSyncLastSyncedTime));
347 
348   CreateBackend();
349 
350   // Initialize the backend.  Every time we start up a new SyncBackendHost,
351   // we'll want to start from a fresh SyncDB, so delete any old one that might
352   // be there.
353   InitializeBackend(!HasSyncSetupCompleted());
354 }
355 
Shutdown(bool sync_disabled)356 void ProfileSyncService::Shutdown(bool sync_disabled) {
357   // Stop all data type controllers, if needed.
358   if (data_type_manager_.get()) {
359     if (data_type_manager_->state() != DataTypeManager::STOPPED) {
360       data_type_manager_->Stop();
361     }
362 
363     registrar_.Remove(this,
364                       NotificationType::SYNC_CONFIGURE_START,
365                       Source<DataTypeManager>(data_type_manager_.get()));
366     registrar_.Remove(this,
367                       NotificationType::SYNC_CONFIGURE_DONE,
368                       Source<DataTypeManager>(data_type_manager_.get()));
369     data_type_manager_.reset();
370   }
371 
372   js_event_handlers_.RemoveBackend();
373 
374   // Move aside the backend so nobody else tries to use it while we are
375   // shutting it down.
376   scoped_ptr<SyncBackendHost> doomed_backend(backend_.release());
377   if (doomed_backend.get()) {
378     doomed_backend->Shutdown(sync_disabled);
379 
380     doomed_backend.reset();
381   }
382 
383   // Clear various flags.
384   is_auth_in_progress_ = false;
385   backend_initialized_ = false;
386   observed_passphrase_required_ = false;
387   last_attempted_user_email_.clear();
388   last_auth_error_ = GoogleServiceAuthError::None();
389 }
390 
ClearServerData()391 void ProfileSyncService::ClearServerData() {
392   clear_server_data_state_ = CLEAR_CLEARING;
393   clear_server_data_timer_.Start(
394       base::TimeDelta::FromSeconds(kSyncClearDataTimeoutInSeconds), this,
395       &ProfileSyncService::OnClearServerDataTimeout);
396   backend_->RequestClearServerData();
397 }
398 
DisableForUser()399 void ProfileSyncService::DisableForUser() {
400   // Clear prefs (including SyncSetupHasCompleted) before shutting down so
401   // PSS clients don't think we're set up while we're shutting down.
402   ClearPreferences();
403   Shutdown(true);
404 
405   if (signin_.get()) {
406     signin_->SignOut();
407   }
408 
409   NotifyObservers();
410 }
411 
HasSyncSetupCompleted() const412 bool ProfileSyncService::HasSyncSetupCompleted() const {
413   return profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted);
414 }
415 
SetSyncSetupCompleted()416 void ProfileSyncService::SetSyncSetupCompleted() {
417   PrefService* prefs = profile()->GetPrefs();
418   prefs->SetBoolean(prefs::kSyncHasSetupCompleted, true);
419   prefs->SetBoolean(prefs::kSyncSuppressStart, false);
420 
421   prefs->ScheduleSavePersistentPrefs();
422 }
423 
UpdateLastSyncedTime()424 void ProfileSyncService::UpdateLastSyncedTime() {
425   last_synced_time_ = base::Time::Now();
426   profile_->GetPrefs()->SetInt64(prefs::kSyncLastSyncedTime,
427       last_synced_time_.ToInternalValue());
428   profile_->GetPrefs()->ScheduleSavePersistentPrefs();
429 }
430 
NotifyObservers()431 void ProfileSyncService::NotifyObservers() {
432   FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
433   // TODO(akalin): Make an Observer subclass that listens and does the
434   // event routing.
435   js_event_handlers_.RouteJsEvent(
436       "onSyncServiceStateChanged", browser_sync::JsArgList(), NULL);
437 }
438 
439 // static
GetPrefNameForDataType(syncable::ModelType data_type)440 const char* ProfileSyncService::GetPrefNameForDataType(
441     syncable::ModelType data_type) {
442   switch (data_type) {
443     case syncable::BOOKMARKS:
444       return prefs::kSyncBookmarks;
445     case syncable::PASSWORDS:
446       return prefs::kSyncPasswords;
447     case syncable::PREFERENCES:
448       return prefs::kSyncPreferences;
449     case syncable::AUTOFILL:
450       return prefs::kSyncAutofill;
451     case syncable::AUTOFILL_PROFILE:
452       return prefs::kSyncAutofillProfile;
453     case syncable::THEMES:
454       return prefs::kSyncThemes;
455     case syncable::TYPED_URLS:
456       return prefs::kSyncTypedUrls;
457     case syncable::EXTENSIONS:
458       return prefs::kSyncExtensions;
459     case syncable::APPS:
460       return prefs::kSyncApps;
461     case syncable::SESSIONS:
462       return prefs::kSyncSessions;
463     default:
464       break;
465   }
466   NOTREACHED();
467   return NULL;
468 }
469 
470 // An invariant has been violated.  Transition to an error state where we try
471 // to do as little work as possible, to avoid further corruption or crashes.
OnUnrecoverableError(const tracked_objects::Location & from_here,const std::string & message)472 void ProfileSyncService::OnUnrecoverableError(
473     const tracked_objects::Location& from_here,
474     const std::string& message) {
475   unrecoverable_error_detected_ = true;
476   unrecoverable_error_message_ = message;
477   unrecoverable_error_location_.reset(
478       new tracked_objects::Location(from_here.function_name(),
479                                     from_here.file_name(),
480                                     from_here.line_number()));
481 
482   // Tell the wizard so it can inform the user only if it is already open.
483   wizard_.Step(SyncSetupWizard::FATAL_ERROR);
484 
485   NotifyObservers();
486   LOG(ERROR) << "Unrecoverable error detected -- ProfileSyncService unusable."
487       << message;
488   std::string location;
489   from_here.Write(true, true, &location);
490   LOG(ERROR) << location;
491 
492   // Shut all data types down.
493   MessageLoop::current()->PostTask(FROM_HERE,
494         scoped_runnable_method_factory_.NewRunnableMethod(
495         &ProfileSyncService::Shutdown, true));
496 }
497 
OnBackendInitialized()498 void ProfileSyncService::OnBackendInitialized() {
499   backend_initialized_ = true;
500 
501   js_event_handlers_.SetBackend(backend_->GetJsBackend());
502 
503   // The very first time the backend initializes is effectively the first time
504   // we can say we successfully "synced".  last_synced_time_ will only be null
505   // in this case, because the pref wasn't restored on StartUp.
506   if (last_synced_time_.is_null()) {
507     UpdateLastSyncedTime();
508   }
509   NotifyObservers();
510 
511   if (!cros_user_.empty()) {
512     if (profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart)) {
513       ShowConfigure(NULL, true);
514     } else {
515       SetSyncSetupCompleted();
516     }
517   }
518 
519   if (HasSyncSetupCompleted()) {
520     ConfigureDataTypeManager();
521   }
522 }
523 
OnSyncCycleCompleted()524 void ProfileSyncService::OnSyncCycleCompleted() {
525   UpdateLastSyncedTime();
526   VLOG(2) << "Notifying observers sync cycle completed";
527   NotifyObservers();
528 }
529 
UpdateAuthErrorState(const GoogleServiceAuthError & error)530 void ProfileSyncService::UpdateAuthErrorState(
531     const GoogleServiceAuthError& error) {
532   last_auth_error_ = error;
533   // Protect against the in-your-face dialogs that pop out of nowhere.
534   // Require the user to click somewhere to run the setup wizard in the case
535   // of a steady-state auth failure.
536   if (WizardIsVisible()) {
537     wizard_.Step(AuthError::NONE == last_auth_error_.state() ?
538         SyncSetupWizard::GAIA_SUCCESS : SyncSetupWizard::GAIA_LOGIN);
539   } else {
540     auth_error_time_ = base::TimeTicks::Now();
541   }
542 
543   if (!auth_start_time_.is_null()) {
544     UMA_HISTOGRAM_TIMES("Sync.AuthorizationTimeInNetwork",
545                     base::TimeTicks::Now() - auth_start_time_);
546     auth_start_time_ = base::TimeTicks();
547   }
548 
549   is_auth_in_progress_ = false;
550   // Fan the notification out to interested UI-thread components.
551   NotifyObservers();
552 }
553 
OnAuthError()554 void ProfileSyncService::OnAuthError() {
555   UpdateAuthErrorState(backend_->GetAuthError());
556 }
557 
OnStopSyncingPermanently()558 void ProfileSyncService::OnStopSyncingPermanently() {
559   if (SetupInProgress()) {
560     wizard_.Step(SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR);
561     expect_sync_configuration_aborted_ = true;
562   }
563   profile_->GetPrefs()->SetBoolean(prefs::kSyncSuppressStart, true);
564   DisableForUser();
565 }
566 
OnClearServerDataTimeout()567 void ProfileSyncService::OnClearServerDataTimeout() {
568   if (clear_server_data_state_ != CLEAR_SUCCEEDED &&
569       clear_server_data_state_ != CLEAR_FAILED) {
570     clear_server_data_state_ = CLEAR_FAILED;
571     NotifyObservers();
572   }
573 }
574 
OnClearServerDataFailed()575 void ProfileSyncService::OnClearServerDataFailed() {
576   clear_server_data_timer_.Stop();
577 
578   // Only once clear has succeeded there is no longer a need to transition to
579   // a failed state as sync is disabled locally.  Also, no need to fire off
580   // the observers if the state didn't change (i.e. it was FAILED before).
581   if (clear_server_data_state_ != CLEAR_SUCCEEDED &&
582       clear_server_data_state_ != CLEAR_FAILED) {
583     clear_server_data_state_ = CLEAR_FAILED;
584     NotifyObservers();
585   }
586 }
587 
OnClearServerDataSucceeded()588 void ProfileSyncService::OnClearServerDataSucceeded() {
589   clear_server_data_timer_.Stop();
590 
591   // Even if the timout fired, we still transition to the succeeded state as
592   // we want UI to update itself and no longer allow the user to press "clear"
593   if (clear_server_data_state_ != CLEAR_SUCCEEDED) {
594     clear_server_data_state_ = CLEAR_SUCCEEDED;
595     NotifyObservers();
596   }
597 }
598 
OnPassphraseRequired(bool for_decryption)599 void ProfileSyncService::OnPassphraseRequired(bool for_decryption) {
600   DCHECK(backend_.get());
601   DCHECK(backend_->IsNigoriEnabled());
602 
603   // TODO(lipalani) : add this check to other locations as well.
604   if (unrecoverable_error_detected_) {
605     // When unrecoverable error is detected we post a task to shutdown the
606     // backend. The task might not have executed yet.
607     return;
608   }
609   observed_passphrase_required_ = true;
610   passphrase_required_for_decryption_ = for_decryption;
611 
612   // First try supplying gaia password as the passphrase.
613   if (!gaia_password_.empty()) {
614     SetPassphrase(gaia_password_, false, true);
615     gaia_password_ = std::string();
616     return;
617   }
618 
619   // If the above failed then try the custom passphrase the user might have
620   // entered in setup.
621   if (!cached_passphrase_.value.empty()) {
622     SetPassphrase(cached_passphrase_.value,
623                   cached_passphrase_.is_explicit,
624                   cached_passphrase_.is_creation);
625     cached_passphrase_ = CachedPassphrase();
626     return;
627   }
628 
629   // We will skip the passphrase prompt and suppress the warning
630   // if the passphrase is needed for decryption but the user is
631   // not syncing an encrypted data type on this machine.
632   // Otherwise we prompt.
633   if (!IsEncryptedDatatypeEnabled() && for_decryption) {
634     OnPassphraseAccepted();
635     return;
636   }
637 
638   if (WizardIsVisible() && for_decryption) {
639     wizard_.Step(SyncSetupWizard::ENTER_PASSPHRASE);
640   }
641 
642   NotifyObservers();
643 }
644 
OnPassphraseAccepted()645 void ProfileSyncService::OnPassphraseAccepted() {
646   // Make sure the data types that depend on the passphrase are started at
647   // this time.
648   syncable::ModelTypeSet types;
649   GetPreferredDataTypes(&types);
650   // Reset "passphrase_required" flag before configuring the DataTypeManager
651   // since we know we no longer require the passphrase.
652   observed_passphrase_required_ = false;
653   if (data_type_manager_.get())
654     data_type_manager_->Configure(types);
655 
656   NotifyObservers();
657 
658   wizard_.Step(SyncSetupWizard::DONE);
659 }
660 
OnEncryptionComplete(const syncable::ModelTypeSet & encrypted_types)661 void ProfileSyncService::OnEncryptionComplete(
662     const syncable::ModelTypeSet& encrypted_types) {
663   if (encrypted_types_ != encrypted_types) {
664     encrypted_types_ = encrypted_types;
665     NotifyObservers();
666   }
667 }
668 
OnMigrationNeededForTypes(const syncable::ModelTypeSet & types)669 void ProfileSyncService::OnMigrationNeededForTypes(
670     const syncable::ModelTypeSet& types) {
671   DCHECK(backend_initialized_);
672   DCHECK(data_type_manager_.get());
673 
674   // Migrator must be valid, because we don't sync until it is created and this
675   // callback originates from a sync cycle.
676   migrator_->MigrateTypes(types);
677 }
678 
ShowLoginDialog(gfx::NativeWindow parent_window)679 void ProfileSyncService::ShowLoginDialog(gfx::NativeWindow parent_window) {
680   if (WizardIsVisible()) {
681     wizard_.Focus();
682     // Force the wizard to step to the login screen (which will only actually
683     // happen if the transition is valid).
684     wizard_.Step(SyncSetupWizard::GAIA_LOGIN);
685     return;
686   }
687 
688   if (!auth_error_time_.is_null()) {
689     UMA_HISTOGRAM_LONG_TIMES("Sync.ReauthorizationTime",
690                              base::TimeTicks::Now() - auth_error_time_);
691     auth_error_time_ = base::TimeTicks();  // Reset auth_error_time_ to null.
692   }
693 
694   wizard_.Step(SyncSetupWizard::GAIA_LOGIN);
695 
696   NotifyObservers();
697 }
698 
ShowErrorUI(gfx::NativeWindow parent_window)699 void ProfileSyncService::ShowErrorUI(gfx::NativeWindow parent_window) {
700   if (observed_passphrase_required()) {
701     if (IsUsingSecondaryPassphrase())
702       PromptForExistingPassphrase(parent_window);
703     else
704       SigninForPassphraseMigration(parent_window);
705     return;
706   }
707   const GoogleServiceAuthError& error = GetAuthError();
708   if (error.state() == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
709       error.state() == GoogleServiceAuthError::CAPTCHA_REQUIRED ||
710       error.state() == GoogleServiceAuthError::ACCOUNT_DELETED ||
711       error.state() == GoogleServiceAuthError::ACCOUNT_DISABLED ||
712       error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
713     ShowLoginDialog(parent_window);
714   }
715 }
716 
717 
ShowConfigure(gfx::NativeWindow parent_window,bool sync_everything)718 void ProfileSyncService::ShowConfigure(
719     gfx::NativeWindow parent_window, bool sync_everything) {
720   if (WizardIsVisible()) {
721     wizard_.Focus();
722     return;
723   }
724 
725   if (sync_everything)
726     wizard_.Step(SyncSetupWizard::SYNC_EVERYTHING);
727   else
728     wizard_.Step(SyncSetupWizard::CONFIGURE);
729 }
730 
PromptForExistingPassphrase(gfx::NativeWindow parent_window)731 void ProfileSyncService::PromptForExistingPassphrase(
732     gfx::NativeWindow parent_window) {
733   if (WizardIsVisible()) {
734     wizard_.Focus();
735     return;
736   }
737 
738   wizard_.Step(SyncSetupWizard::ENTER_PASSPHRASE);
739 }
740 
SigninForPassphraseMigration(gfx::NativeWindow parent_window)741 void ProfileSyncService::SigninForPassphraseMigration(
742     gfx::NativeWindow parent_window) {
743   passphrase_migration_in_progress_ = true;
744   ShowLoginDialog(parent_window);
745 }
746 
QuerySyncStatusSummary()747 SyncBackendHost::StatusSummary ProfileSyncService::QuerySyncStatusSummary() {
748   if (backend_.get() && backend_initialized_)
749     return backend_->GetStatusSummary();
750   else
751     return SyncBackendHost::Status::OFFLINE_UNUSABLE;
752 }
753 
QueryDetailedSyncStatus()754 SyncBackendHost::Status ProfileSyncService::QueryDetailedSyncStatus() {
755   if (backend_.get() && backend_initialized_) {
756     return backend_->GetDetailedStatus();
757   } else {
758     SyncBackendHost::Status status =
759         { SyncBackendHost::Status::OFFLINE_UNUSABLE };
760     return status;
761   }
762 }
763 
SetupInProgress() const764 bool ProfileSyncService::SetupInProgress() const {
765   return !HasSyncSetupCompleted() && WizardIsVisible();
766 }
767 
BuildSyncStatusSummaryText(const sync_api::SyncManager::Status::Summary & summary)768 std::string ProfileSyncService::BuildSyncStatusSummaryText(
769     const sync_api::SyncManager::Status::Summary& summary) {
770   const char* strings[] = {"INVALID", "OFFLINE", "OFFLINE_UNSYNCED", "SYNCING",
771       "READY", "CONFLICT", "OFFLINE_UNUSABLE"};
772   COMPILE_ASSERT(arraysize(strings) ==
773                  sync_api::SyncManager::Status::SUMMARY_STATUS_COUNT,
774                  enum_indexed_array);
775   if (summary < 0 ||
776       summary >= sync_api::SyncManager::Status::SUMMARY_STATUS_COUNT) {
777     LOG(DFATAL) << "Illegal Summary Value: " << summary;
778     return "UNKNOWN";
779   }
780   return strings[summary];
781 }
782 
unrecoverable_error_detected() const783 bool ProfileSyncService::unrecoverable_error_detected() const {
784   return unrecoverable_error_detected_;
785 }
786 
GetLastSyncedTimeString() const787 string16 ProfileSyncService::GetLastSyncedTimeString() const {
788   if (last_synced_time_.is_null())
789     return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER);
790 
791   base::TimeDelta last_synced = base::Time::Now() - last_synced_time_;
792 
793   if (last_synced < base::TimeDelta::FromMinutes(1))
794     return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW);
795 
796   return TimeFormat::TimeElapsed(last_synced);
797 }
798 
GetAuthenticatedUsername() const799 string16 ProfileSyncService::GetAuthenticatedUsername() const {
800   if (backend_.get() && backend_initialized_)
801     return backend_->GetAuthenticatedUsername();
802   else
803     return string16();
804 }
805 
OnUserSubmittedAuth(const std::string & username,const std::string & password,const std::string & captcha,const std::string & access_code)806 void ProfileSyncService::OnUserSubmittedAuth(
807     const std::string& username, const std::string& password,
808     const std::string& captcha, const std::string& access_code) {
809   last_attempted_user_email_ = username;
810   is_auth_in_progress_ = true;
811   NotifyObservers();
812 
813   auth_start_time_ = base::TimeTicks::Now();
814 
815   if (!signin_.get()) {
816     // In ChromeOS we sign in during login, so we do not instantiate signin_.
817     // If this function gets called, we need to re-authenticate (e.g. for
818     // two factor signin), so instantiate signin_ here.
819     signin_.reset(new SigninManager());
820     signin_->Initialize(profile_);
821   }
822 
823   if (!access_code.empty()) {
824     signin_->ProvideSecondFactorAccessCode(access_code);
825     return;
826   }
827 
828   if (!signin_->GetUsername().empty()) {
829     signin_->SignOut();
830   }
831 
832   // The user has submitted credentials, which indicates they don't
833   // want to suppress start up anymore.
834   PrefService* prefs = profile_->GetPrefs();
835   prefs->SetBoolean(prefs::kSyncSuppressStart, false);
836   prefs->ScheduleSavePersistentPrefs();
837 
838   signin_->StartSignIn(username,
839                        password,
840                        last_auth_error_.captcha().token,
841                        captcha);
842 }
843 
OnUserChoseDatatypes(bool sync_everything,const syncable::ModelTypeSet & chosen_types)844 void ProfileSyncService::OnUserChoseDatatypes(bool sync_everything,
845     const syncable::ModelTypeSet& chosen_types) {
846   if (!backend_.get()) {
847     NOTREACHED();
848     return;
849   }
850 
851   profile_->GetPrefs()->SetBoolean(prefs::kKeepEverythingSynced,
852       sync_everything);
853 
854   ChangePreferredDataTypes(chosen_types);
855   profile_->GetPrefs()->ScheduleSavePersistentPrefs();
856 }
857 
OnUserCancelledDialog()858 void ProfileSyncService::OnUserCancelledDialog() {
859   if (!HasSyncSetupCompleted()) {
860     // A sync dialog was aborted before authentication.
861     // Rollback.
862     expect_sync_configuration_aborted_ = true;
863     DisableForUser();
864   }
865 
866   // Though an auth could still be in progress, once the dialog is closed we
867   // don't want the UI to stay stuck in the "waiting for authentication" state
868   // as that could take forever.  We set this to false so the buttons to re-
869   // login will appear until either a) the original request finishes and
870   // succeeds, calling OnAuthError(NONE), or b) the user clicks the button,
871   // and tries to re-authenticate. (b) is a little awkward as this second
872   // request will get queued behind the first and could wind up "undoing" the
873   // good if invalid creds were provided, but it's an edge case and the user
874   // can of course get themselves out of it.
875   is_auth_in_progress_ = false;
876   NotifyObservers();
877 }
878 
ChangePreferredDataTypes(const syncable::ModelTypeSet & preferred_types)879 void ProfileSyncService::ChangePreferredDataTypes(
880     const syncable::ModelTypeSet& preferred_types) {
881 
882   // Filter out any datatypes which aren't registered, or for which
883   // the preference can't be set.
884   syncable::ModelTypeSet registered_types;
885   GetRegisteredDataTypes(&registered_types);
886   for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
887     syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
888     if (!registered_types.count(model_type))
889       continue;
890     const char* pref_name = GetPrefNameForDataType(model_type);
891     if (!pref_name)
892       continue;
893     profile_->GetPrefs()->SetBoolean(pref_name,
894         preferred_types.count(model_type) != 0);
895     if (syncable::AUTOFILL == model_type) {
896       profile_->GetPrefs()->SetBoolean(prefs::kSyncAutofillProfile,
897           preferred_types.count(model_type) != 0);
898     }
899   }
900 
901   // If we haven't initialized yet, don't configure the DTM as it could cause
902   // association to start before a Directory has even been created.
903   if (backend_initialized_)
904     ConfigureDataTypeManager();
905 }
906 
GetPreferredDataTypes(syncable::ModelTypeSet * preferred_types) const907 void ProfileSyncService::GetPreferredDataTypes(
908     syncable::ModelTypeSet* preferred_types) const {
909   preferred_types->clear();
910   if (profile_->GetPrefs()->GetBoolean(prefs::kKeepEverythingSynced)) {
911     GetRegisteredDataTypes(preferred_types);
912   } else {
913     // Filter out any datatypes which aren't registered, or for which
914     // the preference can't be read.
915     syncable::ModelTypeSet registered_types;
916     GetRegisteredDataTypes(&registered_types);
917     for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
918       syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
919       if (!registered_types.count(model_type))
920         continue;
921       if (model_type == syncable::AUTOFILL_PROFILE)
922         continue;
923       const char* pref_name = GetPrefNameForDataType(model_type);
924       if (!pref_name)
925         continue;
926 
927       // We are trying to group autofill_profile tag with the same
928       // enabled/disabled state as autofill. Because the UI only shows autofill.
929       if (profile_->GetPrefs()->GetBoolean(pref_name)) {
930         preferred_types->insert(model_type);
931         if (model_type == syncable::AUTOFILL) {
932           if (!registered_types.count(syncable::AUTOFILL_PROFILE))
933             continue;
934           preferred_types->insert(syncable::AUTOFILL_PROFILE);
935         }
936       }
937     }
938   }
939 }
940 
GetRegisteredDataTypes(syncable::ModelTypeSet * registered_types) const941 void ProfileSyncService::GetRegisteredDataTypes(
942     syncable::ModelTypeSet* registered_types) const {
943   registered_types->clear();
944   // The data_type_controllers_ are determined by command-line flags; that's
945   // effectively what controls the values returned here.
946   for (DataTypeController::TypeMap::const_iterator it =
947        data_type_controllers_.begin();
948        it != data_type_controllers_.end(); ++it) {
949     registered_types->insert((*it).first);
950   }
951 }
952 
IsUsingSecondaryPassphrase() const953 bool ProfileSyncService::IsUsingSecondaryPassphrase() const {
954   return backend_.get() && (backend_->IsUsingExplicitPassphrase() ||
955       (tried_implicit_gaia_remove_when_bug_62103_fixed_ &&
956        observed_passphrase_required_));
957 }
958 
IsCryptographerReady(const sync_api::BaseTransaction * trans) const959 bool ProfileSyncService::IsCryptographerReady(
960     const sync_api::BaseTransaction* trans) const {
961   return backend_.get() && backend_->IsCryptographerReady(trans);
962 }
963 
GetBackendForTest()964 SyncBackendHost* ProfileSyncService::GetBackendForTest() {
965   // We don't check |backend_initialized_|; we assume the test class
966   // knows what it's doing.
967   return backend_.get();
968 }
969 
ConfigureDataTypeManager()970 void ProfileSyncService::ConfigureDataTypeManager() {
971   if (!data_type_manager_.get()) {
972     data_type_manager_.reset(
973         factory_->CreateDataTypeManager(backend_.get(),
974                                         data_type_controllers_));
975     registrar_.Add(this,
976                    NotificationType::SYNC_CONFIGURE_START,
977                    Source<DataTypeManager>(data_type_manager_.get()));
978     registrar_.Add(this,
979                    NotificationType::SYNC_CONFIGURE_DONE,
980                    Source<DataTypeManager>(data_type_manager_.get()));
981 
982     // We create the migrator at the same time.
983     migrator_.reset(
984         new browser_sync::BackendMigrator(this, data_type_manager_.get()));
985   }
986 
987   syncable::ModelTypeSet types;
988   GetPreferredDataTypes(&types);
989   // We set this special case here since it's the only datatype whose encryption
990   // status we already know. All others are set after the initial sync
991   // completes (for now).
992   // TODO(zea): Implement a better way that uses preferences for which types
993   // need encryption.
994   encrypted_types_.clear();
995   if (types.count(syncable::PASSWORDS) > 0)
996     encrypted_types_.insert(syncable::PASSWORDS);
997   if (observed_passphrase_required_ && passphrase_required_for_decryption_) {
998     if (IsEncryptedDatatypeEnabled()) {
999       // We need a passphrase still. Prompt the user for a passphrase, and
1000       // DataTypeManager::Configure() will get called once the passphrase is
1001       // accepted.
1002       OnPassphraseRequired(true);
1003       return;
1004     } else {
1005       // We've been informed that a passphrase is required for decryption, but
1006       // now there are no encrypted data types enabled, so clear the flag
1007       // (NotifyObservers() will be called when configuration completes).
1008       observed_passphrase_required_ = false;
1009     }
1010   }
1011   data_type_manager_->Configure(types);
1012 }
1013 
GetUserShare() const1014 sync_api::UserShare* ProfileSyncService::GetUserShare() const {
1015   if (backend_.get() && backend_initialized_) {
1016     return backend_->GetUserShare();
1017   }
1018   NOTREACHED();
1019   return NULL;
1020 }
1021 
1022 const browser_sync::sessions::SyncSessionSnapshot*
GetLastSessionSnapshot() const1023     ProfileSyncService::GetLastSessionSnapshot() const {
1024   if (backend_.get() && backend_initialized_) {
1025     return backend_->GetLastSessionSnapshot();
1026   }
1027   NOTREACHED();
1028   return NULL;
1029 }
1030 
HasUnsyncedItems() const1031 bool ProfileSyncService::HasUnsyncedItems() const {
1032   if (backend_.get() && backend_initialized_) {
1033     return backend_->HasUnsyncedItems();
1034   }
1035   NOTREACHED();
1036   return false;
1037 }
1038 
GetModelSafeRoutingInfo(browser_sync::ModelSafeRoutingInfo * out)1039 void ProfileSyncService::GetModelSafeRoutingInfo(
1040     browser_sync::ModelSafeRoutingInfo* out) {
1041   if (backend_.get() && backend_initialized_) {
1042     backend_->GetModelSafeRoutingInfo(out);
1043   } else {
1044     NOTREACHED();
1045   }
1046 }
1047 
1048 syncable::AutofillMigrationState
GetAutofillMigrationState()1049     ProfileSyncService::GetAutofillMigrationState() {
1050   if (backend_.get() && backend_initialized_) {
1051     return backend_->GetAutofillMigrationState();
1052   }
1053   NOTREACHED();
1054   return syncable::NOT_DETERMINED;
1055 }
1056 
SetAutofillMigrationState(syncable::AutofillMigrationState state)1057 void ProfileSyncService::SetAutofillMigrationState(
1058     syncable::AutofillMigrationState state) {
1059   if (backend_.get() && backend_initialized_) {
1060     backend_->SetAutofillMigrationState(state);
1061   } else {
1062     NOTREACHED();
1063   }
1064 }
1065 
1066 syncable::AutofillMigrationDebugInfo
GetAutofillMigrationDebugInfo()1067     ProfileSyncService::GetAutofillMigrationDebugInfo() {
1068   if (backend_.get() && backend_initialized_) {
1069     return backend_->GetAutofillMigrationDebugInfo();
1070   }
1071   NOTREACHED();
1072   syncable::AutofillMigrationDebugInfo debug_info = { 0 };
1073   return debug_info;
1074 }
1075 
SetAutofillMigrationDebugInfo(syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,const syncable::AutofillMigrationDebugInfo & info)1076 void ProfileSyncService::SetAutofillMigrationDebugInfo(
1077     syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
1078     const syncable::AutofillMigrationDebugInfo& info) {
1079   if (backend_.get() && backend_initialized_) {
1080     backend_->SetAutofillMigrationDebugInfo(property_to_set, info);
1081   } else {
1082     NOTREACHED();
1083   }
1084 }
1085 
ActivateDataType(DataTypeController * data_type_controller,ChangeProcessor * change_processor)1086 void ProfileSyncService::ActivateDataType(
1087     DataTypeController* data_type_controller,
1088     ChangeProcessor* change_processor) {
1089   if (!backend_.get()) {
1090     NOTREACHED();
1091     return;
1092   }
1093   DCHECK(backend_initialized_);
1094   change_processor->Start(profile(), backend_->GetUserShare());
1095   backend_->ActivateDataType(data_type_controller, change_processor);
1096 }
1097 
DeactivateDataType(DataTypeController * data_type_controller,ChangeProcessor * change_processor)1098 void ProfileSyncService::DeactivateDataType(
1099     DataTypeController* data_type_controller,
1100     ChangeProcessor* change_processor) {
1101   change_processor->Stop();
1102   if (backend_.get())
1103     backend_->DeactivateDataType(data_type_controller, change_processor);
1104 }
1105 
SetPassphrase(const std::string & passphrase,bool is_explicit,bool is_creation)1106 void ProfileSyncService::SetPassphrase(const std::string& passphrase,
1107                                        bool is_explicit,
1108                                        bool is_creation) {
1109   if (ShouldPushChanges() || observed_passphrase_required_) {
1110     backend_->SetPassphrase(passphrase, is_explicit);
1111   } else {
1112     if (is_explicit) {
1113       cached_passphrase_.value = passphrase;
1114       cached_passphrase_.is_explicit = is_explicit;
1115       cached_passphrase_.is_creation = is_creation;
1116     } else {
1117       gaia_password_ = passphrase;
1118     }
1119   }
1120 }
1121 
EncryptDataTypes(const syncable::ModelTypeSet & encrypted_types)1122 void ProfileSyncService::EncryptDataTypes(
1123     const syncable::ModelTypeSet& encrypted_types) {
1124   backend_->EncryptDataTypes(encrypted_types);
1125 }
1126 
GetEncryptedDataTypes(syncable::ModelTypeSet * encrypted_types) const1127 void ProfileSyncService::GetEncryptedDataTypes(
1128     syncable::ModelTypeSet* encrypted_types) const {
1129   *encrypted_types = encrypted_types_;
1130 }
1131 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1132 void ProfileSyncService::Observe(NotificationType type,
1133                                  const NotificationSource& source,
1134                                  const NotificationDetails& details) {
1135   switch (type.value) {
1136     case NotificationType::SYNC_CONFIGURE_START: {
1137       NotifyObservers();
1138       // TODO(sync): Maybe toast?
1139       break;
1140     }
1141     case NotificationType::SYNC_CONFIGURE_DONE: {
1142       DataTypeManager::ConfigureResultWithErrorLocation* result_with_location =
1143           Details<DataTypeManager::ConfigureResultWithErrorLocation>(
1144               details).ptr();
1145 
1146       DataTypeManager::ConfigureResult result = result_with_location->result;
1147       if (result == DataTypeManager::ABORTED &&
1148           expect_sync_configuration_aborted_) {
1149         expect_sync_configuration_aborted_ = false;
1150         return;
1151       }
1152       // Clear out the gaia password if it is already there.
1153       gaia_password_ = std::string();
1154       if (result != DataTypeManager::OK) {
1155         std::string message = StringPrintf("Sync Configuration failed with %d",
1156                                             result);
1157         OnUnrecoverableError(*(result_with_location->location), message);
1158         cached_passphrase_ = CachedPassphrase();
1159         return;
1160       }
1161 
1162       // If the user had entered a custom passphrase use it now.
1163       if (!cached_passphrase_.value.empty()) {
1164         // Don't hold on to the passphrase in raw form longer than needed.
1165         SetPassphrase(cached_passphrase_.value,
1166                       cached_passphrase_.is_explicit,
1167                       cached_passphrase_.is_creation);
1168         cached_passphrase_ = CachedPassphrase();
1169       }
1170 
1171       // We should never get in a state where we have no encrypted datatypes
1172       // enabled, and yet we still think we require a passphrase.
1173       DCHECK(!(observed_passphrase_required_ &&
1174                passphrase_required_for_decryption_ &&
1175                !IsEncryptedDatatypeEnabled()));
1176 
1177       // TODO(sync): Less wizard, more toast.
1178       wizard_.Step(SyncSetupWizard::DONE);
1179       NotifyObservers();
1180 
1181       // In the old world, this would be a no-op.  With new syncer thread,
1182       // this is the point where it is safe to switch from config-mode to
1183       // normal operation.
1184       backend_->StartSyncingWithServer();
1185       break;
1186     }
1187     case NotificationType::SYNC_DATA_TYPES_UPDATED: {
1188       if (!HasSyncSetupCompleted()) break;
1189 
1190       syncable::ModelTypeSet types;
1191       GetPreferredDataTypes(&types);
1192       OnUserChoseDatatypes(false, types);
1193       break;
1194     }
1195     case NotificationType::PREF_CHANGED: {
1196       std::string* pref_name = Details<std::string>(details).ptr();
1197       if (*pref_name == prefs::kSyncManaged) {
1198         NotifyObservers();
1199         if (*pref_sync_managed_) {
1200           DisableForUser();
1201         } else if (HasSyncSetupCompleted() && AreCredentialsAvailable()) {
1202           StartUp();
1203         }
1204       }
1205       break;
1206     }
1207     case NotificationType::GOOGLE_SIGNIN_SUCCESSFUL: {
1208       const GoogleServiceSigninSuccessDetails* successful =
1209           (Details<const GoogleServiceSigninSuccessDetails>(details).ptr());
1210       // We pass 'false' to SetPassphrase to denote that this is an implicit
1211       // request and shouldn't override an explicit one.  Thus, we either
1212       // update the implicit passphrase (idempotent if the passphrase didn't
1213       // actually change), or the user has an explicit passphrase set so this
1214       // becomes a no-op.
1215       tried_implicit_gaia_remove_when_bug_62103_fixed_ = true;
1216       SetPassphrase(successful->password, false, true);
1217 
1218       // If this signin was to initiate a passphrase migration (on the
1219       // first computer, thus not for decryption), continue the migration.
1220       if (passphrase_migration_in_progress_ &&
1221           !passphrase_required_for_decryption_) {
1222         wizard_.Step(SyncSetupWizard::PASSPHRASE_MIGRATION);
1223         passphrase_migration_in_progress_ = false;
1224       }
1225 
1226       break;
1227     }
1228     case NotificationType::GOOGLE_SIGNIN_FAILED: {
1229       GoogleServiceAuthError error =
1230           *(Details<const GoogleServiceAuthError>(details).ptr());
1231       UpdateAuthErrorState(error);
1232       break;
1233     }
1234     case NotificationType::TOKEN_AVAILABLE: {
1235       if (AreCredentialsAvailable()) {
1236         if (backend_initialized_) {
1237           backend_->UpdateCredentials(GetCredentials());
1238         }
1239 
1240         if (!profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart))
1241           StartUp();
1242       }
1243       break;
1244     }
1245     case NotificationType::TOKEN_LOADING_FINISHED: {
1246       // If not in Chrome OS, and we have a username without tokens,
1247       // the user will need to signin again, so sign out.
1248       if (cros_user_.empty() &&
1249           !signin_->GetUsername().empty() &&
1250           !AreCredentialsAvailable()) {
1251         DisableForUser();
1252       }
1253       break;
1254     }
1255     default: {
1256       NOTREACHED();
1257     }
1258   }
1259 }
1260 
AddObserver(Observer * observer)1261 void ProfileSyncService::AddObserver(Observer* observer) {
1262   observers_.AddObserver(observer);
1263 }
1264 
RemoveObserver(Observer * observer)1265 void ProfileSyncService::RemoveObserver(Observer* observer) {
1266   observers_.RemoveObserver(observer);
1267 }
1268 
HasObserver(Observer * observer) const1269 bool ProfileSyncService::HasObserver(Observer* observer) const {
1270   return observers_.HasObserver(observer);
1271 }
1272 
GetJsFrontend()1273 browser_sync::JsFrontend* ProfileSyncService::GetJsFrontend() {
1274   return &js_event_handlers_;
1275 }
1276 
SyncEvent(SyncEventCodes code)1277 void ProfileSyncService::SyncEvent(SyncEventCodes code) {
1278   UMA_HISTOGRAM_ENUMERATION("Sync.EventCodes", code, MAX_SYNC_EVENT_CODE);
1279 }
1280 
1281 // static
IsSyncEnabled()1282 bool ProfileSyncService::IsSyncEnabled() {
1283   // We have switches::kEnableSync just in case we need to change back to
1284   // sync-disabled-by-default on a platform.
1285   return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableSync);
1286 }
1287 
IsManaged()1288 bool ProfileSyncService::IsManaged() {
1289   // Some tests use ProfileSyncServiceMock which doesn't have a profile.
1290   return profile_ && profile_->GetPrefs()->GetBoolean(prefs::kSyncManaged);
1291 }
1292 
ShouldPushChanges()1293 bool ProfileSyncService::ShouldPushChanges() {
1294   // True only after all bootstrapping has succeeded: the sync backend
1295   // is initialized, all enabled data types are consistent with one
1296   // another, and no unrecoverable error has transpired.
1297   if (unrecoverable_error_detected_)
1298     return false;
1299 
1300   if (!data_type_manager_.get())
1301     return false;
1302 
1303   return data_type_manager_->state() == DataTypeManager::CONFIGURED;
1304 }
1305