Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / profile_sync_service.cc
index 0214f75..955a4b6 100644 (file)
@@ -6,8 +6,7 @@
 
 #include <cstddef>
 #include <map>
-#include <set>
-#include <utility>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
 #include "chrome/browser/net/chrome_cookie_notification_details.h"
+#include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/prefs/chrome_pref_service_factory.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/services/gcm/gcm_profile_service.h"
 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/signin/about_signin_internals_factory.h"
+#include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/sync/backend_migrator.h"
 #include "chrome/browser/sync/glue/sync_start_util.h"
 #include "chrome/browser/sync/glue/synced_device_tracker.h"
 #include "chrome/browser/sync/glue/typed_url_data_type_controller.h"
-#include "chrome/browser/sync/managed_user_signin_manager_wrapper.h"
 #include "chrome/browser/sync/profile_sync_components_factory_impl.h"
 #include "chrome/browser/sync/sessions/notification_service_sessions_router.h"
 #include "chrome/browser/sync/sessions/sessions_sync_manager.h"
+#include "chrome/browser/sync/supervised_user_signin_manager_wrapper.h"
 #include "chrome/browser/sync/sync_error_controller.h"
+#include "chrome/browser/sync/sync_type_preference_provider.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -66,6 +68,7 @@
 #include "components/gcm_driver/gcm_driver.h"
 #include "components/invalidation/invalidation_service.h"
 #include "components/invalidation/profile_invalidation_provider.h"
+#include "components/password_manager/core/browser/password_store.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/signin/core/browser/about_signin_internals.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
@@ -76,6 +79,7 @@
 #include "components/sync_driver/pref_names.h"
 #include "components/sync_driver/system_encryptor.h"
 #include "components/sync_driver/user_selectable_sync_type.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "sync/internal_api/public/http_bridge_network_resources.h"
 #include "sync/internal_api/public/network_resources.h"
 #include "sync/internal_api/public/sessions/type_debug_info_observer.h"
-#include "sync/internal_api/public/sync_core_proxy.h"
+#include "sync/internal_api/public/shutdown_reason.h"
+#include "sync/internal_api/public/sync_context_proxy.h"
 #include "sync/internal_api/public/sync_encryption_handler.h"
 #include "sync/internal_api/public/util/experiments.h"
+#include "sync/internal_api/public/util/sync_db_util.h"
 #include "sync/internal_api/public/util/sync_string_conversions.h"
 #include "sync/js/js_event_details.h"
 #include "sync/util/cryptographer.h"
 #include "sync/internal_api/public/read_transaction.h"
 #endif
 
-using browser_sync::ChangeProcessor;
-using browser_sync::DataTypeController;
-using browser_sync::DataTypeManager;
-using browser_sync::FailedDataTypesHandler;
 using browser_sync::NotificationServiceSessionsRouter;
 using browser_sync::ProfileSyncServiceStartBehavior;
 using browser_sync::SyncBackendHost;
+using sync_driver::ChangeProcessor;
+using sync_driver::DataTypeController;
+using sync_driver::DataTypeManager;
+using sync_driver::FailedDataTypesHandler;
 using syncer::ModelType;
 using syncer::ModelTypeSet;
 using syncer::JsBackend;
@@ -163,9 +169,6 @@ static const base::FilePath::CharType kSyncDataFolderName[] =
 static const base::FilePath::CharType kSyncBackupDataFolderName[] =
     FILE_PATH_LITERAL("Sync Data Backup");
 
-// Default delay in seconds to start backup/rollback backend.
-const int kBackupStartDelay = 10;
-
 namespace {
 
 void ClearBrowsingData(Profile* profile, base::Time start, base::Time end) {
@@ -174,6 +177,10 @@ void ClearBrowsingData(Profile* profile, base::Time start, base::Time end) {
       profile, start, end);
   remover->Remove(BrowsingDataRemover::REMOVE_ALL,
                   BrowsingDataHelper::ALL);
+
+  password_manager::PasswordStore* password =
+      PasswordStoreFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS);
+  password->RemoveLoginsSyncedBetween(start, end);
 }
 
 }  // anonymous namespace
@@ -186,15 +193,15 @@ bool ShouldShowActionOnUI(
 }
 
 ProfileSyncService::ProfileSyncService(
-    ProfileSyncComponentsFactory* factory,
+    scoped_ptr<ProfileSyncComponentsFactory> factory,
     Profile* profile,
-    scoped_ptr<ManagedUserSigninManagerWrapper> signin_wrapper,
+    scoped_ptr<SupervisedUserSigninManagerWrapper> signin_wrapper,
     ProfileOAuth2TokenService* oauth2_token_service,
     ProfileSyncServiceStartBehavior start_behavior)
     : OAuth2TokenService::Consumer("sync"),
       last_auth_error_(AuthError::AuthErrorNone()),
       passphrase_required_reason_(syncer::REASON_PASSPHRASE_NOT_REQUIRED),
-      factory_(factory),
+      factory_(factory.Pass()),
       profile_(profile),
       sync_prefs_(profile_->GetPrefs()),
       sync_service_url_(GetSyncServiceURL(*CommandLine::ForCurrentProcess())),
@@ -234,15 +241,19 @@ ProfileSyncService::ProfileSyncService(
                      startup_controller_weak_factory_.GetWeakPtr(),
                      ROLLBACK)),
       backend_mode_(IDLE),
-      backup_start_delay_(base::TimeDelta::FromSeconds(kBackupStartDelay)),
+      need_backup_(false),
+      backup_finished_(false),
       clear_browsing_data_(base::Bind(&ClearBrowsingData)) {
   DCHECK(profile);
   syncer::SyncableService::StartSyncFlare flare(
       sync_start_util::GetFlareForSyncableService(profile->GetPath()));
   scoped_ptr<browser_sync::LocalSessionEventRouter> router(
       new NotificationServiceSessionsRouter(profile, flare));
+
+  DCHECK(factory_.get());
+  local_device_ = factory_->CreateLocalDeviceInfoProvider();
   sessions_sync_manager_.reset(
-      new SessionsSyncManager(profile, this, router.Pass()));
+      new SessionsSyncManager(profile, local_device_.get(), router.Pass()));
 }
 
 ProfileSyncService::~ProfileSyncService() {
@@ -308,22 +319,29 @@ void ProfileSyncService::Initialize() {
   AddObserver(sync_error_controller_.get());
 #endif
 
-  startup_controller_.Reset(GetRegisteredDataTypes());
-  startup_controller_.TryStart();
-
-
+  bool running_rollback = false;
   if (browser_sync::BackupRollbackController::IsBackupEnabled()) {
-    backup_rollback_controller_.Start(backup_start_delay_);
+    // Backup is needed if user's not signed in or signed in but previous
+    // backup didn't finish, i.e. backend didn't switch from backup to sync.
+    need_backup_ = signin_->GetEffectiveUsername().empty() ||
+        sync_prefs_.GetFirstSyncTime().is_null();
+
+    // Try to resume rollback if it didn't finish in last session.
+    running_rollback = backup_rollback_controller_.StartRollback();
   } else {
+    need_backup_ = false;
+  }
+
 #if defined(ENABLE_PRE_SYNC_BACKUP)
-    profile_->GetIOTaskRunner()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(base::IgnoreResult(base::DeleteFile),
-                   profile_->GetPath().Append(kSyncBackupDataFolderName),
-                   true),
-        backup_start_delay_);
-#endif
+  if (!running_rollback && signin_->GetEffectiveUsername().empty()) {
+    CleanUpBackup();
   }
+#else
+  DCHECK(!running_rollback);
+#endif
+
+  startup_controller_.Reset(GetRegisteredDataTypes());
+  startup_controller_.TryStart();
 }
 
 void ProfileSyncService::TrySyncDatatypePrefRecovery() {
@@ -399,12 +417,10 @@ void ProfileSyncService::RegisterNonBlockingType(syncer::ModelType type) {
 
 void ProfileSyncService::InitializeNonBlockingType(
     syncer::ModelType type,
-    scoped_refptr<base::SequencedTaskRunner> task_runner,
-    base::WeakPtr<syncer::NonBlockingTypeProcessor> processor) {
-  non_blocking_data_type_manager_.InitializeTypeProcessor(
-      type,
-      task_runner,
-      processor);
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+    const base::WeakPtr<syncer::ModelTypeSyncProxyImpl>& type_sync_proxy) {
+  non_blocking_data_type_manager_.InitializeType(
+      type, task_runner, type_sync_proxy);
 }
 
 bool ProfileSyncService::IsSessionsDataTypeControllerRunning() const {
@@ -424,15 +440,14 @@ browser_sync::FaviconCache* ProfileSyncService::GetFaviconCache() {
   return sessions_sync_manager_->GetFaviconCache();
 }
 
-scoped_ptr<browser_sync::DeviceInfo>
-ProfileSyncService::GetLocalDeviceInfo() const {
-  if (HasSyncingBackend()) {
-    browser_sync::SyncedDeviceTracker* device_tracker =
-        backend_->GetSyncedDeviceTracker();
-    if (device_tracker)
-      return device_tracker->ReadLocalDeviceInfo();
-  }
-  return scoped_ptr<browser_sync::DeviceInfo>();
+browser_sync::SyncedWindowDelegatesGetter*
+ProfileSyncService::GetSyncedWindowDelegatesGetter() const {
+  return sessions_sync_manager_->GetSyncedWindowDelegatesGetter();
+}
+
+browser_sync::LocalDeviceInfoProvider*
+ProfileSyncService::GetLocalDeviceInfoProvider() {
+  return local_device_.get();
 }
 
 scoped_ptr<browser_sync::DeviceInfo>
@@ -460,17 +475,6 @@ ScopedVector<browser_sync::DeviceInfo>
   return devices.Pass();
 }
 
-std::string ProfileSyncService::GetLocalSyncCacheGUID() const {
-  if (HasSyncingBackend()) {
-    browser_sync::SyncedDeviceTracker* device_tracker =
-        backend_->GetSyncedDeviceTracker();
-    if (device_tracker) {
-      return device_tracker->cache_guid();
-    }
-  }
-  return std::string();
-}
-
 // Notifies the observer of any device info changes.
 void ProfileSyncService::AddObserverForDeviceInfoChange(
     browser_sync::SyncedDeviceTracker::Observer* observer) {
@@ -496,8 +500,8 @@ void ProfileSyncService::RemoveObserverForDeviceInfoChange(
 }
 
 void ProfileSyncService::GetDataTypeControllerStates(
-  browser_sync::DataTypeController::StateMap* state_map) const {
-    for (browser_sync::DataTypeController::TypeMap::const_iterator iter =
+  DataTypeController::StateMap* state_map) const {
+    for (DataTypeController::TypeMap::const_iterator iter =
          directory_data_type_controllers_.begin();
          iter != directory_data_type_controllers_.end();
          ++iter)
@@ -513,31 +517,26 @@ SyncCredentials ProfileSyncService::GetCredentials() {
 
     if (credentials.sync_token.empty())
       credentials.sync_token = "credentials_lost";
+
+    credentials.scope_set.insert(signin_->GetSyncScopeToUse());
   }
 
   return credentials;
 }
 
 bool ProfileSyncService::ShouldDeleteSyncFolder() {
-  if (backend_mode_ == SYNC)
-    return !HasSyncSetupCompleted();
-
-  if (backend_mode_ == BACKUP) {
-    base::Time reset_time = chrome_prefs::GetResetTime(profile_);
-
-    // Start fresh if:
-    // * It's the first time backup after user stopped syncing because backup
-    //   DB may contain items deleted by user during sync period and can cause
-    //   back-from-dead issues if user didn't choose rollback.
-    // * Settings are reset during startup because of tampering to avoid
-    //   restoring settings from backup.
-    if (!sync_prefs_.GetFirstSyncTime().is_null() ||
-        (!reset_time.is_null() && profile_->GetStartTime() <= reset_time)) {
+  switch (backend_mode_) {
+    case SYNC:
+      return !HasSyncSetupCompleted();
+    case BACKUP:
+      return true;
+    case ROLLBACK:
+      return false;
+    case IDLE:
+      NOTREACHED();
       return true;
-    }
   }
-
-  return false;
+  return true;
 }
 
 void ProfileSyncService::InitializeBackend(bool delete_stale_data) {
@@ -649,15 +648,57 @@ void ProfileSyncService::StartUpSlowBackendComponents(
     return;
   }
 
+  // Backend mode transition rules:
+  // * can transit from IDLE to any other non-IDLE mode.
+  // * forbidden to transit from SYNC to any other mode, i.e. SYNC backend must
+  //   be explicitly shut down before backup/rollback starts.
+  // * can not transit out of ROLLBACK mode until rollback is finished
+  //   (successfully or unsuccessfully).
+  // * can not transit out of BACKUP mode until backup is finished
+  //   (successfully or unsuccessfully).
+  // * if backup is needed, can only transit to SYNC if backup is finished,
+
+  if (backend_mode_ == SYNC) {
+    LOG(DFATAL) << "Shouldn't switch from mode SYNC to mode " << mode;
+    return;
+  }
+
+  if (backend_mode_ == ROLLBACK ||
+      (backend_mode_ == BACKUP && !backup_finished_)) {
+    // Wait for rollback/backup to finish before start new backend.
+    return;
+  }
+
+  if (mode == SYNC && NeedBackup() && !backup_finished_) {
+    if (backend_mode_ != BACKUP)
+      backup_rollback_controller_.StartBackup();
+    return;
+  }
+
   DVLOG(1) << "Start backend mode: " << mode;
 
-  if (backend_)
-    ShutdownImpl(browser_sync::SyncBackendHost::STOP_AND_CLAIM_THREAD);
+  if (backend_) {
+    if (mode == SYNC)
+      ShutdownImpl(syncer::SWITCH_MODE_SYNC);
+    else
+      ShutdownImpl(syncer::STOP_SYNC);
+  }
 
   backend_mode_ = mode;
 
+  if (backend_mode_ == BACKUP)
+    backup_start_time_ = base::Time::Now();
+
+  if (backend_mode_ == SYNC && !backup_start_time_.is_null()) {
+    UMA_HISTOGRAM_TIMES("first-sync-delay-by-backup",
+                        base::Time::Now() - backup_start_time_);
+    backup_start_time_ = base::Time();
+  }
+
   if (backend_mode_ == ROLLBACK)
     ClearBrowsingDataSinceFirstSync();
+  else if (backend_mode_ == SYNC)
+    CheckSyncBackupIfNeeded();
 
   base::FilePath sync_folder = backend_mode_ == SYNC ?
       base::FilePath(kSyncDataFolderName) :
@@ -787,7 +828,7 @@ void ProfileSyncService::OnRefreshTokensLoaded() {
 void ProfileSyncService::Shutdown() {
   UnregisterAuthNotifications();
 
-  ShutdownImpl(browser_sync::SyncBackendHost::STOP);
+  ShutdownImpl(syncer::BROWSER_SHUTDOWN);
   if (sync_error_controller_) {
     // Destroy the SyncErrorController when the service shuts down for good.
     RemoveObserver(sync_error_controller_.get());
@@ -798,8 +839,7 @@ void ProfileSyncService::Shutdown() {
     sync_thread_->Stop();
 }
 
-void ProfileSyncService::ShutdownImpl(
-    browser_sync::SyncBackendHost::ShutdownOption option) {
+void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason) {
   if (!backend_)
     return;
 
@@ -834,7 +874,7 @@ void ProfileSyncService::ShutdownImpl(
   // shutting it down.
   scoped_ptr<SyncBackendHost> doomed_backend(backend_.release());
   if (doomed_backend) {
-    sync_thread_ = doomed_backend->Shutdown(option);
+    sync_thread_ = doomed_backend->Shutdown(reason);
     doomed_backend.reset();
   }
   base::TimeDelta shutdown_time = base::Time::Now() - shutdown_start_time;
@@ -845,6 +885,20 @@ void ProfileSyncService::ShutdownImpl(
   if (backend_mode_ == SYNC)
     startup_controller_.Reset(GetRegisteredDataTypes());
 
+  // Don't let backup block sync regardless backup succeeded or not.
+  if (backend_mode_ == BACKUP)
+    backup_finished_ = true;
+
+  // Sync could be blocked by rollback/backup. Post task to check whether sync
+  // should start after shutting down rollback/backup backend.
+  if ((backend_mode_ == ROLLBACK || backend_mode_ == BACKUP) &&
+      reason != syncer::SWITCH_MODE_SYNC &&
+      reason != syncer::BROWSER_SHUTDOWN) {
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE, base::Bind(&ProfileSyncService::TryStartSyncAfterBackup,
+                              startup_controller_weak_factory_.GetWeakPtr()));
+  }
+
   // Clear various flags.
   backend_mode_ = IDLE;
   expect_sync_configuration_aborted_ = false;
@@ -869,7 +923,7 @@ void ProfileSyncService::DisableForUser() {
   // PSS clients don't think we're set up while we're shutting down.
   sync_prefs_.ClearPreferences();
   ClearUnrecoverableError();
-  ShutdownImpl(browser_sync::SyncBackendHost::DISABLE_AND_CLAIM_THREAD);
+  ShutdownImpl(syncer::DISABLE_SYNC);
 }
 
 bool ProfileSyncService::HasSyncSetupCompleted() const {
@@ -948,34 +1002,7 @@ void ProfileSyncService::OnUnrecoverableErrorImpl(
       base::Bind(&ProfileSyncService::ShutdownImpl,
                  weak_factory_.GetWeakPtr(),
                  delete_sync_database ?
-                     browser_sync::SyncBackendHost::DISABLE_AND_CLAIM_THREAD :
-                     browser_sync::SyncBackendHost::STOP_AND_CLAIM_THREAD));
-}
-
-// TODO(zea): Move this logic into the DataTypeController/DataTypeManager.
-void ProfileSyncService::DisableDatatype(
-    syncer::ModelType type,
-    const tracked_objects::Location& from_here,
-    std::string message) {
-  // First deactivate the type so that no further server changes are
-  // passed onto the change processor.
-  DeactivateDataType(type);
-
-  syncer::SyncError error(from_here,
-                          syncer::SyncError::DATATYPE_ERROR,
-                          message,
-                          type);
-
-  std::map<syncer::ModelType, syncer::SyncError> errors;
-  errors[type] = error;
-
-  // Update this before posting a task. So if a configure happens before
-  // the task that we are going to post, this type would still be disabled.
-  failed_data_types_handler_.UpdateFailedDataTypes(errors);
-
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-      base::Bind(&ProfileSyncService::ReconfigureDatatypeManager,
-                 weak_factory_.GetWeakPtr()));
+                     syncer::DISABLE_SYNC : syncer::STOP_SYNC));
 }
 
 void ProfileSyncService::ReenableDatatype(syncer::ModelType type) {
@@ -1022,12 +1049,19 @@ void ProfileSyncService::PostBackendInitialization() {
   // Never get here for backup / restore.
   DCHECK_EQ(backend_mode_, SYNC);
 
+  if (last_backup_time_) {
+    browser_sync::SyncedDeviceTracker* device_tracker =
+        backend_->GetSyncedDeviceTracker();
+    if (device_tracker)
+      device_tracker->UpdateLocalDeviceBackupTime(*last_backup_time_);
+  }
+
   if (protocol_event_observers_.might_have_observers()) {
     backend_->RequestBufferedProtocolEventsAndEnableForwarding();
   }
 
   non_blocking_data_type_manager_.ConnectSyncBackend(
-      backend_->GetSyncCoreProxy());
+      backend_->GetSyncContextProxy());
 
   if (type_debug_info_observers_.might_have_observers()) {
     backend_->EnableDirectoryTypeDebugInfoForwarding();
@@ -1068,6 +1102,7 @@ void ProfileSyncService::OnBackendInitialized(
     const syncer::WeakHandle<syncer::JsBackend>& js_backend,
     const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
         debug_info_listener,
+    const std::string& cache_guid,
     bool success) {
   UpdateBackendInitUMA(success);
 
@@ -1096,6 +1131,15 @@ void ProfileSyncService::OnBackendInitialized(
   sync_js_controller_.AttachJsBackend(js_backend);
   debug_info_listener_ = debug_info_listener;
 
+  SigninClient* signin_client =
+      ChromeSigninClientFactory::GetForProfile(profile_);
+  DCHECK(signin_client);
+  std::string signin_scoped_device_id =
+      signin_client->GetSigninScopedDeviceId();
+
+  // Initialize local device info.
+  local_device_->Initialize(cache_guid, signin_scoped_device_id);
+
   // Give the DataTypeControllers a handle to the now initialized backend
   // as a UserShare.
   for (DataTypeController::TypeMap::iterator it =
@@ -1371,9 +1415,15 @@ void ProfileSyncService::OnEncryptedTypesChanged(
   // delete directives are unnecessary.
   if (GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES) &&
       encrypted_types_.Has(syncer::SESSIONS)) {
-    DisableDatatype(syncer::HISTORY_DELETE_DIRECTIVES,
-                    FROM_HERE,
-                    "Delete directives not supported with encryption.");
+    syncer::SyncError error(
+        FROM_HERE,
+        syncer::SyncError::DATATYPE_POLICY_ERROR,
+        "Delete directives not supported with encryption.",
+        syncer::HISTORY_DELETE_DIRECTIVES);
+    FailedDataTypesHandler::TypeErrorMap error_map;
+    error_map[error.model_type()] = error;
+    failed_data_types_handler_.UpdateFailedDataTypes(error_map);
+    ReconfigureDatatypeManager();
   }
 }
 
@@ -1440,39 +1490,55 @@ void ProfileSyncService::OnActionableError(const SyncProtocolError& error) {
       // Sync disabled by domain admin. we should stop syncing until next
       // restart.
       sync_disabled_by_admin_ = true;
-      ShutdownImpl(browser_sync::SyncBackendHost::DISABLE_AND_CLAIM_THREAD);
+      ShutdownImpl(syncer::DISABLE_SYNC);
       break;
     default:
       NOTREACHED();
   }
   NotifyObservers();
 
-  backup_rollback_controller_.Start(base::TimeDelta());
+  if (error.action == syncer::DISABLE_SYNC_ON_CLIENT ||
+      (error.action == syncer::DISABLE_SYNC_AND_ROLLBACK &&
+          !backup_rollback_controller_.StartRollback())) {
+    // Clean up backup data for sign-out only or when rollback is disabled.
+    CleanUpBackup();
+  } else if (error.action == syncer::ROLLBACK_DONE) {
+    // Shut down ROLLBACK backend and delete backup DB.
+    ShutdownImpl(syncer::DISABLE_SYNC);
+    sync_prefs_.ClearFirstSyncTime();
+  }
 }
 
 void ProfileSyncService::OnConfigureDone(
-    const browser_sync::DataTypeManager::ConfigureResult& result) {
-  // We should have cleared our cached passphrase before we get here (in
-  // OnBackendInitialized()).
-  DCHECK(cached_passphrase_.empty());
-
+    const DataTypeManager::ConfigureResult& result) {
   configure_status_ = result.status;
 
   if (backend_mode_ != SYNC) {
-    if (configure_status_ == DataTypeManager::OK ||
-        configure_status_ == DataTypeManager::PARTIAL_SUCCESS) {
+    if (configure_status_ == DataTypeManager::OK) {
       StartSyncingWithServer();
+
+      // Backup is done after models are associated.
+      if (backend_mode_ == BACKUP)
+        backup_finished_ = true;
+
+      // Asynchronously check whether sync needs to start.
+      base::MessageLoop::current()->PostTask(
+          FROM_HERE, base::Bind(&ProfileSyncService::TryStartSyncAfterBackup,
+                                startup_controller_weak_factory_.GetWeakPtr()));
     } else if (!expect_sync_configuration_aborted_) {
       DVLOG(1) << "Backup/rollback backend failed to configure.";
-      ShutdownImpl(browser_sync::SyncBackendHost::STOP_AND_CLAIM_THREAD);
+      ShutdownImpl(syncer::STOP_SYNC);
     }
 
     return;
   }
 
+  // We should have cleared our cached passphrase before we get here (in
+  // OnBackendInitialized()).
+  DCHECK(cached_passphrase_.empty());
+
   if (!sync_configure_start_time_.is_null()) {
-    if (result.status == DataTypeManager::OK ||
-        result.status == DataTypeManager::PARTIAL_SUCCESS) {
+    if (result.status == DataTypeManager::OK) {
       base::Time sync_configure_stop_time = base::Time::Now();
       base::TimeDelta delta = sync_configure_stop_time -
           sync_configure_start_time_;
@@ -1496,8 +1562,7 @@ void ProfileSyncService::OnConfigureDone(
   // The possible status values:
   //    ABORT - Configuration was aborted. This is not an error, if
   //            initiated by user.
-  //    OK - Everything succeeded.
-  //    PARTIAL_SUCCESS - Some datatypes failed to start.
+  //    OK - Some or all types succeeded.
   //    Everything else is an UnrecoverableError. So treat it as such.
 
   // First handle the abort case.
@@ -1509,18 +1574,18 @@ void ProfileSyncService::OnConfigureDone(
   }
 
   // Handle unrecoverable error.
-  if (configure_status_ != DataTypeManager::OK &&
-      configure_status_ != DataTypeManager::PARTIAL_SUCCESS) {
+  if (configure_status_ != DataTypeManager::OK) {
     // Something catastrophic had happened. We should only have one
     // error representing it.
-    DCHECK_EQ(result.failed_data_types.size(),
-              static_cast<unsigned int>(1));
-    syncer::SyncError error = result.failed_data_types.begin()->second;
+    syncer::SyncError error =
+        failed_data_types_handler_.GetUnrecoverableError();
     DCHECK(error.IsSet());
     std::string message =
         "Sync configuration failed with status " +
         DataTypeManager::ConfigureStatusToString(configure_status_) +
-        " during " + syncer::ModelTypeToString(error.model_type()) +
+        " caused by " +
+        syncer::ModelTypeSetToString(
+            failed_data_types_handler_.GetUnrecoverableErrorTypes()) +
         ": " + error.message();
     LOG(ERROR) << "ProfileSyncService error: " << message;
     OnInternalUnrecoverableError(error.location(),
@@ -1710,17 +1775,17 @@ void ProfileSyncService::UpdateSelectedTypesHistogram(
   // Only log the data types that are shown in the sync settings ui.
   // Note: the order of these types must match the ordering of
   // the respective types in ModelType
-const browser_sync::user_selectable_type::UserSelectableSyncType
+const sync_driver::user_selectable_type::UserSelectableSyncType
       user_selectable_types[] = {
-    browser_sync::user_selectable_type::BOOKMARKS,
-    browser_sync::user_selectable_type::PREFERENCES,
-    browser_sync::user_selectable_type::PASSWORDS,
-    browser_sync::user_selectable_type::AUTOFILL,
-    browser_sync::user_selectable_type::THEMES,
-    browser_sync::user_selectable_type::TYPED_URLS,
-    browser_sync::user_selectable_type::EXTENSIONS,
-    browser_sync::user_selectable_type::APPS,
-    browser_sync::user_selectable_type::PROXY_TABS
+    sync_driver::user_selectable_type::BOOKMARKS,
+    sync_driver::user_selectable_type::PREFERENCES,
+    sync_driver::user_selectable_type::PASSWORDS,
+    sync_driver::user_selectable_type::AUTOFILL,
+    sync_driver::user_selectable_type::THEMES,
+    sync_driver::user_selectable_type::TYPED_URLS,
+    sync_driver::user_selectable_type::EXTENSIONS,
+    sync_driver::user_selectable_type::APPS,
+    sync_driver::user_selectable_type::PROXY_TABS
   };
 
   COMPILE_ASSERT(32 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram);
@@ -1742,7 +1807,7 @@ const browser_sync::user_selectable_type::UserSelectableSyncType
         UMA_HISTOGRAM_ENUMERATION(
             "Sync.CustomSync",
             user_selectable_types[i],
-            browser_sync::user_selectable_type::SELECTABLE_DATATYPE_COUNT + 1);
+            sync_driver::user_selectable_type::SELECTABLE_DATATYPE_COUNT + 1);
       }
     }
   }
@@ -1751,7 +1816,7 @@ const browser_sync::user_selectable_type::UserSelectableSyncType
 #if defined(OS_CHROMEOS)
 void ProfileSyncService::RefreshSpareBootstrapToken(
     const std::string& passphrase) {
-  browser_sync::SystemEncryptor encryptor;
+  sync_driver::SystemEncryptor encryptor;
   syncer::Cryptographer temp_cryptographer(&encryptor);
   // The first 2 params (hostname and username) doesn't have any effect here.
   syncer::KeyParams key_params = {"localhost", "dummy", passphrase};
@@ -1779,9 +1844,14 @@ void ProfileSyncService::OnUserChoseDatatypes(
   failed_data_types_handler_.Reset();
   if (GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES) &&
       encrypted_types_.Has(syncer::SESSIONS)) {
-    DisableDatatype(syncer::HISTORY_DELETE_DIRECTIVES,
-                    FROM_HERE,
-                    "Delete directives not supported with encryption.");
+    syncer::SyncError error(
+        FROM_HERE,
+        syncer::SyncError::DATATYPE_POLICY_ERROR,
+        "Delete directives not supported with encryption.",
+        syncer::HISTORY_DELETE_DIRECTIVES);
+    FailedDataTypesHandler::TypeErrorMap error_map;
+    error_map[error.model_type()] = error;
+    failed_data_types_handler_.UpdateFailedDataTypes(error_map);
   }
   ChangePreferredDataTypes(chosen_types);
   AcknowledgeSyncedTypes();
@@ -1826,7 +1896,8 @@ ProfileSyncService::GetPreferredDirectoryDataTypes() const {
       GetRegisteredDirectoryDataTypes();
   const syncer::ModelTypeSet preferred_types =
       sync_prefs_.GetPreferredDataTypes(registered_directory_types);
-  return preferred_types;
+
+  return Union(preferred_types, GetDataTypesFromPreferenceProviders());
 }
 
 syncer::ModelTypeSet
@@ -1894,7 +1965,7 @@ void ProfileSyncService::ConfigureDataTypeManager() {
   // start syncing data until the user is done configuring encryption options,
   // etc. ReconfigureDatatypeManager() will get called again once the UI calls
   // SetSetupInProgress(false).
-  if (startup_controller_.setup_in_progress())
+  if (backend_mode_ == SYNC && startup_controller_.setup_in_progress())
     return;
 
   bool restart = false;
@@ -2026,10 +2097,22 @@ base::Value* ProfileSyncService::GetTypeStatusMap() const {
     if (error_map.find(type) != error_map.end()) {
       const syncer::SyncError &error = error_map.find(type)->second;
       DCHECK(error.IsSet());
-      std::string error_text = "Error: " + error.location().ToString() +
-          ", " + error.message();
-      type_status->SetString("status", "error");
-      type_status->SetString("value", error_text);
+      switch (error.GetSeverity()) {
+        case syncer::SyncError::SYNC_ERROR_SEVERITY_ERROR: {
+            std::string error_text = "Error: " + error.location().ToString() +
+                ", " + error.GetMessagePrefix() + error.message();
+            type_status->SetString("status", "error");
+            type_status->SetString("value", error_text);
+          }
+          break;
+        case syncer::SyncError::SYNC_ERROR_SEVERITY_INFO:
+          type_status->SetString("status", "disabled");
+          type_status->SetString("value", error.message());
+          break;
+        default:
+          NOTREACHED() << "Unexpected error severity.";
+          break;
+      }
     } else if (syncer::IsProxyType(type) && passive_types.Has(type)) {
       // Show a proxy type in "ok" state unless it is disabled by user.
       DCHECK(!throttled_types.Has(type));
@@ -2222,7 +2305,10 @@ void ProfileSyncService::GoogleSignedOut(const std::string& username) {
   sync_disabled_by_admin_ = false;
   DisableForUser();
 
-  backup_rollback_controller_.Start(base::TimeDelta());
+  if (browser_sync::BackupRollbackController::IsBackupEnabled()) {
+    need_backup_ = true;
+    backup_finished_ = false;
+  }
 }
 
 void ProfileSyncService::AddObserver(
@@ -2255,7 +2341,8 @@ void ProfileSyncService::RemoveProtocolEventObserver(
 void ProfileSyncService::AddTypeDebugInfoObserver(
     syncer::TypeDebugInfoObserver* type_debug_info_observer) {
   type_debug_info_observers_.AddObserver(type_debug_info_observer);
-  if (type_debug_info_observers_.might_have_observers() && backend_) {
+  if (type_debug_info_observers_.might_have_observers() &&
+      backend_initialized_) {
     backend_->EnableDirectoryTypeDebugInfoForwarding();
   }
 }
@@ -2263,11 +2350,31 @@ void ProfileSyncService::AddTypeDebugInfoObserver(
 void ProfileSyncService::RemoveTypeDebugInfoObserver(
     syncer::TypeDebugInfoObserver* type_debug_info_observer) {
   type_debug_info_observers_.RemoveObserver(type_debug_info_observer);
-  if (!type_debug_info_observers_.might_have_observers() && backend_) {
+  if (!type_debug_info_observers_.might_have_observers() &&
+      backend_initialized_) {
     backend_->DisableDirectoryTypeDebugInfoForwarding();
   }
 }
 
+void ProfileSyncService::AddPreferenceProvider(
+    SyncTypePreferenceProvider* provider) {
+  DCHECK(!HasPreferenceProvider(provider))
+      << "Providers may only be added once!";
+  preference_providers_.insert(provider);
+}
+
+void ProfileSyncService::RemovePreferenceProvider(
+    SyncTypePreferenceProvider* provider) {
+  DCHECK(HasPreferenceProvider(provider))
+      << "Only providers that have been added before can be removed!";
+  preference_providers_.erase(provider);
+}
+
+bool ProfileSyncService::HasPreferenceProvider(
+    SyncTypePreferenceProvider* provider) const {
+  return preference_providers_.count(provider) > 0;
+}
+
 namespace {
 
 class GetAllNodesRequestHelper
@@ -2408,7 +2515,7 @@ void ProfileSyncService::StopAndSuppress() {
   if (HasSyncingBackend()) {
     backend_->UnregisterInvalidationIds();
   }
-  ShutdownImpl(browser_sync::SyncBackendHost::STOP_AND_CLAIM_THREAD);
+  ShutdownImpl(syncer::STOP_SYNC);
 }
 
 bool ProfileSyncService::IsStartSuppressed() const {
@@ -2456,6 +2563,18 @@ void ProfileSyncService::ReconfigureDatatypeManager() {
   }
 }
 
+syncer::ModelTypeSet ProfileSyncService::GetDataTypesFromPreferenceProviders()
+    const {
+  syncer::ModelTypeSet types;
+  for (std::set<SyncTypePreferenceProvider*>::const_iterator it =
+           preference_providers_.begin();
+       it != preference_providers_.end();
+       ++it) {
+    types.PutAll((*it)->GetPreferredDataTypes());
+  }
+  return types;
+}
+
 const FailedDataTypesHandler& ProfileSyncService::failed_data_types_handler()
     const {
   return failed_data_types_handler_;
@@ -2529,17 +2648,14 @@ bool ProfileSyncService::HasSyncingBackend() const {
   return backend_mode_ != SYNC ? false : backend_ != NULL;
 }
 
-void ProfileSyncService::SetBackupStartDelayForTest(base::TimeDelta delay) {
-  backup_start_delay_ = delay;
-}
-
 void ProfileSyncService::UpdateFirstSyncTimePref() {
   if (signin_->GetEffectiveUsername().empty()) {
     // Clear if user's not signed in and rollback is done.
-    if (backend_mode_ == BACKUP)
+    if (backend_mode_ != ROLLBACK)
       sync_prefs_.ClearFirstSyncTime();
-  } else if (sync_prefs_.GetFirstSyncTime().is_null()) {
-    // Set if user is signed in and time was not set before.
+  } else if (sync_prefs_.GetFirstSyncTime().is_null() &&
+      backend_mode_ == SYNC) {
+    // Set if not set before and it's syncing now.
     sync_prefs_.SetFirstSyncTime(base::Time::Now());
   }
 }
@@ -2589,9 +2705,67 @@ GURL ProfileSyncService::GetSyncServiceURL(
   return result;
 }
 
-void ProfileSyncService::StartStopBackupForTesting() {
-  if (backend_mode_ == BACKUP)
-    ShutdownImpl(browser_sync::SyncBackendHost::STOP_AND_CLAIM_THREAD);
-  else
-    backup_rollback_controller_.Start(base::TimeDelta());
+void ProfileSyncService::CheckSyncBackupIfNeeded() {
+  DCHECK_EQ(backend_mode_, SYNC);
+
+#if defined(ENABLE_PRE_SYNC_BACKUP)
+  // Check backup once a day.
+  if (!last_backup_time_ &&
+      (last_synced_time_.is_null() ||
+          base::Time::Now() - last_synced_time_ >=
+              base::TimeDelta::FromDays(1))) {
+    // If sync thread is set, need to serialize check on sync thread after
+    // closing backup DB.
+    if (sync_thread_) {
+      sync_thread_->message_loop_proxy()->PostTask(
+          FROM_HERE,
+          base::Bind(syncer::CheckSyncDbLastModifiedTime,
+                     profile_->GetPath().Append(kSyncBackupDataFolderName),
+                     base::MessageLoopProxy::current(),
+                     base::Bind(&ProfileSyncService::CheckSyncBackupCallback,
+                                weak_factory_.GetWeakPtr())));
+    } else {
+      content::BrowserThread::PostTask(
+          content::BrowserThread::FILE, FROM_HERE,
+          base::Bind(syncer::CheckSyncDbLastModifiedTime,
+                     profile_->GetPath().Append(kSyncBackupDataFolderName),
+                     base::MessageLoopProxy::current(),
+                     base::Bind(&ProfileSyncService::CheckSyncBackupCallback,
+                                weak_factory_.GetWeakPtr())));
+    }
+  }
+#endif
+}
+
+void ProfileSyncService::CheckSyncBackupCallback(base::Time backup_time) {
+  last_backup_time_.reset(new base::Time(backup_time));
+
+  if (HasSyncingBackend() && backend_initialized_) {
+    browser_sync::SyncedDeviceTracker* device_tracker =
+        backend_->GetSyncedDeviceTracker();
+    if (device_tracker)
+      device_tracker->UpdateLocalDeviceBackupTime(*last_backup_time_);
+  }
+}
+
+void ProfileSyncService::TryStartSyncAfterBackup() {
+  startup_controller_.Reset(GetRegisteredDataTypes());
+  startup_controller_.TryStart();
+}
+
+void ProfileSyncService::CleanUpBackup() {
+  sync_prefs_.ClearFirstSyncTime();
+  profile_->GetIOTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(base::IgnoreResult(base::DeleteFile),
+                 profile_->GetPath().Append(kSyncBackupDataFolderName),
+                 true));
+}
+
+bool ProfileSyncService::NeedBackup() const {
+  return need_backup_;
+}
+
+base::Time ProfileSyncService::GetDeviceBackupTimeForTesting() const {
+  return backend_->GetSyncedDeviceTracker()->GetLocalDeviceBackupTime();
 }