Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / components / sync_driver / model_association_manager.cc
blob71fbdd522c422edf02254423ac1cd6f8d9af1f94
1 // Copyright 2014 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 "components/sync_driver/model_association_manager.h"
7 #include <algorithm>
8 #include <functional>
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/histogram.h"
13 #include "base/trace_event/trace_event.h"
14 #include "sync/internal_api/public/base/model_type.h"
16 using syncer::ModelTypeSet;
18 namespace sync_driver {
20 namespace {
22 static const syncer::ModelType kStartOrder[] = {
23 syncer::NIGORI, // Listed for completeness.
24 syncer::DEVICE_INFO, // Listed for completeness.
25 syncer::EXPERIMENTS, // Listed for completeness.
26 syncer::PROXY_TABS, // Listed for completeness.
28 // Kick off the association of the non-UI types first so they can associate
29 // in parallel with the UI types.
30 syncer::PASSWORDS,
31 syncer::AUTOFILL,
32 syncer::AUTOFILL_PROFILE,
33 syncer::AUTOFILL_WALLET_DATA,
34 syncer::EXTENSION_SETTINGS,
35 syncer::APP_SETTINGS,
36 syncer::TYPED_URLS,
37 syncer::HISTORY_DELETE_DIRECTIVES,
38 syncer::SYNCED_NOTIFICATIONS,
39 syncer::SYNCED_NOTIFICATION_APP_INFO,
41 // UI thread data types.
42 syncer::BOOKMARKS,
43 syncer::SUPERVISED_USERS, // Syncing supervised users on initial login
44 // might block creating a new supervised user,
45 // so we want to do it early.
46 syncer::PREFERENCES,
47 syncer::PRIORITY_PREFERENCES,
48 syncer::EXTENSIONS,
49 syncer::APPS,
50 syncer::APP_LIST,
51 syncer::THEMES,
52 syncer::SEARCH_ENGINES,
53 syncer::SESSIONS,
54 syncer::APP_NOTIFICATIONS,
55 syncer::DICTIONARY,
56 syncer::FAVICON_IMAGES,
57 syncer::FAVICON_TRACKING,
58 syncer::SUPERVISED_USER_SETTINGS,
59 syncer::SUPERVISED_USER_SHARED_SETTINGS,
60 syncer::SUPERVISED_USER_WHITELISTS,
61 syncer::ARTICLES,
62 syncer::WIFI_CREDENTIALS,
65 static_assert(arraysize(kStartOrder) ==
66 syncer::MODEL_TYPE_COUNT - syncer::FIRST_REAL_MODEL_TYPE,
67 "kStartOrder must have MODEL_TYPE_COUNT - "
68 "FIRST_REAL_MODEL_TYPE elements");
70 // The amount of time we wait for association to finish. If some types haven't
71 // finished association by the time, DataTypeManager is notified of the
72 // unfinished types.
73 const int64 kAssociationTimeOutInSeconds = 600;
75 syncer::DataTypeAssociationStats BuildAssociationStatsFromMergeResults(
76 const syncer::SyncMergeResult& local_merge_result,
77 const syncer::SyncMergeResult& syncer_merge_result,
78 const base::TimeDelta& association_wait_time,
79 const base::TimeDelta& association_time) {
80 DCHECK_EQ(local_merge_result.model_type(), syncer_merge_result.model_type());
81 syncer::DataTypeAssociationStats stats;
82 stats.had_error = local_merge_result.error().IsSet() ||
83 syncer_merge_result.error().IsSet();
84 stats.num_local_items_before_association =
85 local_merge_result.num_items_before_association();
86 stats.num_sync_items_before_association =
87 syncer_merge_result.num_items_before_association();
88 stats.num_local_items_after_association =
89 local_merge_result.num_items_after_association();
90 stats.num_sync_items_after_association =
91 syncer_merge_result.num_items_after_association();
92 stats.num_local_items_added =
93 local_merge_result.num_items_added();
94 stats.num_local_items_deleted =
95 local_merge_result.num_items_deleted();
96 stats.num_local_items_modified =
97 local_merge_result.num_items_modified();
98 stats.local_version_pre_association =
99 local_merge_result.pre_association_version();
100 stats.num_sync_items_added =
101 syncer_merge_result.num_items_added();
102 stats.num_sync_items_deleted =
103 syncer_merge_result.num_items_deleted();
104 stats.num_sync_items_modified =
105 syncer_merge_result.num_items_modified();
106 stats.sync_version_pre_association =
107 syncer_merge_result.pre_association_version();
108 stats.association_wait_time = association_wait_time;
109 stats.association_time = association_time;
110 return stats;
113 } // namespace
115 ModelAssociationManager::ModelAssociationManager(
116 const DataTypeController::TypeMap* controllers,
117 ModelAssociationManagerDelegate* processor)
118 : state_(IDLE),
119 controllers_(controllers),
120 delegate_(processor),
121 configure_status_(DataTypeManager::UNKNOWN),
122 weak_ptr_factory_(this) {
123 // Ensure all data type controllers are stopped.
124 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
125 it != controllers_->end(); ++it) {
126 DCHECK_EQ(DataTypeController::NOT_RUNNING, (*it).second->state());
130 ModelAssociationManager::~ModelAssociationManager() {
133 void ModelAssociationManager::Initialize(syncer::ModelTypeSet desired_types) {
134 // state_ can be INITIALIZED_TO_CONFIGURE if types are reconfigured when
135 // data is being downloaded, so StartAssociationAsync() is never called for
136 // the first configuration.
137 DCHECK_NE(CONFIGURING, state_);
139 // Only keep types that have controllers.
140 desired_types_.Clear();
141 for (syncer::ModelTypeSet::Iterator it = desired_types.First();
142 it.Good(); it.Inc()) {
143 if (controllers_->find(it.Get()) != controllers_->end())
144 desired_types_.Put(it.Get());
147 DVLOG(1) << "ModelAssociationManager: Initializing for "
148 << syncer::ModelTypeSetToString(desired_types_);
150 state_ = INITIALIZED_TO_CONFIGURE;
152 StopDisabledTypes();
153 LoadEnabledTypes();
156 void ModelAssociationManager::StopDatatype(
157 const syncer::SyncError& error,
158 DataTypeController* dtc) {
159 loaded_types_.Remove(dtc->type());
160 associated_types_.Remove(dtc->type());
161 associating_types_.Remove(dtc->type());
163 if (error.IsSet() || dtc->state() != DataTypeController::NOT_RUNNING) {
164 // If an error was set, the delegate must be informed of the error.
165 delegate_->OnSingleDataTypeWillStop(dtc->type(), error);
166 dtc->Stop();
170 void ModelAssociationManager::StopDisabledTypes() {
171 DVLOG(1) << "ModelAssociationManager: Stopping disabled types.";
172 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
173 it != controllers_->end(); ++it) {
174 DataTypeController* dtc = (*it).second.get();
175 if (dtc->state() != DataTypeController::NOT_RUNNING &&
176 !desired_types_.Has(dtc->type())) {
177 DVLOG(1) << "ModelTypeToString: stop " << dtc->name();
178 StopDatatype(syncer::SyncError(), dtc);
183 void ModelAssociationManager::LoadEnabledTypes() {
184 // Load in kStartOrder.
185 for (size_t i = 0; i < arraysize(kStartOrder); i++) {
186 syncer::ModelType type = kStartOrder[i];
187 if (!desired_types_.Has(type))
188 continue;
190 DCHECK(controllers_->find(type) != controllers_->end());
191 DataTypeController* dtc = controllers_->find(type)->second.get();
192 if (dtc->state() == DataTypeController::NOT_RUNNING) {
193 DCHECK(!loaded_types_.Has(dtc->type()));
194 DCHECK(!associated_types_.Has(dtc->type()));
195 dtc->LoadModels(base::Bind(&ModelAssociationManager::ModelLoadCallback,
196 weak_ptr_factory_.GetWeakPtr()));
201 void ModelAssociationManager::StartAssociationAsync(
202 const syncer::ModelTypeSet& types_to_associate) {
203 DCHECK_NE(CONFIGURING, state_);
204 state_ = CONFIGURING;
206 association_start_time_ = base::TimeTicks::Now();
208 requested_types_ = types_to_associate;
210 associating_types_ = types_to_associate;
211 associating_types_.RetainAll(desired_types_);
212 associating_types_.RemoveAll(associated_types_);
214 // Assume success.
215 configure_status_ = DataTypeManager::OK;
217 // Done if no types to associate.
218 if (associating_types_.Empty()) {
219 ModelAssociationDone();
220 return;
223 timer_.Start(FROM_HERE,
224 base::TimeDelta::FromSeconds(kAssociationTimeOutInSeconds),
225 this,
226 &ModelAssociationManager::ModelAssociationDone);
228 // Start association of types that are loaded in specified order.
229 for (size_t i = 0; i < arraysize(kStartOrder); i++) {
230 syncer::ModelType type = kStartOrder[i];
231 if (!associating_types_.Has(type) || !loaded_types_.Has(type))
232 continue;
234 DataTypeController* dtc = controllers_->find(type)->second.get();
235 DCHECK(DataTypeController::MODEL_LOADED == dtc->state() ||
236 DataTypeController::ASSOCIATING == dtc->state());
237 if (dtc->state() == DataTypeController::MODEL_LOADED) {
238 TRACE_EVENT_ASYNC_BEGIN1("sync", "ModelAssociation",
239 dtc,
240 "DataType",
241 ModelTypeToString(type));
243 dtc->StartAssociating(
244 base::Bind(&ModelAssociationManager::TypeStartCallback,
245 weak_ptr_factory_.GetWeakPtr(),
246 type, base::TimeTicks::Now()));
251 void ModelAssociationManager::ResetForNextAssociation() {
252 DVLOG(1) << "ModelAssociationManager: Reseting for next configuration";
253 // |loaded_types_| and |associated_types_| are not cleared. So
254 // reconfiguration won't restart types that are already started.
255 requested_types_.Clear();
256 associating_types_.Clear();
259 void ModelAssociationManager::Stop() {
260 // Ignore callbacks from controllers.
261 weak_ptr_factory_.InvalidateWeakPtrs();
263 desired_types_.Clear();
264 loaded_types_.Clear();
265 associated_types_.Clear();
266 associating_types_.Clear();
268 // Stop started data types.
269 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
270 it != controllers_->end(); ++it) {
271 DataTypeController* dtc = (*it).second.get();
272 if (dtc->state() != DataTypeController::NOT_RUNNING) {
273 StopDatatype(syncer::SyncError(), dtc);
274 DVLOG(1) << "ModelAssociationManager: Stopped " << dtc->name();
278 if (state_ == CONFIGURING) {
279 if (configure_status_ == DataTypeManager::OK)
280 configure_status_ = DataTypeManager::ABORTED;
281 DVLOG(1) << "ModelAssociationManager: Calling OnModelAssociationDone";
282 ModelAssociationDone();
285 ResetForNextAssociation();
287 state_ = IDLE;
290 void ModelAssociationManager::ModelLoadCallback(syncer::ModelType type,
291 syncer::SyncError error) {
292 DVLOG(1) << "ModelAssociationManager: ModelLoadCallback for "
293 << syncer::ModelTypeToString(type);
295 if (error.IsSet()) {
296 syncer::SyncMergeResult local_merge_result(type);
297 local_merge_result.set_error(error);
298 TypeStartCallback(type,
299 base::TimeTicks::Now(),
300 DataTypeController::ASSOCIATION_FAILED,
301 local_merge_result,
302 syncer::SyncMergeResult(type));
303 return;
306 // This happens when slow loading type is disabled by new configuration.
307 if (!desired_types_.Has(type))
308 return;
310 DCHECK(!loaded_types_.Has(type));
311 loaded_types_.Put(type);
312 if (associating_types_.Has(type)) {
313 DataTypeController* dtc = controllers_->find(type)->second.get();
314 dtc->StartAssociating(
315 base::Bind(&ModelAssociationManager::TypeStartCallback,
316 weak_ptr_factory_.GetWeakPtr(),
317 type, base::TimeTicks::Now()));
321 void ModelAssociationManager::TypeStartCallback(
322 syncer::ModelType type,
323 base::TimeTicks type_start_time,
324 DataTypeController::ConfigureResult start_result,
325 const syncer::SyncMergeResult& local_merge_result,
326 const syncer::SyncMergeResult& syncer_merge_result) {
327 if (desired_types_.Has(type) &&
328 !DataTypeController::IsSuccessfulResult(start_result)) {
329 DVLOG(1) << "ModelAssociationManager: Type encountered an error.";
330 desired_types_.Remove(type);
331 DataTypeController* dtc = controllers_->find(type)->second.get();
332 StopDatatype(local_merge_result.error(), dtc);
334 // Update configuration result.
335 if (start_result == DataTypeController::UNRECOVERABLE_ERROR)
336 configure_status_ = DataTypeManager::UNRECOVERABLE_ERROR;
339 // This happens when a slow associating type is disabled or if a type
340 // disables itself after initial configuration.
341 if (!desired_types_.Has(type)) {
342 // It's possible all types failed to associate, in which case association
343 // is complete.
344 if (state_ == CONFIGURING && associating_types_.Empty())
345 ModelAssociationDone();
346 return;
349 DCHECK(!associated_types_.Has(type));
350 DCHECK(DataTypeController::IsSuccessfulResult(start_result));
351 associated_types_.Put(type);
353 if (state_ != CONFIGURING)
354 return;
356 TRACE_EVENT_ASYNC_END1("sync", "ModelAssociation",
357 controllers_->find(type)->second.get(),
358 "DataType",
359 ModelTypeToString(type));
361 // Track the merge results if we succeeded or an association failure
362 // occurred.
363 if (syncer::ProtocolTypes().Has(type)) {
364 base::TimeDelta association_wait_time =
365 std::max(base::TimeDelta(), type_start_time - association_start_time_);
366 base::TimeDelta association_time =
367 base::TimeTicks::Now() - type_start_time;;
368 syncer::DataTypeAssociationStats stats =
369 BuildAssociationStatsFromMergeResults(local_merge_result,
370 syncer_merge_result,
371 association_wait_time,
372 association_time);
373 delegate_->OnSingleDataTypeAssociationDone(type, stats);
376 associating_types_.Remove(type);
378 if (associating_types_.Empty())
379 ModelAssociationDone();
382 void ModelAssociationManager::ModelAssociationDone() {
383 CHECK_EQ(CONFIGURING, state_);
385 timer_.Stop();
387 // Treat any unfinished types as having errors.
388 desired_types_.RemoveAll(associating_types_);
389 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
390 it != controllers_->end(); ++it) {
391 DataTypeController* dtc = (*it).second.get();
392 if (associating_types_.Has(dtc->type()) &&
393 dtc->state() != DataTypeController::NOT_RUNNING) {
394 UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed",
395 ModelTypeToHistogramInt(dtc->type()),
396 syncer::MODEL_TYPE_COUNT);
397 StopDatatype(syncer::SyncError(FROM_HERE,
398 syncer::SyncError::DATATYPE_ERROR,
399 "Association timed out.",
400 dtc->type()),
401 dtc);
405 DataTypeManager::ConfigureResult result(configure_status_,
406 requested_types_);
408 // Reset state before notifying |delegate_| because that might
409 // trigger a new round of configuration.
410 ResetForNextAssociation();
411 state_ = IDLE;
413 delegate_->OnModelAssociationDone(result);
416 base::OneShotTimer<ModelAssociationManager>*
417 ModelAssociationManager::GetTimerForTesting() {
418 return &timer_;
421 } // namespace sync_driver