Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / sync / backend_migrator.cc
blob759c7240db180dd8ad49729b045f0a6912dc9ba4
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/sync/backend_migrator.h"
7 #include "base/location.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "base/tracked_objects.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/sync/profile_sync_service.h"
14 #include "content/public/browser/notification_details.h"
15 #include "content/public/browser/notification_source.h"
16 #include "sync/internal_api/public/configure_reason.h"
17 #include "sync/internal_api/public/read_transaction.h"
18 #include "sync/protocol/sync.pb.h"
19 #include "sync/syncable/directory.h" // TODO(tim): Bug 131130.
21 using syncer::ModelTypeSet;
23 namespace browser_sync {
25 using syncer::ModelTypeToString;
27 MigrationObserver::~MigrationObserver() {}
29 BackendMigrator::BackendMigrator(const std::string& name,
30 syncer::UserShare* user_share,
31 ProfileSyncService* service,
32 sync_driver::DataTypeManager* manager,
33 const base::Closure &migration_done_callback)
34 : name_(name), user_share_(user_share), service_(service),
35 manager_(manager), state_(IDLE),
36 migration_done_callback_(migration_done_callback),
37 weak_ptr_factory_(this) {
40 BackendMigrator::~BackendMigrator() {
43 // Helper macros to log with the syncer thread name; useful when there
44 // are multiple syncer threads involved.
46 #define SLOG(severity) LOG(severity) << name_ << ": "
48 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
50 void BackendMigrator::MigrateTypes(syncer::ModelTypeSet types) {
51 const ModelTypeSet old_to_migrate = to_migrate_;
52 to_migrate_.PutAll(types);
53 SDVLOG(1) << "MigrateTypes called with " << ModelTypeSetToString(types)
54 << ", old_to_migrate = " << ModelTypeSetToString(old_to_migrate)
55 << ", to_migrate_ = " << ModelTypeSetToString(to_migrate_);
56 if (old_to_migrate.Equals(to_migrate_)) {
57 SDVLOG(1) << "MigrateTypes called with no new types; ignoring";
58 return;
61 if (state_ == IDLE)
62 ChangeState(WAITING_TO_START);
64 if (state_ == WAITING_TO_START) {
65 if (!TryStart())
66 SDVLOG(1) << "Manager not configured; waiting";
67 return;
70 DCHECK_GT(state_, WAITING_TO_START);
71 // If we're already migrating, interrupt the current migration.
72 RestartMigration();
75 void BackendMigrator::AddMigrationObserver(MigrationObserver* observer) {
76 migration_observers_.AddObserver(observer);
79 bool BackendMigrator::HasMigrationObserver(
80 const MigrationObserver* observer) const {
81 return migration_observers_.HasObserver(observer);
84 void BackendMigrator::RemoveMigrationObserver(MigrationObserver* observer) {
85 migration_observers_.RemoveObserver(observer);
88 void BackendMigrator::ChangeState(State new_state) {
89 state_ = new_state;
90 FOR_EACH_OBSERVER(MigrationObserver, migration_observers_,
91 OnMigrationStateChange());
94 bool BackendMigrator::TryStart() {
95 DCHECK_EQ(state_, WAITING_TO_START);
96 if (manager_->state() == sync_driver::DataTypeManager::CONFIGURED) {
97 RestartMigration();
98 return true;
100 return false;
103 void BackendMigrator::RestartMigration() {
104 // We'll now disable any running types that need to be migrated.
105 ChangeState(DISABLING_TYPES);
106 SDVLOG(1) << "BackendMigrator disabling types "
107 << ModelTypeSetToString(to_migrate_);
109 manager_->PurgeForMigration(to_migrate_, syncer::CONFIGURE_REASON_MIGRATION);
112 void BackendMigrator::OnConfigureDone(
113 const sync_driver::DataTypeManager::ConfigureResult& result) {
114 if (state_ == IDLE)
115 return;
117 // |manager_|'s methods aren't re-entrant, and we're notified from
118 // them, so post a task to avoid problems.
119 SDVLOG(1) << "Posting OnConfigureDoneImpl";
120 base::ThreadTaskRunnerHandle::Get()->PostTask(
121 FROM_HERE, base::Bind(&BackendMigrator::OnConfigureDoneImpl,
122 weak_ptr_factory_.GetWeakPtr(), result));
125 namespace {
127 syncer::ModelTypeSet GetUnsyncedDataTypes(syncer::UserShare* user_share) {
128 syncer::ReadTransaction trans(FROM_HERE, user_share);
129 syncer::ModelTypeSet unsynced_data_types;
130 for (int i = syncer::FIRST_REAL_MODEL_TYPE;
131 i < syncer::MODEL_TYPE_COUNT; ++i) {
132 syncer::ModelType type = syncer::ModelTypeFromInt(i);
133 sync_pb::DataTypeProgressMarker progress_marker;
134 trans.GetDirectory()->GetDownloadProgress(type, &progress_marker);
135 if (progress_marker.token().empty()) {
136 unsynced_data_types.Put(type);
139 return unsynced_data_types;
142 } // namespace
144 void BackendMigrator::OnConfigureDoneImpl(
145 const sync_driver::DataTypeManager::ConfigureResult& result) {
146 SDVLOG(1) << "OnConfigureDone with requested types "
147 << ModelTypeSetToString(result.requested_types)
148 << ", status " << result.status
149 << ", and to_migrate_ = " << ModelTypeSetToString(to_migrate_);
150 if (state_ == WAITING_TO_START) {
151 if (!TryStart())
152 SDVLOG(1) << "Manager still not configured; still waiting";
153 return;
156 DCHECK_GT(state_, WAITING_TO_START);
158 const ModelTypeSet intersection =
159 Intersection(result.requested_types, to_migrate_);
160 // This intersection check is to determine if our disable request
161 // was interrupted by a user changing preferred types.
162 if (state_ == DISABLING_TYPES && !intersection.Empty()) {
163 SDVLOG(1) << "Disable request interrupted by user changing types";
164 RestartMigration();
165 return;
168 if (result.status != sync_driver::DataTypeManager::OK) {
169 // If this fails, and we're disabling types, a type may or may not be
170 // disabled until the user restarts the browser. If this wasn't an abort,
171 // any failure will be reported as an unrecoverable error to the UI. If it
172 // was an abort, then typically things are shutting down anyway. There isn't
173 // much we can do in any case besides wait until a restart to try again.
174 // The server will send down MIGRATION_DONE again for types needing
175 // migration as the type will still be enabled on restart.
176 SLOG(WARNING) << "Unable to migrate, configuration failed!";
177 ChangeState(IDLE);
178 to_migrate_.Clear();
179 return;
182 if (state_ == DISABLING_TYPES) {
183 const syncer::ModelTypeSet unsynced_types =
184 GetUnsyncedDataTypes(user_share_);
185 if (!unsynced_types.HasAll(to_migrate_)) {
186 SLOG(WARNING) << "Set of unsynced types: "
187 << syncer::ModelTypeSetToString(unsynced_types)
188 << " does not contain types to migrate: "
189 << syncer::ModelTypeSetToString(to_migrate_)
190 << "; not re-enabling yet";
191 return;
194 ChangeState(REENABLING_TYPES);
195 // Don't use |to_migrate_| for the re-enabling because the user
196 // may have chosen to disable types during the migration.
197 const ModelTypeSet full_set = service_->GetPreferredDataTypes();
198 SDVLOG(1) << "BackendMigrator re-enabling types: "
199 << syncer::ModelTypeSetToString(full_set);
200 manager_->Configure(full_set, syncer::CONFIGURE_REASON_MIGRATION);
201 } else if (state_ == REENABLING_TYPES) {
202 // We're done!
203 ChangeState(IDLE);
205 SDVLOG(1) << "BackendMigrator: Migration complete for: "
206 << syncer::ModelTypeSetToString(to_migrate_);
207 to_migrate_.Clear();
209 if (!migration_done_callback_.is_null())
210 migration_done_callback_.Run();
214 BackendMigrator::State BackendMigrator::state() const {
215 return state_;
218 syncer::ModelTypeSet BackendMigrator::GetPendingMigrationTypesForTest() const {
219 return to_migrate_;
222 #undef SDVLOG
224 #undef SLOG
226 }; // namespace browser_sync