#include <cstddef>
#include <map>
-#include <set>
-#include <utility>
+#include <vector>
#include "base/basictypes.h"
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/strings/string16.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "chrome/browser/bookmarks/enhanced_bookmarks_features.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browsing_data/browsing_data_helper.h"
#include "chrome/browser/chrome_notification_types.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.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.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/sync/backend_migrator.h"
-#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/chrome_report_unrecoverable_error.h"
-#include "chrome/browser/sync/glue/device_info.h"
#include "chrome/browser/sync/glue/favicon_cache.h"
-#include "chrome/browser/sync/glue/session_data_type_controller.h"
-#include "chrome/browser/sync/glue/session_model_associator.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/glue/sync_backend_host_impl.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/sessions2/notification_service_sessions_router.h"
-#include "chrome/browser/sync/sessions2/sessions_sync_manager.h"
+#include "chrome/browser/sync/sessions/notification_service_sessions_router.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"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
+#include "chrome/grit/generated_resources.h"
+#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"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/signin/core/browser/signin_metrics.h"
+#include "components/sync_driver/change_processor.h"
#include "components/sync_driver/data_type_controller.h"
+#include "components/sync_driver/device_info.h"
#include "components/sync_driver/pref_names.h"
#include "components/sync_driver/system_encryptor.h"
#include "components/sync_driver/user_selectable_sync_type.h"
-#include "components/user_prefs/pref_registry_syncable.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 "google_apis/gaia/gaia_constants.h"
-#include "grit/generated_resources.h"
#include "net/cookies/cookie_monster.h"
#include "net/url_request/url_request_context_getter.h"
#include "sync/api/sync_error.h"
#include "sync/internal_api/public/configure_reason.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/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_arg_list.h"
#include "sync/js/js_event_details.h"
#include "sync/util/cryptographer.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/time_format.h"
-#if defined(ENABLE_MANAGED_USERS)
-#include "chrome/browser/managed_mode/managed_user_constants.h"
-#endif
-
#if defined(OS_ANDROID)
#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::SessionsSyncManager;
using browser_sync::SyncBackendHost;
+using sync_driver::ChangeProcessor;
+using sync_driver::DataTypeController;
+using sync_driver::DataTypeManager;
+using sync_driver::DataTypeStatusTable;
+using sync_driver::DeviceInfoSyncService;
using syncer::ModelType;
using syncer::ModelTypeSet;
using syncer::JsBackend;
false,
};
+static const base::FilePath::CharType kSyncDataFolderName[] =
+ FILE_PATH_LITERAL("Sync Data");
+
+static const base::FilePath::CharType kSyncBackupDataFolderName[] =
+ FILE_PATH_LITERAL("Sync Data Backup");
+
+namespace {
+
+void ClearBrowsingData(BrowsingDataRemover::Observer* observer,
+ Profile* profile,
+ base::Time start,
+ base::Time end) {
+ // BrowsingDataRemover deletes itself when it's done.
+ BrowsingDataRemover* remover = BrowsingDataRemover::CreateForRange(
+ profile, start, end);
+ if (observer)
+ remover->AddObserver(observer);
+ remover->Remove(BrowsingDataRemover::REMOVE_ALL,
+ BrowsingDataHelper::ALL);
+
+ scoped_refptr<password_manager::PasswordStore> password =
+ PasswordStoreFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS);
+ password->RemoveLoginsSyncedBetween(start, end);
+}
+
+// Perform the actual sync data folder deletion.
+// This should only be called on the sync thread.
+void DeleteSyncDataFolder(const base::FilePath& directory_path) {
+ if (base::DirectoryExists(directory_path)) {
+ if (!base::DeleteFile(directory_path, true))
+ LOG(DFATAL) << "Could not delete the Sync Data folder.";
+ }
+}
+
+} // anonymous namespace
+
bool ShouldShowActionOnUI(
const syncer::SyncProtocolError& error) {
return (error.action != syncer::UNKNOWN_ACTION &&
}
ProfileSyncService::ProfileSyncService(
- ProfileSyncComponentsFactory* factory,
+ scoped_ptr<ProfileSyncComponentsFactory> factory,
Profile* profile,
- 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_(kDevServerUrl),
+ sync_service_url_(GetSyncServiceURL(*CommandLine::ForCurrentProcess())),
is_first_time_sync_configure_(false),
backend_initialized_(false),
sync_disabled_by_admin_(false),
is_auth_in_progress_(false),
- signin_(signin_wrapper),
+ signin_(signin_wrapper.Pass()),
unrecoverable_error_reason_(ERROR_REASON_UNSET),
expect_sync_configuration_aborted_(false),
encrypted_types_(syncer::SyncEncryptionHandler::SensitiveTypes()),
+ encrypt_everything_allowed_(true),
encrypt_everything_(false),
encryption_pending_(false),
configure_status_(DataTypeManager::UNKNOWN),
start_behavior,
oauth2_token_service,
&sync_prefs_,
- signin_wrapper,
+ signin_.get(),
+ base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
+ startup_controller_weak_factory_.GetWeakPtr(),
+ SYNC)),
+ backup_rollback_controller_(
+ &sync_prefs_,
+ signin_.get(),
+ base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
+ startup_controller_weak_factory_.GetWeakPtr(),
+ BACKUP),
base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
- startup_controller_weak_factory_.GetWeakPtr())) {
+ startup_controller_weak_factory_.GetWeakPtr(),
+ ROLLBACK)),
+ backend_mode_(IDLE),
+ need_backup_(false),
+ backup_finished_(false),
+ clear_browsing_data_(base::Bind(&ClearBrowsingData)),
+ browsing_data_remover_observer_(NULL) {
DCHECK(profile);
- // By default, dev, canary, and unbranded Chromium users will go to the
- // development servers. Development servers have more features than standard
- // sync servers. Users with officially-branded Chrome stable and beta builds
- // will go to the standard sync servers.
- //
- // GetChannel hits the registry on Windows. See http://crbug.com/70380.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
- if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
- channel == chrome::VersionInfo::CHANNEL_BETA) {
- sync_service_url_ = GURL(kSyncServerUrl);
- }
+ syncer::SyncableService::StartSyncFlare flare(
+ sync_start_util::GetFlareForSyncableService(profile->GetPath()));
+ scoped_ptr<browser_sync::LocalSessionEventRouter> router(
+ new NotificationServiceSessionsRouter(profile, flare));
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableSyncSessionsV2)) {
- syncer::SyncableService::StartSyncFlare flare(
- sync_start_util::GetFlareForSyncableService(profile->GetPath()));
- scoped_ptr<browser_sync::LocalSessionEventRouter> router(
- new NotificationServiceSessionsRouter(profile, flare));
- sessions_sync_manager_.reset(
- new SessionsSyncManager(profile, this, router.Pass()));
- }
+ DCHECK(factory_.get());
+ local_device_ = factory_->CreateLocalDeviceInfoProvider();
+ sessions_sync_manager_.reset(
+ new SessionsSyncManager(profile, local_device_.get(), router.Pass()));
+ device_info_sync_service_.reset(
+ new DeviceInfoSyncService(local_device_.get()));
}
ProfileSyncService::~ProfileSyncService() {
}
void ProfileSyncService::Initialize() {
- InitSettings();
-
// We clear this here (vs Shutdown) because we want to remember that an error
// happened on shutdown so we can display details (message, location) about it
// in about:sync.
TrySyncDatatypePrefRecovery();
- last_synced_time_ = sync_prefs_.GetLastSyncedTime();
-
#if defined(OS_CHROMEOS)
std::string bootstrap_token = sync_prefs_.GetEncryptionBootstrapToken();
if (bootstrap_token.empty()) {
AddObserver(sync_error_controller_.get());
#endif
+ bool running_rollback = false;
+ if (browser_sync::BackupRollbackController::IsBackupEnabled()) {
+ // 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)
+ if (!running_rollback && signin_->GetEffectiveUsername().empty()) {
+ CleanUpBackup();
+ }
+#else
+ DCHECK(!running_rollback);
+#endif
+
startup_controller_.Reset(GetRegisteredDataTypes());
startup_controller_.TryStart();
}
void ProfileSyncService::TrySyncDatatypePrefRecovery() {
- DCHECK(!sync_initialized());
+ DCHECK(!backend_initialized());
if (!HasSyncSetupCompleted())
return;
UMA_HISTOGRAM_COUNTS("Sync.DatatypePrefRecovery", 1);
sync_prefs_.SetKeepEverythingSynced(true);
syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
- sync_prefs_.SetPreferredDataTypes(registered_types,
- registered_types);
}
void ProfileSyncService::StartSyncingWithServer() {
void ProfileSyncService::RegisterDataTypeController(
DataTypeController* data_type_controller) {
- DCHECK_EQ(data_type_controllers_.count(data_type_controller->type()), 0U);
- data_type_controllers_[data_type_controller->type()] =
+ DCHECK_EQ(
+ directory_data_type_controllers_.count(data_type_controller->type()),
+ 0U);
+ DCHECK(!GetRegisteredNonBlockingDataTypes().Has(
+ data_type_controller->type()));
+ directory_data_type_controllers_[data_type_controller->type()] =
data_type_controller;
}
-browser_sync::SessionModelAssociator*
- ProfileSyncService::GetSessionModelAssociatorDeprecated() {
- if (!IsSessionsDataTypeControllerRunning())
- return NULL;
-
- // If we're using sessions V2, there's no model associator.
- if (sessions_sync_manager_.get())
- return NULL;
+void ProfileSyncService::RegisterNonBlockingType(syncer::ModelType type) {
+ DCHECK_EQ(directory_data_type_controllers_.count(type), 0U)
+ << "Duplicate registration of type " << ModelTypeToString(type);
- return static_cast<browser_sync::SessionDataTypeController*>(
- data_type_controllers_.find(
- syncer::SESSIONS)->second.get())->GetModelAssociator();
+ // TODO(rlarocque): Set the enable flag properly when crbug.com/368834 is
+ // fixed and we have some way of telling whether or not this type should be
+ // enabled.
+ non_blocking_data_type_manager_.RegisterType(type, false);
}
-bool ProfileSyncService::IsSessionsDataTypeControllerRunning() const {
- return data_type_controllers_.find(syncer::SESSIONS) !=
- data_type_controllers_.end() &&
- data_type_controllers_.find(syncer::SESSIONS)->second->state() ==
- DataTypeController::RUNNING;
+void ProfileSyncService::InitializeNonBlockingType(
+ syncer::ModelType type,
+ 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);
}
-browser_sync::OpenTabsUIDelegate* ProfileSyncService::GetOpenTabsUIDelegate() {
- if (!IsSessionsDataTypeControllerRunning())
- return NULL;
-
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableSyncSessionsV2)) {
- return sessions_sync_manager_.get();
- } else {
- return GetSessionModelAssociatorDeprecated();
+bool ProfileSyncService::IsDataTypeControllerRunning(
+ syncer::ModelType type) const {
+ DataTypeController::TypeMap::const_iterator iter =
+ directory_data_type_controllers_.find(type);
+ if (iter == directory_data_type_controllers_.end()) {
+ return false;
}
+ return iter->second->state() == DataTypeController::RUNNING;
}
-browser_sync::FaviconCache* ProfileSyncService::GetFaviconCache() {
- // TODO(tim): Clean this up (or remove) once there's only one implementation.
- // Bug 98892.
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableSyncSessionsV2)) {
- return sessions_sync_manager_->GetFaviconCache();
- } else if (GetSessionModelAssociatorDeprecated()) {
- return GetSessionModelAssociatorDeprecated()->GetFaviconCache();
- } else {
+browser_sync::OpenTabsUIDelegate* ProfileSyncService::GetOpenTabsUIDelegate() {
+ if (!IsDataTypeControllerRunning(syncer::SESSIONS))
return NULL;
- }
-}
-
-scoped_ptr<browser_sync::DeviceInfo>
-ProfileSyncService::GetLocalDeviceInfo() const {
- if (backend_) {
- browser_sync::SyncedDeviceTracker* device_tracker =
- backend_->GetSyncedDeviceTracker();
- if (device_tracker)
- return device_tracker->ReadLocalDeviceInfo();
- }
- return scoped_ptr<browser_sync::DeviceInfo>();
+ return sessions_sync_manager_.get();
}
-scoped_ptr<browser_sync::DeviceInfo>
-ProfileSyncService::GetDeviceInfo(const std::string& client_id) const {
- if (backend_) {
- browser_sync::SyncedDeviceTracker* device_tracker =
- backend_->GetSyncedDeviceTracker();
- if (device_tracker)
- return device_tracker->ReadDeviceInfo(client_id);
- }
- return scoped_ptr<browser_sync::DeviceInfo>();
+browser_sync::FaviconCache* ProfileSyncService::GetFaviconCache() {
+ return sessions_sync_manager_->GetFaviconCache();
}
-ScopedVector<browser_sync::DeviceInfo>
- ProfileSyncService::GetAllSignedInDevices() const {
- ScopedVector<browser_sync::DeviceInfo> devices;
- if (backend_) {
- browser_sync::SyncedDeviceTracker* device_tracker =
- backend_->GetSyncedDeviceTracker();
- if (device_tracker) {
- // TODO(lipalani) - Make device tracker return a scoped vector.
- device_tracker->GetAllSyncedDeviceInfo(&devices);
- }
- }
- return devices.Pass();
+browser_sync::SyncedWindowDelegatesGetter*
+ProfileSyncService::GetSyncedWindowDelegatesGetter() const {
+ return sessions_sync_manager_->GetSyncedWindowDelegatesGetter();
}
-std::string ProfileSyncService::GetLocalSyncCacheGUID() const {
- if (backend_) {
- browser_sync::SyncedDeviceTracker* device_tracker =
- backend_->GetSyncedDeviceTracker();
- if (device_tracker) {
- return device_tracker->cache_guid();
- }
- }
- return std::string();
-}
+sync_driver::DeviceInfoTracker* ProfileSyncService::GetDeviceInfoTracker()
+ const {
+ if (!IsDataTypeControllerRunning(syncer::DEVICE_INFO))
+ return NULL;
-// Notifies the observer of any device info changes.
-void ProfileSyncService::AddObserverForDeviceInfoChange(
- browser_sync::SyncedDeviceTracker::Observer* observer) {
- if (backend_) {
- browser_sync::SyncedDeviceTracker* device_tracker =
- backend_->GetSyncedDeviceTracker();
- if (device_tracker) {
- device_tracker->AddObserver(observer);
- }
- }
+ return device_info_sync_service_.get();
}
-// Removes the observer from device info change notification.
-void ProfileSyncService::RemoveObserverForDeviceInfoChange(
- browser_sync::SyncedDeviceTracker::Observer* observer) {
- if (backend_) {
- browser_sync::SyncedDeviceTracker* device_tracker =
- backend_->GetSyncedDeviceTracker();
- if (device_tracker) {
- device_tracker->RemoveObserver(observer);
- }
- }
+sync_driver::LocalDeviceInfoProvider*
+ProfileSyncService::GetLocalDeviceInfoProvider() {
+ return local_device_.get();
}
void ProfileSyncService::GetDataTypeControllerStates(
- browser_sync::DataTypeController::StateMap* state_map) const {
- for (browser_sync::DataTypeController::TypeMap::const_iterator iter =
- data_type_controllers_.begin(); iter != data_type_controllers_.end();
+ DataTypeController::StateMap* state_map) const {
+ for (DataTypeController::TypeMap::const_iterator iter =
+ directory_data_type_controllers_.begin();
+ iter != directory_data_type_controllers_.end();
++iter)
(*state_map)[iter->first] = iter->second.get()->state();
}
-void ProfileSyncService::InitSettings() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
- // Override the sync server URL from the command-line, if sync server
- // command-line argument exists.
- if (command_line.HasSwitch(switches::kSyncServiceURL)) {
- std::string value(command_line.GetSwitchValueASCII(
- switches::kSyncServiceURL));
- if (!value.empty()) {
- GURL custom_sync_url(value);
- if (custom_sync_url.is_valid()) {
- sync_service_url_ = custom_sync_url;
- } else {
- LOG(WARNING) << "The following sync URL specified at the command-line "
- << "is invalid: " << value;
- }
- }
- }
-}
-
SyncCredentials ProfileSyncService::GetCredentials() {
SyncCredentials credentials;
- credentials.email = signin_->GetEffectiveUsername();
- DCHECK(!credentials.email.empty());
- credentials.sync_token = access_token_;
+ if (backend_mode_ == SYNC) {
+ credentials.email = signin_->GetEffectiveUsername();
+ DCHECK(!credentials.email.empty());
+ credentials.sync_token = access_token_;
+
+ if (credentials.sync_token.empty())
+ credentials.sync_token = "credentials_lost";
+
+ credentials.scope_set.insert(signin_->GetSyncScopeToUse());
+ }
- if (credentials.sync_token.empty())
- credentials.sync_token = "credentials_lost";
return credentials;
}
+bool ProfileSyncService::ShouldDeleteSyncFolder() {
+ switch (backend_mode_) {
+ case SYNC:
+ return !HasSyncSetupCompleted();
+ case BACKUP:
+ return true;
+ case ROLLBACK:
+ return false;
+ case IDLE:
+ NOTREACHED();
+ return true;
+ }
+ return true;
+}
+
void ProfileSyncService::InitializeBackend(bool delete_stale_data) {
if (!backend_) {
NOTREACHED();
scoped_refptr<net::URLRequestContextGetter> request_context_getter(
profile_->GetRequestContext());
- if (delete_stale_data)
+ if (backend_mode_ == SYNC && delete_stale_data)
ClearStaleErrors();
scoped_ptr<syncer::UnrecoverableErrorHandler>
credentials,
delete_stale_data,
scoped_ptr<syncer::SyncManagerFactory>(
- new syncer::SyncManagerFactory).Pass(),
+ new syncer::SyncManagerFactory(GetManagerType())).Pass(),
backend_unrecoverable_error_handler.Pass(),
&browser_sync::ChromeReportUnrecoverableError,
network_resources_.get());
return !Intersection(preferred_types, encrypted_types).Empty();
}
-void ProfileSyncService::OnSyncConfigureRetry() {
- // Note: in order to handle auth failures that arise before the backend is
- // initialized (e.g. from invalidation notifier, or downloading new control
- // types), we have to gracefully handle configuration retries at all times.
- // At this point an auth error badge should be shown, which once resolved
- // will trigger a new sync cycle.
- NotifyObservers();
-}
-
void ProfileSyncService::OnProtocolEvent(
const syncer::ProtocolEvent& event) {
FOR_EACH_OBSERVER(browser_sync::ProtocolEventObserver,
OnProtocolEvent(event));
}
+void ProfileSyncService::OnDirectoryTypeCommitCounterUpdated(
+ syncer::ModelType type,
+ const syncer::CommitCounters& counters) {
+ FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver,
+ type_debug_info_observers_,
+ OnCommitCountersUpdated(type, counters));
+}
+
+void ProfileSyncService::OnDirectoryTypeUpdateCounterUpdated(
+ syncer::ModelType type,
+ const syncer::UpdateCounters& counters) {
+ FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver,
+ type_debug_info_observers_,
+ OnUpdateCountersUpdated(type, counters));
+}
+
+void ProfileSyncService::OnDirectoryTypeStatusCounterUpdated(
+ syncer::ModelType type,
+ const syncer::StatusCounters& counters) {
+ FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver,
+ type_debug_info_observers_,
+ OnStatusCountersUpdated(type, counters));
+}
+
void ProfileSyncService::OnDataTypeRequestsSyncStartup(
syncer::ModelType type) {
DCHECK(syncer::UserTypes().Has(type));
startup_controller_.OnDataTypeRequestsSyncStartup(type);
}
-void ProfileSyncService::StartUpSlowBackendComponents() {
- // Don't start up multiple times.
- DCHECK(!backend_);
+void ProfileSyncService::StartUpSlowBackendComponents(
+ ProfileSyncService::BackendMode mode) {
+ DCHECK_NE(IDLE, mode);
+ if (backend_mode_ == mode) {
+ return;
+ }
- DCHECK(IsSyncEnabledAndLoggedIn());
+ // 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_) {
+ 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_MEDIUM_TIMES("Sync.FirstSyncDelayByBackup",
+ 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) :
+ base::FilePath(kSyncBackupDataFolderName);
+
+ invalidation::InvalidationService* invalidator = NULL;
+ if (backend_mode_ == SYNC) {
+ invalidation::ProfileInvalidationProvider* provider =
+ invalidation::ProfileInvalidationProviderFactory::GetForProfile(
+ profile_);
+ if (provider)
+ invalidator = provider->GetInvalidationService();
+ }
+
+ directory_path_ = profile_->GetPath().Append(sync_folder);
- DCHECK(!sync_disabled_by_admin_);
backend_.reset(
factory_->CreateSyncBackendHost(
profile_->GetDebugName(),
profile_,
- sync_prefs_.AsWeakPtr()));
+ invalidator,
+ sync_prefs_.AsWeakPtr(),
+ sync_folder));
// Initialize the backend. Every time we start up a new SyncBackendHost,
// we'll want to start from a fresh SyncDB, so delete any old one that might
// be there.
- InitializeBackend(!HasSyncSetupCompleted());
+ InitializeBackend(ShouldDeleteSyncFolder());
+
+ UpdateFirstSyncTimePref();
}
void ProfileSyncService::OnGetTokenSuccess(
AUTH_ERROR_LIMIT);
}
- if (backend_)
+ if (HasSyncingBackend())
backend_->UpdateCredentials(GetCredentials());
else
startup_controller_.TryStart();
last_get_token_error_ = error;
switch (error.state()) {
case GoogleServiceAuthError::CONNECTION_FAILED:
+ case GoogleServiceAuthError::REQUEST_CANCELED:
+ case GoogleServiceAuthError::SERVICE_ERROR:
case GoogleServiceAuthError::SERVICE_UNAVAILABLE: {
// Transient error. Retry after some time.
request_access_token_backoff_.InformOfRequest(false);
NotifyObservers();
break;
}
- case GoogleServiceAuthError::SERVICE_ERROR:
case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
if (!sync_prefs_.SyncHasAuthError()) {
sync_prefs_.SetSyncAuthError(true);
// Fallthrough.
}
default: {
+ if (error.state() != GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
+ LOG(ERROR) << "Unexpected persistent error: " << error.ToString();
+ }
// Show error to user.
UpdateAuthErrorState(error);
}
void ProfileSyncService::OnRefreshTokenAvailable(
const std::string& account_id) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/422460 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "422460 ProfileSyncService::OnRefreshTokenAvailable"));
+
if (account_id == signin_->GetAccountIdToUse())
OnRefreshTokensLoaded();
}
// Initialize the backend if sync is enabled. If the sync token was
// not loaded, GetCredentials() will generate invalid credentials to
// cause the backend to generate an auth error (crbug.com/121755).
- if (backend_) {
+ if (HasSyncingBackend()) {
RequestAccessToken();
} else {
startup_controller_.TryStart();
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());
sync_thread_->Stop();
}
-void ProfileSyncService::ShutdownImpl(
- browser_sync::SyncBackendHost::ShutdownOption option) {
- if (!backend_)
+void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason) {
+ if (!backend_) {
+ if (reason == syncer::ShutdownReason::DISABLE_SYNC && sync_thread_) {
+ // If the backend is already shut down when a DISABLE_SYNC happens,
+ // the data directory needs to be cleaned up here.
+ sync_thread_->message_loop()->PostTask(FROM_HERE,
+ base::Bind(&DeleteSyncDataFolder, directory_path_));
+ }
return;
+ }
+
+ non_blocking_data_type_manager_.DisconnectSyncBackend();
// First, we spin down the backend to stop change processing as soon as
// possible.
// change from a native model. In that case, it will get applied to the sync
// database (which doesn't get destroyed until we destroy the backend below)
// as an unsynced change. That will be persisted, and committed on restart.
- if (data_type_manager_) {
- if (data_type_manager_->state() != DataTypeManager::STOPPED) {
+ if (directory_data_type_manager_) {
+ if (directory_data_type_manager_->state() != DataTypeManager::STOPPED) {
// When aborting as part of shutdown, we should expect an aborted sync
// configure result, else we'll dcheck when we try to read the sync error.
expect_sync_configuration_aborted_ = true;
- data_type_manager_->Stop();
+ directory_data_type_manager_->Stop();
}
- data_type_manager_.reset();
+ directory_data_type_manager_.reset();
}
// Shutdown the migrator before the backend to ensure it doesn't pull a null
// 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;
weak_factory_.InvalidateWeakPtrs();
- startup_controller_.Reset(GetRegisteredDataTypes());
+ 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;
is_auth_in_progress_ = false;
backend_initialized_ = false;
// 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 {
}
void ProfileSyncService::UpdateLastSyncedTime() {
- last_synced_time_ = base::Time::Now();
- sync_prefs_.SetLastSyncedTime(last_synced_time_);
+ sync_prefs_.SetLastSyncedTime(base::Time::Now());
}
void ProfileSyncService::NotifyObservers() {
ClearUnrecoverableError();
last_actionable_error_ = SyncProtocolError();
// Clear the data type errors as well.
- failed_data_types_handler_.Reset();
+ if (directory_data_type_manager_.get())
+ directory_data_type_manager_->ResetDataTypeErrors();
+
}
void ProfileSyncService::ClearUnrecoverableError() {
}
void ProfileSyncService::RegisterNewDataType(syncer::ModelType data_type) {
- if (data_type_controllers_.count(data_type) > 0)
+ if (directory_data_type_controllers_.count(data_type) > 0)
return;
NOTREACHED();
}
UMA_HISTOGRAM_ENUMERATION(kSyncUnrecoverableErrorHistogram,
unrecoverable_error_reason_,
ERROR_REASON_LIMIT);
- NotifyObservers();
std::string location;
from_here.Write(true, true, &location);
LOG(ERROR)
base::Bind(&ProfileSyncService::ShutdownImpl,
weak_factory_.GetWeakPtr(),
delete_sync_database ?
- browser_sync::SyncBackendHost::DISABLE_AND_CLAIM_THREAD :
- browser_sync::SyncBackendHost::STOP_AND_CLAIM_THREAD));
+ syncer::DISABLE_SYNC : syncer::STOP_SYNC));
}
-// TODO(zea): Move this logic into the DataTypeController/DataTypeManager.
-void ProfileSyncService::DisableBrokenDatatype(
- 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()));
+void ProfileSyncService::ReenableDatatype(syncer::ModelType type) {
+ DCHECK(backend_initialized_);
+ directory_data_type_manager_->ReenableType(type);
}
-void ProfileSyncService::OnBackendInitialized(
- const syncer::WeakHandle<syncer::JsBackend>& js_backend,
- const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
- debug_info_listener,
- bool success) {
+void ProfileSyncService::UpdateBackendInitUMA(bool success) {
+ if (backend_mode_ != SYNC)
+ return;
+
is_first_time_sync_configure_ = !HasSyncSetupCompleted();
if (is_first_time_sync_configure_) {
} else {
UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeRestoreTime", delta);
}
+}
- if (!success) {
- // Something went unexpectedly wrong. Play it safe: stop syncing at once
- // and surface error UI to alert the user sync has stopped.
- // Keep the directory around for now so that on restart we will retry
- // again and potentially succeed in presence of transient file IO failures
- // or permissions issues, etc.
- //
- // TODO(rlarocque): Consider making this UnrecoverableError less special.
- // Unlike every other UnrecoverableError, it does not delete our sync data.
- // This exception made sense at the time it was implemented, but our new
- // directory corruption recovery mechanism makes it obsolete. By the time
- // we get here, we will have already tried and failed to delete the
- // directory. It would be no big deal if we tried to delete it again.
- OnInternalUnrecoverableError(FROM_HERE,
- "BackendInitialize failure",
- false,
- ERROR_REASON_BACKEND_INIT_FAILURE);
- return;
+void ProfileSyncService::PostBackendInitialization() {
+ // Never get here for backup / restore.
+ DCHECK_EQ(backend_mode_, SYNC);
+
+ if (last_backup_time_) {
+ DCHECK(device_info_sync_service_);
+ device_info_sync_service_->UpdateLocalDeviceBackupTime(*last_backup_time_);
}
- backend_initialized_ = true;
+ if (protocol_event_observers_.might_have_observers()) {
+ backend_->RequestBufferedProtocolEventsAndEnableForwarding();
+ }
- sync_js_controller_.AttachJsBackend(js_backend);
- debug_info_listener_ = debug_info_listener;
+ non_blocking_data_type_manager_.ConnectSyncBackend(
+ backend_->GetSyncContextProxy());
- if (protocol_event_observers_.might_have_observers()) {
- backend_->SetForwardProtocolEvents(true);
+ if (type_debug_info_observers_.might_have_observers()) {
+ backend_->EnableDirectoryTypeDebugInfoForwarding();
}
// If we have a cached passphrase use it to decrypt/encrypt data now that the
ConsumeCachedPassphraseIfPossible();
// The very first time the backend initializes is effectively the first time
- // we can say we successfully "synced". last_synced_time_ will only be null
- // in this case, because the pref wasn't restored on StartUp.
- if (last_synced_time_.is_null()) {
+ // we can say we successfully "synced". LastSyncedTime will only be null in
+ // this case, because the pref wasn't restored on StartUp.
+ if (sync_prefs_.GetLastSyncedTime().is_null()) {
UpdateLastSyncedTime();
}
NotifyObservers();
}
+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);
+
+ if (!success) {
+ // Something went unexpectedly wrong. Play it safe: stop syncing at once
+ // and surface error UI to alert the user sync has stopped.
+ // Keep the directory around for now so that on restart we will retry
+ // again and potentially succeed in presence of transient file IO failures
+ // or permissions issues, etc.
+ //
+ // TODO(rlarocque): Consider making this UnrecoverableError less special.
+ // Unlike every other UnrecoverableError, it does not delete our sync data.
+ // This exception made sense at the time it was implemented, but our new
+ // directory corruption recovery mechanism makes it obsolete. By the time
+ // we get here, we will have already tried and failed to delete the
+ // directory. It would be no big deal if we tried to delete it again.
+ OnInternalUnrecoverableError(FROM_HERE,
+ "BackendInitialize failure",
+ false,
+ ERROR_REASON_BACKEND_INIT_FAILURE);
+ return;
+ }
+
+ backend_initialized_ = true;
+
+ 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);
+
+ DVLOG(1) << "Setting preferred types for non-blocking DTM";
+ non_blocking_data_type_manager_.SetPreferredTypes(GetPreferredDataTypes());
+
+ // Give the DataTypeControllers a handle to the now initialized backend
+ // as a UserShare.
+ for (DataTypeController::TypeMap::iterator it =
+ directory_data_type_controllers_.begin();
+ it != directory_data_type_controllers_.end(); ++it) {
+ it->second->OnUserShareReady(GetUserShare());
+ }
+
+ if (backend_mode_ == BACKUP || backend_mode_ == ROLLBACK)
+ ConfigureDataTypeManager();
+ else
+ PostBackendInitialization();
+}
+
void ProfileSyncService::OnSyncCycleCompleted() {
UpdateLastSyncedTime();
- if (IsSessionsDataTypeControllerRunning()) {
+ if (IsDataTypeControllerRunning(syncer::SESSIONS)) {
// Trigger garbage collection of old sessions now that we've downloaded
// any new session data.
- if (sessions_sync_manager_) {
- // Sessions V2.
- base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
- &browser_sync::SessionsSyncManager::DoGarbageCollection,
- base::AsWeakPtr(sessions_sync_manager_.get())));
- } else {
- base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
- &browser_sync::SessionModelAssociator::DeleteStaleSessions,
- GetSessionModelAssociatorDeprecated()->AsWeakPtr()));
- }
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &SessionsSyncManager::DoGarbageCollection,
+ base::AsWeakPtr(sessions_sync_manager_.get())));
}
DVLOG(2) << "Notifying observers sync cycle completed";
NotifySyncCycleCompleted();
current_experiments_ = experiments;
// Handle preference-backed experiments first.
- if (experiments.gcm_channel_state != syncer::Experiments::UNSET) {
- profile()->GetPrefs()->SetBoolean(prefs::kGCMChannelEnabled,
- experiments.gcm_channel_state ==
- syncer::Experiments::ENABLED);
- gcm::GCMProfileService* gcm_profile_service =
- gcm::GCMProfileServiceFactory::GetForProfile(profile());
- if (gcm_profile_service) {
- if (experiments.gcm_channel_state == syncer::Experiments::SUPPRESSED)
- gcm_profile_service->Stop();
- else
- gcm_profile_service->Start();
- }
+ if (experiments.gcm_channel_state == syncer::Experiments::SUPPRESSED) {
+ profile()->GetPrefs()->SetBoolean(prefs::kGCMChannelEnabled, false);
+ gcm::GCMProfileServiceFactory::GetForProfile(profile())->driver()
+ ->Disable();
} else {
profile()->GetPrefs()->ClearPref(prefs::kGCMChannelEnabled);
+ gcm::GCMProfileServiceFactory::GetForProfile(profile())->driver()
+ ->Enable();
}
profile()->GetPrefs()->SetBoolean(prefs::kInvalidationServiceUseGCMChannel,
experiments.gcm_invalidations_enabled);
- int bookmarks_experiment_state_before = profile_->GetPrefs()->GetInteger(
- sync_driver::prefs::kEnhancedBookmarksExperimentEnabled);
- // kEnhancedBookmarksExperiment flag could have values "", "1" and "0".
- // "" and "1" means experiment is enabled.
- if ((CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kEnhancedBookmarksExperiment) != "0")) {
- profile_->GetPrefs()->SetInteger(
- sync_driver::prefs::kEnhancedBookmarksExperimentEnabled,
- experiments.enhanced_bookmarks_enabled ? kBookmarksExperimentEnabled
- : kNoBookmarksExperiment);
+ if (experiments.enhanced_bookmarks_enabled) {
profile_->GetPrefs()->SetString(
sync_driver::prefs::kEnhancedBookmarksExtensionId,
experiments.enhanced_bookmarks_ext_id);
} else {
- // User opt-out from chrome://flags
- if (experiments.enhanced_bookmarks_enabled) {
- profile_->GetPrefs()->SetInteger(
- sync_driver::prefs::kEnhancedBookmarksExperimentEnabled,
- kBookmarksExperimentEnabledUserOptOut);
- // Keep extension id up-to-date in case will opt-in later.
- profile_->GetPrefs()->SetString(
- sync_driver::prefs::kEnhancedBookmarksExtensionId,
- experiments.enhanced_bookmarks_ext_id);
- } else {
- profile_->GetPrefs()->ClearPref(
- sync_driver::prefs::kEnhancedBookmarksExperimentEnabled);
- profile_->GetPrefs()->ClearPref(
- sync_driver::prefs::kEnhancedBookmarksExtensionId);
- }
- }
- BookmarksExperimentState bookmarks_experiment_state =
- static_cast<BookmarksExperimentState>(profile_->GetPrefs()->GetInteger(
- sync_driver::prefs::kEnhancedBookmarksExperimentEnabled));
- // If bookmark experiment state was changed update about flags experiment.
- if (bookmarks_experiment_state_before != bookmarks_experiment_state) {
- UpdateBookmarksExperiment(g_browser_process->local_state(),
- bookmarks_experiment_state);
+ profile_->GetPrefs()->ClearPref(
+ sync_driver::prefs::kEnhancedBookmarksExtensionId);
}
+ UpdateBookmarksExperimentState(
+ profile_->GetPrefs(), g_browser_process->local_state(), true,
+ experiments.enhanced_bookmarks_enabled ? BOOKMARKS_EXPERIMENT_ENABLED :
+ BOOKMARKS_EXPERIMENT_NONE);
// If this is a first time sync for a client, this will be called before
// OnBackendInitialized() to ensure the new datatypes are available at sync
<< syncer::PassphraseRequiredReasonToString(reason);
passphrase_required_reason_ = reason;
- const syncer::ModelTypeSet types = GetPreferredDataTypes();
- if (data_type_manager_) {
+ const syncer::ModelTypeSet types = GetPreferredDirectoryDataTypes();
+ if (directory_data_type_manager_) {
// Reconfigure without the encrypted types (excluded implicitly via the
// failed datatypes handler).
- data_type_manager_->Configure(types,
- syncer::CONFIGURE_REASON_CRYPTO);
+ directory_data_type_manager_->Configure(types,
+ syncer::CONFIGURE_REASON_CRYPTO);
}
+ // TODO(rlarocque): Support non-blocking types. http://crbug.com/351005.
+
// Notify observers that the passphrase status may have changed.
NotifyObservers();
}
// Make sure the data types that depend on the passphrase are started at
// this time.
- const syncer::ModelTypeSet types = GetPreferredDataTypes();
- if (data_type_manager_) {
+ const syncer::ModelTypeSet types = GetPreferredDirectoryDataTypes();
+ if (directory_data_type_manager_) {
// Re-enable any encrypted types if necessary.
- data_type_manager_->Configure(types,
- syncer::CONFIGURE_REASON_CRYPTO);
+ directory_data_type_manager_->Configure(types,
+ syncer::CONFIGURE_REASON_CRYPTO);
}
+ // TODO(rlarocque): Support non-blocking types. http://crbug.com/351005.
+
NotifyObservers();
}
bool encrypt_everything) {
encrypted_types_ = encrypted_types;
encrypt_everything_ = encrypt_everything;
+ DCHECK(encrypt_everything_allowed_ || !encrypt_everything_);
DVLOG(1) << "Encrypted types changed to "
<< syncer::ModelTypeSetToString(encrypted_types_)
<< " (encrypt everything is set to "
<< (encrypt_everything_ ? "true" : "false") << ")";
DCHECK(encrypted_types_.Has(syncer::PASSWORDS));
- // If sessions are encrypted, full history sync is not possible, and
- // delete directives are unnecessary.
- if (GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES) &&
- encrypted_types_.Has(syncer::SESSIONS)) {
- DisableBrokenDatatype(syncer::HISTORY_DELETE_DIRECTIVES,
- FROM_HERE,
- "Delete directives not supported with encryption.");
- }
+ NotifyObservers();
}
void ProfileSyncService::OnEncryptionComplete() {
void ProfileSyncService::OnMigrationNeededForTypes(
syncer::ModelTypeSet types) {
DCHECK(backend_initialized_);
- DCHECK(data_type_manager_.get());
+ DCHECK(directory_data_type_manager_.get());
// Migrator must be valid, because we don't sync until it is created and this
// callback originates from a sync cycle.
true,
ERROR_REASON_ACTIONABLE_ERROR);
break;
+ case syncer::DISABLE_SYNC_AND_ROLLBACK:
+ backup_rollback_controller_.OnRollbackReceived();
+ // Fall through to shutdown backend and sign user out.
case syncer::DISABLE_SYNC_ON_CLIENT:
StopSyncingPermanently();
#if !defined(OS_CHROMEOS)
// On desktop Chrome, sign out the user after a dashboard clear.
// Skip sign out on ChromeOS/Android.
- if (!startup_controller_.auto_start_enabled())
- SigninManagerFactory::GetForProfile(profile_)->SignOut();
+ if (!startup_controller_.auto_start_enabled()) {
+ SigninManagerFactory::GetForProfile(profile_)->SignOut(
+ signin_metrics::SERVER_FORCED_DISABLE);
+ }
#endif
break;
+ case syncer::ROLLBACK_DONE:
+ backup_rollback_controller_.OnRollbackDone();
+ break;
case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT:
// 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();
+
+ 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) {
+ const DataTypeManager::ConfigureResult& result) {
+ configure_status_ = result.status;
+ data_type_status_table_ = result.data_type_status_table;
+
+ if (backend_mode_ != SYNC) {
+ 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(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_;
content::Source<ProfileSyncService>(this),
content::NotificationService::NoDetails());
- configure_status_ = result.status;
DVLOG(1) << "PSS OnConfigureDone called with status: " << configure_status_;
// 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.
}
// 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 =
+ data_type_status_table_.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(
+ data_type_status_table_.GetUnrecoverableErrorTypes()) +
": " + error.message();
LOG(ERROR) << "ProfileSyncService error: " << message;
OnInternalUnrecoverableError(error.location(),
}
}
-void ProfileSyncService::OnConfigureRetry() {
- // We should have cleared our cached passphrase before we get here (in
- // OnBackendInitialized()).
- DCHECK(cached_passphrase_.empty());
-
- OnSyncConfigureRetry();
-}
-
void ProfileSyncService::OnConfigureStart() {
sync_configure_start_time_ = base::Time::Now();
NotifyObservers();
return UNRECOVERABLE_ERROR;
} else if (!backend_) {
return NOT_ENABLED;
+ } else if (backend_mode_ == BACKUP) {
+ return BACKUP_USER_DATA;
+ } else if (backend_mode_ == ROLLBACK) {
+ return ROLLBACK_USER_DATA;
} else if (backend_.get() && !HasSyncSetupCompleted()) {
return SETUP_INCOMPLETE;
- } else if (backend_.get() && HasSyncSetupCompleted() &&
- data_type_manager_.get() &&
- data_type_manager_->state() != DataTypeManager::CONFIGURED) {
+ } else if (
+ backend_.get() && HasSyncSetupCompleted() &&
+ directory_data_type_manager_.get() &&
+ directory_data_type_manager_->state() == DataTypeManager::STOPPED) {
return DATATYPES_NOT_INITIALIZED;
- } else if (ShouldPushChanges()) {
+ } else if (SyncActive()) {
return INITIALIZED;
}
return UNKNOWN_ERROR;
std::string ProfileSyncService::QuerySyncStatusSummaryString() {
SyncStatusSummary status = QuerySyncStatusSummary();
+
+ std::string config_status_str =
+ configure_status_ != DataTypeManager::UNKNOWN ?
+ DataTypeManager::ConfigureStatusToString(configure_status_) : "";
+
switch (status) {
case UNRECOVERABLE_ERROR:
return "Unrecoverable error detected";
return "Datatypes not fully initialized";
case INITIALIZED:
return "Sync service initialized";
+ case BACKUP_USER_DATA:
+ return "Backing-up user data. Status: " + config_status_str;
+ case ROLLBACK_USER_DATA:
+ return "Restoring user data. Status: " + config_status_str;
default:
return "Status unknown: Internal error?";
}
return;
startup_controller_.set_setup_in_progress(setup_in_progress);
- if (!setup_in_progress && sync_initialized())
+ if (!setup_in_progress && backend_initialized())
ReconfigureDatatypeManager();
NotifyObservers();
}
-bool ProfileSyncService::sync_initialized() const {
+bool ProfileSyncService::SyncActive() const {
+ return backend_initialized_ && backend_mode_ == SYNC &&
+ directory_data_type_manager_ &&
+ directory_data_type_manager_->state() != DataTypeManager::STOPPED;
+}
+
+bool ProfileSyncService::backend_initialized() const {
return backend_initialized_;
}
+ProfileSyncService::BackendMode ProfileSyncService::backend_mode() const {
+ return backend_mode_;
+}
+
+bool ProfileSyncService::ConfigurationDone() const {
+ return directory_data_type_manager_ &&
+ directory_data_type_manager_->state() == DataTypeManager::CONFIGURED;
+}
+
bool ProfileSyncService::waiting_for_auth() const {
return is_auth_in_progress_;
}
}
base::string16 ProfileSyncService::GetLastSyncedTimeString() const {
- if (last_synced_time_.is_null())
+ const base::Time last_synced_time = sync_prefs_.GetLastSyncedTime();
+ if (last_synced_time.is_null())
return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER);
- base::TimeDelta last_synced = base::Time::Now() - last_synced_time_;
+ base::TimeDelta time_since_last_sync = base::Time::Now() - last_synced_time;
- if (last_synced < base::TimeDelta::FromMinutes(1))
+ if (time_since_last_sync < base::TimeDelta::FromMinutes(1))
return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW);
return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_ELAPSED,
- ui::TimeFormat::LENGTH_SHORT, last_synced);
+ ui::TimeFormat::LENGTH_SHORT,
+ time_since_last_sync);
}
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::WIFI_CREDENTIAL,
+ sync_driver::user_selectable_type::PROXY_TABS,
};
- COMPILE_ASSERT(32 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram);
+ COMPILE_ASSERT(33 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram);
if (!sync_everything) {
const syncer::ModelTypeSet current_types = GetPreferredDataTypes();
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);
}
}
}
#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};
UpdateSelectedTypesHistogram(sync_everything, chosen_types);
sync_prefs_.SetKeepEverythingSynced(sync_everything);
- failed_data_types_handler_.Reset();
- if (GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES) &&
- encrypted_types_.Has(syncer::SESSIONS)) {
- DisableBrokenDatatype(syncer::HISTORY_DELETE_DIRECTIVES,
- FROM_HERE,
- "Delete directives not supported with encryption.");
- }
+ if (directory_data_type_manager_.get())
+ directory_data_type_manager_->ResetDataTypeErrors();
ChangePreferredDataTypes(chosen_types);
AcknowledgeSyncedTypes();
- NotifyObservers();
}
void ProfileSyncService::ChangePreferredDataTypes(
// Now reconfigure the DTM.
ReconfigureDatatypeManager();
+
+ // TODO(rlarocque): Reconfigure the NonBlockingDataTypeManager, too. Blocked
+ // on crbug.com/368834. Until that bug is fixed, it's difficult to tell
+ // which types should be enabled and when.
}
syncer::ModelTypeSet ProfileSyncService::GetActiveDataTypes() const {
+ if (!SyncActive() || !ConfigurationDone())
+ return syncer::ModelTypeSet();
const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes();
const syncer::ModelTypeSet failed_types =
- failed_data_types_handler_.GetFailedTypes();
+ data_type_status_table_.GetFailedTypes();
return Difference(preferred_types, failed_types);
}
const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
const syncer::ModelTypeSet preferred_types =
sync_prefs_.GetPreferredDataTypes(registered_types);
- return preferred_types;
+ const syncer::ModelTypeSet enforced_types =
+ Intersection(GetDataTypesFromPreferenceProviders(), registered_types);
+ return Union(preferred_types, enforced_types);
+}
+
+syncer::ModelTypeSet
+ProfileSyncService::GetPreferredDirectoryDataTypes() const {
+ const syncer::ModelTypeSet registered_directory_types =
+ GetRegisteredDirectoryDataTypes();
+ const syncer::ModelTypeSet preferred_types =
+ sync_prefs_.GetPreferredDataTypes(registered_directory_types);
+ const syncer::ModelTypeSet enforced_types =
+ Intersection(GetDataTypesFromPreferenceProviders(),
+ registered_directory_types);
+ return Union(preferred_types, enforced_types);
+}
+
+syncer::ModelTypeSet
+ProfileSyncService::GetPreferredNonBlockingDataTypes() const {
+ return sync_prefs_.GetPreferredDataTypes(GetRegisteredNonBlockingDataTypes());
+}
+
+syncer::ModelTypeSet ProfileSyncService::GetForcedDataTypes() const {
+ // TODO(treib,zea): When SyncPrefs also implements SyncTypePreferenceProvider,
+ // we'll need another way to distinguish user-choosable types from
+ // programmatically-enabled types.
+ return GetDataTypesFromPreferenceProviders();
}
syncer::ModelTypeSet ProfileSyncService::GetRegisteredDataTypes() const {
+ return Union(GetRegisteredDirectoryDataTypes(),
+ GetRegisteredNonBlockingDataTypes());
+}
+
+syncer::ModelTypeSet
+ProfileSyncService::GetRegisteredDirectoryDataTypes() const {
syncer::ModelTypeSet registered_types;
- // The data_type_controllers_ are determined by command-line flags; that's
- // effectively what controls the values returned here.
+ // The directory_data_type_controllers_ are determined by command-line flags;
+ // that's effectively what controls the values returned here.
for (DataTypeController::TypeMap::const_iterator it =
- data_type_controllers_.begin();
- it != data_type_controllers_.end(); ++it) {
+ directory_data_type_controllers_.begin();
+ it != directory_data_type_controllers_.end(); ++it) {
registered_types.Put(it->first);
}
return registered_types;
}
+syncer::ModelTypeSet
+ProfileSyncService::GetRegisteredNonBlockingDataTypes() const {
+ return non_blocking_data_type_manager_.GetRegisteredTypes();
+}
+
bool ProfileSyncService::IsUsingSecondaryPassphrase() const {
syncer::PassphraseType passphrase_type = GetPassphraseType();
return passphrase_type == syncer::FROZEN_IMPLICIT_PASSPHRASE ||
void ProfileSyncService::ConfigurePriorityDataTypes() {
const syncer::ModelTypeSet priority_types =
- Intersection(GetPreferredDataTypes(), syncer::PriorityUserTypes());
+ Intersection(GetPreferredDirectoryDataTypes(),
+ syncer::PriorityUserTypes());
if (!priority_types.Empty()) {
const syncer::ConfigureReason reason = HasSyncSetupCompleted() ?
syncer::CONFIGURE_REASON_RECONFIGURATION :
syncer::CONFIGURE_REASON_NEW_CLIENT;
- data_type_manager_->Configure(priority_types, reason);
+ directory_data_type_manager_->Configure(priority_types, reason);
}
}
// 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;
- if (!data_type_manager_) {
+ if (!directory_data_type_manager_) {
restart = true;
- data_type_manager_.reset(
+ directory_data_type_manager_.reset(
factory_->CreateDataTypeManager(debug_info_listener_,
- &data_type_controllers_,
+ &directory_data_type_controllers_,
this,
backend_.get(),
- this,
- &failed_data_types_handler_));
+ this));
// We create the migrator at the same time.
migrator_.reset(
new browser_sync::BackendMigrator(
profile_->GetDebugName(), GetUserShare(),
- this, data_type_manager_.get(),
+ this, directory_data_type_manager_.get(),
base::Bind(&ProfileSyncService::StartSyncingWithServer,
base::Unretained(this))));
}
- const syncer::ModelTypeSet types = GetPreferredDataTypes();
+ syncer::ModelTypeSet types;
syncer::ConfigureReason reason = syncer::CONFIGURE_REASON_UNKNOWN;
- if (!HasSyncSetupCompleted()) {
- reason = syncer::CONFIGURE_REASON_NEW_CLIENT;
- } else if (restart) {
- // Datatype downloads on restart are generally due to newly supported
- // datatypes (although it's also possible we're picking up where a failed
- // previous configuration left off).
- // TODO(sync): consider detecting configuration recovery and setting
- // the reason here appropriately.
- reason = syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
+ if (backend_mode_ == BACKUP || backend_mode_ == ROLLBACK) {
+ types = syncer::BackupTypes();
+ reason = syncer::CONFIGURE_REASON_BACKUP_ROLLBACK;
} else {
- // The user initiated a reconfiguration (either to add or remove types).
- reason = syncer::CONFIGURE_REASON_RECONFIGURATION;
+ types = GetPreferredDirectoryDataTypes();
+ if (!HasSyncSetupCompleted()) {
+ reason = syncer::CONFIGURE_REASON_NEW_CLIENT;
+ } else if (restart) {
+ // Datatype downloads on restart are generally due to newly supported
+ // datatypes (although it's also possible we're picking up where a failed
+ // previous configuration left off).
+ // TODO(sync): consider detecting configuration recovery and setting
+ // the reason here appropriately.
+ reason = syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
+ } else {
+ // The user initiated a reconfiguration (either to add or remove types).
+ reason = syncer::CONFIGURE_REASON_RECONFIGURATION;
+ }
}
- data_type_manager_->Configure(types, reason);
+ directory_data_type_manager_->Configure(types, reason);
}
syncer::UserShare* ProfileSyncService::GetUserShare() const {
}
syncer::sessions::SyncSessionSnapshot
- ProfileSyncService::GetLastSessionSnapshot() const {
- if (backend_.get() && backend_initialized_) {
+ProfileSyncService::GetLastSessionSnapshot() const {
+ if (backend_)
return backend_->GetLastSessionSnapshot();
- }
- NOTREACHED();
return syncer::sessions::SyncSessionSnapshot();
}
bool ProfileSyncService::HasUnsyncedItems() const {
- if (backend_.get() && backend_initialized_) {
+ if (HasSyncingBackend() && backend_initialized_) {
return backend_->HasUnsyncedItems();
}
NOTREACHED();
}
browser_sync::BackendMigrator*
- ProfileSyncService::GetBackendMigratorForTest() {
+ProfileSyncService::GetBackendMigratorForTest() {
return migrator_.get();
}
return result.release();
}
- FailedDataTypesHandler::TypeErrorMap error_map =
- failed_data_types_handler_.GetAllErrors();
-
+ DataTypeStatusTable::TypeErrorMap error_map =
+ data_type_status_table_.GetAllErrors();
ModelTypeSet active_types;
ModelTypeSet passive_types;
ModelSafeRoutingInfo routing_info;
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));
+ type_status->SetString("status", "ok");
+ type_status->SetString("value", "Passive");
} else if (throttled_types.Has(type) && passive_types.Has(type)) {
type_status->SetString("status", "warning");
type_status->SetString("value", "Passive, Throttled");
} else if (throttled_types.Has(type)) {
type_status->SetString("status", "warning");
type_status->SetString("value", "Throttled");
+ } else if (GetRegisteredNonBlockingDataTypes().Has(type)) {
+ type_status->SetString("status", "ok");
+ type_status->SetString("value", "Non-Blocking");
} else if (active_types.Has(type)) {
type_status->SetString("status", "ok");
type_status->SetString("value", "Active: " +
return result.release();
}
-void ProfileSyncService::ActivateDataType(
- syncer::ModelType type, syncer::ModelSafeGroup group,
- ChangeProcessor* change_processor) {
- if (!backend_) {
- NOTREACHED();
- return;
- }
- DCHECK(backend_initialized_);
- backend_->ActivateDataType(type, group, change_processor);
-}
-
void ProfileSyncService::DeactivateDataType(syncer::ModelType type) {
if (!backend_)
return;
// If no cached passphrase, or sync backend hasn't started up yet, just exit.
// If the backend isn't running yet, OnBackendInitialized() will call this
// method again after the backend starts up.
- if (cached_passphrase_.empty() || !sync_initialized())
+ if (cached_passphrase_.empty() || !backend_initialized())
return;
// Backend is up and running, so we can consume the cached passphrase.
return;
request_access_token_retry_timer_.Stop();
OAuth2TokenService::ScopeSet oauth2_scopes;
- if (profile_->IsManaged()) {
- oauth2_scopes.insert(GaiaConstants::kChromeSyncManagedOAuth2Scope);
- } else {
- oauth2_scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
- }
+ oauth2_scopes.insert(signin_->GetSyncScopeToUse());
// Invalidate previous token, otherwise token service will return the same
// token again.
void ProfileSyncService::SetEncryptionPassphrase(const std::string& passphrase,
PassphraseType type) {
// This should only be called when the backend has been initialized.
- DCHECK(sync_initialized());
+ DCHECK(backend_initialized());
DCHECK(!(type == IMPLICIT && IsUsingSecondaryPassphrase())) <<
"Data is already encrypted using an explicit passphrase";
DCHECK(!(type == EXPLICIT &&
}
}
+bool ProfileSyncService::EncryptEverythingAllowed() const {
+ return encrypt_everything_allowed_;
+}
+
+void ProfileSyncService::SetEncryptEverythingAllowed(bool allowed) {
+ DCHECK(allowed || !backend_initialized() || !EncryptEverythingEnabled());
+ encrypt_everything_allowed_ = allowed;
+}
+
void ProfileSyncService::EnableEncryptEverything() {
- // Tests override sync_initialized() to always return true, so we
+ DCHECK(EncryptEverythingAllowed());
+
+ // Tests override backend_initialized() to always return true, so we
// must check that instead of |backend_initialized_|.
// TODO(akalin): Fix the above. :/
- DCHECK(sync_initialized());
+ DCHECK(backend_initialized());
// TODO(atwilson): Persist the encryption_pending_ flag to address the various
// problems around cancelling encryption in the background (crbug.com/119649).
if (!encrypt_everything_)
}
void ProfileSyncService::OnSyncManagedPrefChange(bool is_sync_managed) {
- NotifyObservers();
if (is_sync_managed) {
DisableForUser();
} else {
}
}
-void ProfileSyncService::GoogleSigninSucceeded(const std::string& username,
+void ProfileSyncService::GoogleSigninSucceeded(const std::string& account_id,
+ const std::string& username,
const std::string& password) {
if (!sync_prefs_.IsStartSuppressed() && !password.empty()) {
cached_passphrase_ = password;
#if defined(OS_CHROMEOS)
RefreshSpareBootstrapToken(password);
#endif
- if (!sync_initialized() || GetAuthError().state() != AuthError::NONE) {
+ if (!backend_initialized() || GetAuthError().state() != AuthError::NONE) {
// Track the fact that we're still waiting for auth to complete.
is_auth_in_progress_ = true;
}
}
-void ProfileSyncService::GoogleSignedOut(const std::string& username) {
+void ProfileSyncService::GoogleSignedOut(const std::string& account_id,
+ const std::string& username) {
sync_disabled_by_admin_ = false;
DisableForUser();
+
+ if (browser_sync::BackupRollbackController::IsBackupEnabled()) {
+ need_backup_ = true;
+ backup_finished_ = false;
+ }
}
void ProfileSyncService::AddObserver(
void ProfileSyncService::AddProtocolEventObserver(
browser_sync::ProtocolEventObserver* observer) {
protocol_event_observers_.AddObserver(observer);
- if (backend_) {
- backend_->SetForwardProtocolEvents(
- protocol_event_observers_.might_have_observers());
+ if (HasSyncingBackend()) {
+ backend_->RequestBufferedProtocolEventsAndEnableForwarding();
}
}
void ProfileSyncService::RemoveProtocolEventObserver(
browser_sync::ProtocolEventObserver* observer) {
protocol_event_observers_.RemoveObserver(observer);
- if (backend_) {
- backend_->SetForwardProtocolEvents(
- protocol_event_observers_.might_have_observers());
+ if (HasSyncingBackend() &&
+ !protocol_event_observers_.might_have_observers()) {
+ backend_->DisableProtocolEventForwarding();
+ }
+}
+
+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_initialized_) {
+ backend_->EnableDirectoryTypeDebugInfoForwarding();
+ }
+}
+
+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_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
+ : public base::RefCountedThreadSafe<GetAllNodesRequestHelper> {
+ public:
+ GetAllNodesRequestHelper(
+ syncer::ModelTypeSet requested_types,
+ const base::Callback<void(scoped_ptr<base::ListValue>)>& callback);
+
+ void OnReceivedNodesForTypes(
+ const std::vector<syncer::ModelType>& types,
+ ScopedVector<base::ListValue> scoped_node_lists);
+
+ private:
+ friend class base::RefCountedThreadSafe<GetAllNodesRequestHelper>;
+ virtual ~GetAllNodesRequestHelper();
+
+ scoped_ptr<base::ListValue> result_accumulator_;
+
+ syncer::ModelTypeSet awaiting_types_;
+ base::Callback<void(scoped_ptr<base::ListValue>)> callback_;
+};
+
+GetAllNodesRequestHelper::GetAllNodesRequestHelper(
+ syncer::ModelTypeSet requested_types,
+ const base::Callback<void(scoped_ptr<base::ListValue>)>& callback)
+ : result_accumulator_(new base::ListValue()),
+ awaiting_types_(requested_types),
+ callback_(callback) {}
+
+GetAllNodesRequestHelper::~GetAllNodesRequestHelper() {
+ if (!awaiting_types_.Empty()) {
+ DLOG(WARNING)
+ << "GetAllNodesRequest deleted before request was fulfilled. "
+ << "Missing types are: " << ModelTypeSetToString(awaiting_types_);
+ }
+}
+
+// Called when the set of nodes for a type or set of types has been returned.
+//
+// The nodes for several types can be returned at the same time by specifying
+// their types in the |types| array, and putting their results at the
+// correspnding indices in the |scoped_node_lists|.
+void GetAllNodesRequestHelper::OnReceivedNodesForTypes(
+ const std::vector<syncer::ModelType>& types,
+ ScopedVector<base::ListValue> scoped_node_lists) {
+ DCHECK_EQ(types.size(), scoped_node_lists.size());
+
+ // Take unsafe ownership of the node list.
+ std::vector<base::ListValue*> node_lists;
+ scoped_node_lists.release(&node_lists);
+
+ for (size_t i = 0; i < node_lists.size() && i < types.size(); ++i) {
+ const ModelType type = types[i];
+ base::ListValue* node_list = node_lists[i];
+
+ // Add these results to our list.
+ scoped_ptr<base::DictionaryValue> type_dict(new base::DictionaryValue());
+ type_dict->SetString("type", ModelTypeToString(type));
+ type_dict->Set("nodes", node_list);
+ result_accumulator_->Append(type_dict.release());
+
+ // Remember that this part of the request is satisfied.
+ awaiting_types_.Remove(type);
+ }
+
+ if (awaiting_types_.Empty()) {
+ callback_.Run(result_accumulator_.Pass());
+ callback_.Reset();
+ }
+}
+
+} // namespace
+
+void ProfileSyncService::GetAllNodes(
+ const base::Callback<void(scoped_ptr<base::ListValue>)>& callback) {
+ ModelTypeSet directory_types = GetRegisteredDirectoryDataTypes();
+ directory_types.PutAll(syncer::ControlTypes());
+ scoped_refptr<GetAllNodesRequestHelper> helper =
+ new GetAllNodesRequestHelper(directory_types, callback);
+
+ if (!backend_initialized_) {
+ // If there's no backend available to fulfill the request, handle it here.
+ ScopedVector<base::ListValue> empty_results;
+ std::vector<ModelType> type_vector;
+ for (ModelTypeSet::Iterator it = directory_types.First();
+ it.Good(); it.Inc()) {
+ type_vector.push_back(it.Get());
+ empty_results.push_back(new base::ListValue());
+ }
+ helper->OnReceivedNodesForTypes(type_vector, empty_results.Pass());
+ } else {
+ backend_->GetAllNodesForTypes(
+ directory_types,
+ base::Bind(&GetAllNodesRequestHelper::OnReceivedNodesForTypes, helper));
}
}
return sync_prefs_.IsManaged() || sync_disabled_by_admin_;
}
-bool ProfileSyncService::ShouldPushChanges() {
- // True only after all bootstrapping has succeeded: the sync backend
- // is initialized, all enabled data types are consistent with one
- // another, and no unrecoverable error has transpired.
- if (HasUnrecoverableError())
- return false;
-
- if (!data_type_manager_)
- return false;
-
- return data_type_manager_->state() == DataTypeManager::CONFIGURED;
-}
-
void ProfileSyncService::StopAndSuppress() {
sync_prefs_.SetStartSuppressed(true);
- if (backend_) {
+ if (HasSyncingBackend()) {
backend_->UnregisterInvalidationIds();
}
- ShutdownImpl(browser_sync::SyncBackendHost::STOP_AND_CLAIM_THREAD);
+ ShutdownImpl(syncer::STOP_SYNC);
}
bool ProfileSyncService::IsStartSuppressed() const {
void ProfileSyncService::UnsuppressAndStart() {
DCHECK(profile_);
sync_prefs_.SetStartSuppressed(false);
- // Set username in SigninManager, as SigninManager::OnGetUserInfoSuccess
- // is never called for some clients.
- if (signin_.get() &&
- signin_->GetOriginal()->GetAuthenticatedUsername().empty()) {
+ if (signin_.get() && !signin_->GetOriginal()->IsAuthenticated()) {
signin_->GetOriginal()->SetAuthenticatedUsername(
profile_->GetPrefs()->GetString(prefs::kGoogleServicesUsername));
}
}
}
-const FailedDataTypesHandler& ProfileSyncService::failed_data_types_handler()
+syncer::ModelTypeSet ProfileSyncService::GetDataTypesFromPreferenceProviders()
const {
- return failed_data_types_handler_;
+ 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 DataTypeStatusTable& ProfileSyncService::data_type_status_table()
+ const {
+ return data_type_status_table_;
}
void ProfileSyncService::OnInternalUnrecoverableError(
OnUnrecoverableErrorImpl(from_here, message, delete_sync_database);
}
+syncer::SyncManagerFactory::MANAGER_TYPE
+ProfileSyncService::GetManagerType() const {
+ switch (backend_mode_) {
+ case SYNC:
+ return syncer::SyncManagerFactory::NORMAL;
+ case BACKUP:
+ return syncer::SyncManagerFactory::BACKUP;
+ case ROLLBACK:
+ return syncer::SyncManagerFactory::ROLLBACK;
+ case IDLE:
+ NOTREACHED();
+ }
+ return syncer::SyncManagerFactory::NORMAL;
+}
+
bool ProfileSyncService::IsRetryingAccessTokenFetchForTest() const {
return request_access_token_retry_timer_.IsRunning();
}
return sessions_sync_manager_.get();
}
+syncer::SyncableService* ProfileSyncService::GetDeviceInfoSyncableService() {
+ return device_info_sync_service_.get();
+}
+
ProfileSyncService::SyncTokenStatus::SyncTokenStatus()
: connection_status(syncer::CONNECTION_NOT_ATTEMPTED),
last_get_token_error(GoogleServiceAuthError::AuthErrorNone()) {}
scoped_ptr<syncer::NetworkResources> network_resources) {
network_resources_ = network_resources.Pass();
}
+
+bool ProfileSyncService::HasSyncingBackend() const {
+ return backend_mode_ != SYNC ? false : backend_ != NULL;
+}
+
+void ProfileSyncService::UpdateFirstSyncTimePref() {
+ if (signin_->GetEffectiveUsername().empty()) {
+ // Clear if user's not signed in and rollback is done.
+ if (backend_mode_ != ROLLBACK)
+ sync_prefs_.ClearFirstSyncTime();
+ } 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());
+ }
+}
+
+void ProfileSyncService::ClearBrowsingDataSinceFirstSync() {
+ base::Time first_sync_time = sync_prefs_.GetFirstSyncTime();
+ if (first_sync_time.is_null())
+ return;
+
+ clear_browsing_data_.Run(browsing_data_remover_observer_,
+ profile_,
+ first_sync_time,
+ base::Time::Now());
+}
+
+void ProfileSyncService::SetBrowsingDataRemoverObserverForTesting(
+ BrowsingDataRemover::Observer* observer) {
+ browsing_data_remover_observer_ = observer;
+}
+
+void ProfileSyncService::SetClearingBrowseringDataForTesting(
+ base::Callback<void(BrowsingDataRemover::Observer* observer,
+ Profile*,
+ base::Time,
+ base::Time)> c) {
+ clear_browsing_data_ = c;
+}
+
+GURL ProfileSyncService::GetSyncServiceURL(
+ const base::CommandLine& command_line) {
+ // By default, dev, canary, and unbranded Chromium users will go to the
+ // development servers. Development servers have more features than standard
+ // sync servers. Users with officially-branded Chrome stable and beta builds
+ // will go to the standard sync servers.
+ GURL result(kDevServerUrl);
+
+ chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
+ if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
+ channel == chrome::VersionInfo::CHANNEL_BETA) {
+ result = GURL(kSyncServerUrl);
+ }
+
+ // Override the sync server URL from the command-line, if sync server
+ // command-line argument exists.
+ if (command_line.HasSwitch(switches::kSyncServiceURL)) {
+ std::string value(command_line.GetSwitchValueASCII(
+ switches::kSyncServiceURL));
+ if (!value.empty()) {
+ GURL custom_sync_url(value);
+ if (custom_sync_url.is_valid()) {
+ result = custom_sync_url;
+ } else {
+ LOG(WARNING) << "The following sync URL specified at the command-line "
+ << "is invalid: " << value;
+ }
+ }
+ }
+ return result;
+}
+
+void ProfileSyncService::CheckSyncBackupIfNeeded() {
+ DCHECK_EQ(backend_mode_, SYNC);
+
+#if defined(ENABLE_PRE_SYNC_BACKUP)
+ const base::Time last_synced_time = sync_prefs_.GetLastSyncedTime();
+ // 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));
+
+ DCHECK(device_info_sync_service_);
+ device_info_sync_service_->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 device_info_sync_service_->GetLocalDeviceBackupTime();
+}
+
+void ProfileSyncService::FlushDirectory() const {
+ // backend_initialized_ implies backend_ isn't NULL and the manager exists.
+ // If sync is not initialized yet, we fail silently.
+ if (backend_initialized_)
+ backend_->FlushDirectory();
+}
+
+base::FilePath ProfileSyncService::GetDirectoryPathForTest() const {
+ return directory_path_;
+}
+
+base::MessageLoop* ProfileSyncService::GetSyncLoopForTest() const {
+ if (sync_thread_) {
+ return sync_thread_->message_loop();
+ } else if (backend_) {
+ return backend_->GetSyncLoopForTesting();
+ } else {
+ return NULL;
+ }
+}