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.
4
5 #include "components/sync_driver/data_type_manager_impl.h"
6
7 #include <algorithm>
8 #include <functional>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/callback.h"
13 #include "base/compiler_specific.h"
14 #include "base/debug/trace_event.h"
15 #include "base/logging.h"
16 #include "base/metrics/histogram.h"
17 #include "base/strings/stringprintf.h"
18 #include "components/sync_driver/data_type_controller.h"
19 #include "components/sync_driver/data_type_encryption_handler.h"
20 #include "components/sync_driver/data_type_manager_observer.h"
21 #include "components/sync_driver/failed_data_types_handler.h"
22 #include "sync/internal_api/public/data_type_debug_info_listener.h"
23
24 namespace browser_sync {
25
26 namespace {
27
28 FailedDataTypesHandler::TypeErrorMap
GenerateCryptoErrorsForTypes(syncer::ModelTypeSet encrypted_types)29 GenerateCryptoErrorsForTypes(syncer::ModelTypeSet encrypted_types) {
30 FailedDataTypesHandler::TypeErrorMap crypto_errors;
31 for (syncer::ModelTypeSet::Iterator iter = encrypted_types.First();
32 iter.Good(); iter.Inc()) {
33 crypto_errors[iter.Get()] = syncer::SyncError(
34 FROM_HERE,
35 syncer::SyncError::CRYPTO_ERROR,
36 "",
37 iter.Get());
38 }
39 return crypto_errors;
40 }
41
42 } // namespace
43
AssociationTypesInfo()44 DataTypeManagerImpl::AssociationTypesInfo::AssociationTypesInfo() {}
~AssociationTypesInfo()45 DataTypeManagerImpl::AssociationTypesInfo::~AssociationTypesInfo() {}
46
DataTypeManagerImpl(const base::Closure & unrecoverable_error_method,const syncer::WeakHandle<syncer::DataTypeDebugInfoListener> & debug_info_listener,const DataTypeController::TypeMap * controllers,const browser_sync::DataTypeEncryptionHandler * encryption_handler,BackendDataTypeConfigurer * configurer,DataTypeManagerObserver * observer,browser_sync::FailedDataTypesHandler * failed_data_types_handler)47 DataTypeManagerImpl::DataTypeManagerImpl(
48 const base::Closure& unrecoverable_error_method,
49 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
50 debug_info_listener,
51 const DataTypeController::TypeMap* controllers,
52 const browser_sync::DataTypeEncryptionHandler* encryption_handler,
53 BackendDataTypeConfigurer* configurer,
54 DataTypeManagerObserver* observer,
55 browser_sync::FailedDataTypesHandler* failed_data_types_handler)
56 : configurer_(configurer),
57 controllers_(controllers),
58 state_(DataTypeManager::STOPPED),
59 needs_reconfigure_(false),
60 last_configure_reason_(syncer::CONFIGURE_REASON_UNKNOWN),
61 debug_info_listener_(debug_info_listener),
62 model_association_manager_(controllers, this),
63 observer_(observer),
64 failed_data_types_handler_(failed_data_types_handler),
65 encryption_handler_(encryption_handler),
66 unrecoverable_error_method_(unrecoverable_error_method),
67 weak_ptr_factory_(this) {
68 DCHECK(failed_data_types_handler_);
69 DCHECK(configurer_);
70 DCHECK(observer_);
71 }
72
~DataTypeManagerImpl()73 DataTypeManagerImpl::~DataTypeManagerImpl() {}
74
Configure(syncer::ModelTypeSet desired_types,syncer::ConfigureReason reason)75 void DataTypeManagerImpl::Configure(syncer::ModelTypeSet desired_types,
76 syncer::ConfigureReason reason) {
77 if (reason == syncer::CONFIGURE_REASON_BACKUP_ROLLBACK)
78 desired_types.PutAll(syncer::ControlTypes());
79 else
80 desired_types.PutAll(syncer::CoreTypes());
81
82 // Only allow control types and types that have controllers.
83 syncer::ModelTypeSet filtered_desired_types;
84 for (syncer::ModelTypeSet::Iterator type = desired_types.First();
85 type.Good(); type.Inc()) {
86 DataTypeController::TypeMap::const_iterator iter =
87 controllers_->find(type.Get());
88 if (syncer::IsControlType(type.Get()) ||
89 iter != controllers_->end()) {
90 if (iter != controllers_->end()) {
91 if (!iter->second->ReadyForStart()) {
92 // Add the type to the unready types set to prevent purging it. It's
93 // up to the datatype controller to, if necessary, explicitly
94 // mark the type as broken to trigger a purge.
95 syncer::SyncError error(FROM_HERE,
96 syncer::SyncError::UNREADY_ERROR,
97 "Datatype not ready at config time.",
98 type.Get());
99 std::map<syncer::ModelType, syncer::SyncError> errors;
100 errors[type.Get()] = error;
101 failed_data_types_handler_->UpdateFailedDataTypes(errors);
102 } else {
103 failed_data_types_handler_->ResetUnreadyErrorFor(type.Get());
104 }
105 }
106 filtered_desired_types.Put(type.Get());
107 }
108 }
109 ConfigureImpl(filtered_desired_types, reason);
110 }
111
PurgeForMigration(syncer::ModelTypeSet undesired_types,syncer::ConfigureReason reason)112 void DataTypeManagerImpl::PurgeForMigration(
113 syncer::ModelTypeSet undesired_types,
114 syncer::ConfigureReason reason) {
115 syncer::ModelTypeSet remainder = Difference(last_requested_types_,
116 undesired_types);
117 ConfigureImpl(remainder, reason);
118 }
119
ConfigureImpl(syncer::ModelTypeSet desired_types,syncer::ConfigureReason reason)120 void DataTypeManagerImpl::ConfigureImpl(
121 syncer::ModelTypeSet desired_types,
122 syncer::ConfigureReason reason) {
123 DCHECK_NE(reason, syncer::CONFIGURE_REASON_UNKNOWN);
124 DVLOG(1) << "Configuring for " << syncer::ModelTypeSetToString(desired_types)
125 << " with reason " << reason;
126 if (state_ == STOPPING) {
127 // You can not set a configuration while stopping.
128 LOG(ERROR) << "Configuration set while stopping.";
129 return;
130 }
131
132 // TODO(zea): consider not performing a full configuration once there's a
133 // reliable way to determine if the requested set of enabled types matches the
134 // current set.
135
136 last_requested_types_ = desired_types;
137 last_configure_reason_ = reason;
138 // Only proceed if we're in a steady state or retrying.
139 if (state_ != STOPPED && state_ != CONFIGURED && state_ != RETRYING) {
140 DVLOG(1) << "Received configure request while configuration in flight. "
141 << "Postponing until current configuration complete.";
142 needs_reconfigure_ = true;
143 return;
144 }
145
146 Restart(reason);
147 }
148
149 BackendDataTypeConfigurer::DataTypeConfigStateMap
BuildDataTypeConfigStateMap(const syncer::ModelTypeSet & types_being_configured) const150 DataTypeManagerImpl::BuildDataTypeConfigStateMap(
151 const syncer::ModelTypeSet& types_being_configured) const {
152 // 1. Get the failed types (due to fatal, crypto, and unready errors).
153 // 2. Add the difference between last_requested_types_ and the failed types
154 // as CONFIGURE_INACTIVE.
155 // 3. Flip |types_being_configured| to CONFIGURE_ACTIVE.
156 // 4. Set non-enabled user types as DISABLED.
157 // 5. Set the fatal, crypto, and unready types to their respective states.
158 syncer::ModelTypeSet error_types =
159 failed_data_types_handler_->GetFailedTypes();
160 syncer::ModelTypeSet fatal_types =
161 failed_data_types_handler_->GetFatalErrorTypes();
162 syncer::ModelTypeSet crypto_types =
163 failed_data_types_handler_->GetCryptoErrorTypes();
164 syncer::ModelTypeSet unready_types=
165 failed_data_types_handler_->GetUnreadyErrorTypes();
166
167 // Types with persistence errors are only purged/resynced when they're
168 // actively being configured.
169 syncer::ModelTypeSet persistence_types =
170 failed_data_types_handler_->GetPersistenceErrorTypes();
171 persistence_types.RetainAll(types_being_configured);
172
173 // Types with unready errors do not count as unready if they've been disabled.
174 unready_types.RetainAll(last_requested_types_);
175
176 syncer::ModelTypeSet enabled_types = last_requested_types_;
177 enabled_types.RemoveAll(error_types);
178 syncer::ModelTypeSet disabled_types =
179 syncer::Difference(
180 syncer::Union(syncer::UserTypes(), syncer::ControlTypes()),
181 enabled_types);
182 syncer::ModelTypeSet to_configure = syncer::Intersection(
183 enabled_types, types_being_configured);
184 DVLOG(1) << "Enabling: " << syncer::ModelTypeSetToString(enabled_types);
185 DVLOG(1) << "Configuring: " << syncer::ModelTypeSetToString(to_configure);
186 DVLOG(1) << "Disabling: " << syncer::ModelTypeSetToString(disabled_types);
187
188 BackendDataTypeConfigurer::DataTypeConfigStateMap config_state_map;
189 BackendDataTypeConfigurer::SetDataTypesState(
190 BackendDataTypeConfigurer::CONFIGURE_INACTIVE, enabled_types,
191 &config_state_map);
192 BackendDataTypeConfigurer::SetDataTypesState(
193 BackendDataTypeConfigurer::CONFIGURE_ACTIVE, to_configure,
194 &config_state_map);
195 BackendDataTypeConfigurer::SetDataTypesState(
196 BackendDataTypeConfigurer::CONFIGURE_CLEAN, persistence_types,
197 &config_state_map);
198 BackendDataTypeConfigurer::SetDataTypesState(
199 BackendDataTypeConfigurer::DISABLED, disabled_types,
200 &config_state_map);
201 BackendDataTypeConfigurer::SetDataTypesState(
202 BackendDataTypeConfigurer::FATAL, fatal_types,
203 &config_state_map);
204 BackendDataTypeConfigurer::SetDataTypesState(
205 BackendDataTypeConfigurer::CRYPTO, crypto_types,
206 &config_state_map);
207 BackendDataTypeConfigurer::SetDataTypesState(
208 BackendDataTypeConfigurer::UNREADY, unready_types,
209 &config_state_map);
210 return config_state_map;
211 }
212
Restart(syncer::ConfigureReason reason)213 void DataTypeManagerImpl::Restart(syncer::ConfigureReason reason) {
214 DVLOG(1) << "Restarting...";
215
216 // Check for new or resolved data type crypto errors.
217 if (encryption_handler_->IsPassphraseRequired()) {
218 syncer::ModelTypeSet encrypted_types =
219 encryption_handler_->GetEncryptedDataTypes();
220 encrypted_types.RetainAll(last_requested_types_);
221 encrypted_types.RemoveAll(
222 failed_data_types_handler_->GetCryptoErrorTypes());
223 FailedDataTypesHandler::TypeErrorMap crypto_errors =
224 GenerateCryptoErrorsForTypes(encrypted_types);
225 failed_data_types_handler_->UpdateFailedDataTypes(crypto_errors);
226 } else {
227 failed_data_types_handler_->ResetCryptoErrors();
228 }
229
230 syncer::ModelTypeSet failed_types =
231 failed_data_types_handler_->GetFailedTypes();
232 syncer::ModelTypeSet enabled_types =
233 syncer::Difference(last_requested_types_, failed_types);
234
235 last_restart_time_ = base::Time::Now();
236 configuration_stats_.clear();
237
238 DCHECK(state_ == STOPPED || state_ == CONFIGURED || state_ == RETRYING);
239
240 // Starting from a "steady state" (stopped or configured) state
241 // should send a start notification.
242 if (state_ == STOPPED || state_ == CONFIGURED)
243 NotifyStart();
244
245 model_association_manager_.Initialize(enabled_types);
246
247 download_types_queue_ = PrioritizeTypes(enabled_types);
248 association_types_queue_ = std::queue<AssociationTypesInfo>();
249
250 // Tell the backend about the new set of data types we wish to sync.
251 // The task will be invoked when updates are downloaded.
252 state_ = DOWNLOAD_PENDING;
253 configurer_->ConfigureDataTypes(
254 reason,
255 BuildDataTypeConfigStateMap(download_types_queue_.front()),
256 base::Bind(&DataTypeManagerImpl::DownloadReady,
257 weak_ptr_factory_.GetWeakPtr(),
258 base::Time::Now(),
259 download_types_queue_.front(),
260 syncer::ModelTypeSet()),
261 base::Bind(&DataTypeManagerImpl::OnDownloadRetry,
262 weak_ptr_factory_.GetWeakPtr()));
263 }
264
GetPriorityTypes() const265 syncer::ModelTypeSet DataTypeManagerImpl::GetPriorityTypes() const {
266 syncer::ModelTypeSet high_priority_types;
267 high_priority_types.PutAll(syncer::PriorityCoreTypes());
268 high_priority_types.PutAll(syncer::PriorityUserTypes());
269 return high_priority_types;
270 }
271
PrioritizeTypes(const syncer::ModelTypeSet & types)272 TypeSetPriorityList DataTypeManagerImpl::PrioritizeTypes(
273 const syncer::ModelTypeSet& types) {
274 syncer::ModelTypeSet high_priority_types = GetPriorityTypes();
275 high_priority_types.RetainAll(types);
276
277 syncer::ModelTypeSet low_priority_types =
278 syncer::Difference(types, high_priority_types);
279
280 TypeSetPriorityList result;
281 if (!high_priority_types.Empty())
282 result.push(high_priority_types);
283 if (!low_priority_types.Empty())
284 result.push(low_priority_types);
285
286 // Could be empty in case of purging for migration, sync nothing, etc.
287 // Configure empty set to purge data from backend.
288 if (result.empty())
289 result.push(syncer::ModelTypeSet());
290
291 return result;
292 }
293
ProcessReconfigure()294 void DataTypeManagerImpl::ProcessReconfigure() {
295 DCHECK(needs_reconfigure_);
296
297 // Wait for current download and association to finish.
298 if (!(download_types_queue_.empty() && association_types_queue_.empty()))
299 return;
300
301 // An attempt was made to reconfigure while we were already configuring.
302 // This can be because a passphrase was accepted or the user changed the
303 // set of desired types. Either way, |last_requested_types_| will contain
304 // the most recent set of desired types, so we just call configure.
305 // Note: we do this whether or not GetControllersNeedingStart is true,
306 // because we may need to stop datatypes.
307 DVLOG(1) << "Reconfiguring due to previous configure attempt occuring while"
308 << " busy.";
309
310 // Note: ConfigureImpl is called directly, rather than posted, in order to
311 // ensure that any purging/unapplying/journaling happens while the set of
312 // failed types is still up to date. If stack unwinding were to be done
313 // via PostTask, the failed data types may be reset before the purging was
314 // performed.
315 state_ = RETRYING;
316 needs_reconfigure_ = false;
317 ConfigureImpl(last_requested_types_, last_configure_reason_);
318 }
319
OnDownloadRetry()320 void DataTypeManagerImpl::OnDownloadRetry() {
321 DCHECK(state_ == DOWNLOAD_PENDING || state_ == CONFIGURING);
322 observer_->OnConfigureRetry();
323 }
324
DownloadReady(base::Time download_start_time,syncer::ModelTypeSet types_to_download,syncer::ModelTypeSet high_priority_types_before,syncer::ModelTypeSet first_sync_types,syncer::ModelTypeSet failed_configuration_types)325 void DataTypeManagerImpl::DownloadReady(
326 base::Time download_start_time,
327 syncer::ModelTypeSet types_to_download,
328 syncer::ModelTypeSet high_priority_types_before,
329 syncer::ModelTypeSet first_sync_types,
330 syncer::ModelTypeSet failed_configuration_types) {
331 DCHECK(state_ == DOWNLOAD_PENDING || state_ == CONFIGURING);
332
333 // Persistence errors are reset after each backend configuration attempt
334 // during which they would have been purged.
335 failed_data_types_handler_->ResetPersistenceErrorsFrom(types_to_download);
336
337 // Ignore |failed_configuration_types| if we need to reconfigure
338 // anyway.
339 if (needs_reconfigure_) {
340 download_types_queue_ = TypeSetPriorityList();
341 ProcessReconfigure();
342 return;
343 }
344
345 if (!failed_configuration_types.Empty()) {
346 if (!unrecoverable_error_method_.is_null())
347 unrecoverable_error_method_.Run();
348 std::string error_msg =
349 "Configuration failed for types " +
350 syncer::ModelTypeSetToString(failed_configuration_types);
351 syncer::SyncError error(FROM_HERE,
352 syncer::SyncError::UNRECOVERABLE_ERROR,
353 error_msg,
354 failed_configuration_types.First().Get());
355 Abort(UNRECOVERABLE_ERROR, error);
356 return;
357 }
358
359 state_ = CONFIGURING;
360
361 // Pop and associate download-ready types.
362 syncer::ModelTypeSet ready_types = types_to_download;
363 download_types_queue_.pop();
364 syncer::ModelTypeSet new_types_to_download;
365 if (!download_types_queue_.empty())
366 new_types_to_download = download_types_queue_.front();
367
368 AssociationTypesInfo association_info;
369 association_info.types = ready_types;
370 association_info.first_sync_types = first_sync_types;
371 association_info.download_start_time = download_start_time;
372 association_info.download_ready_time = base::Time::Now();
373 association_info.high_priority_types_before = high_priority_types_before;
374 association_types_queue_.push(association_info);
375 if (association_types_queue_.size() == 1u)
376 StartNextAssociation();
377
378 // Download types of low priority while configuring types of high priority.
379 if (!new_types_to_download.Empty()) {
380 configurer_->ConfigureDataTypes(
381 last_configure_reason_,
382 BuildDataTypeConfigStateMap(new_types_to_download),
383 base::Bind(&DataTypeManagerImpl::DownloadReady,
384 weak_ptr_factory_.GetWeakPtr(),
385 base::Time::Now(),
386 new_types_to_download,
387 syncer::Union(ready_types, high_priority_types_before)),
388 base::Bind(&DataTypeManagerImpl::OnDownloadRetry,
389 weak_ptr_factory_.GetWeakPtr()));
390 }
391 }
392
StartNextAssociation()393 void DataTypeManagerImpl::StartNextAssociation() {
394 CHECK(!association_types_queue_.empty());
395
396 association_types_queue_.front().association_request_time =
397 base::Time::Now();
398 model_association_manager_.StartAssociationAsync(
399 association_types_queue_.front().types);
400 }
401
OnSingleDataTypeWillStop(syncer::ModelType type)402 void DataTypeManagerImpl::OnSingleDataTypeWillStop(
403 syncer::ModelType type) {
404 configurer_->DeactivateDataType(type);
405 }
406
OnSingleDataTypeAssociationDone(syncer::ModelType type,const syncer::DataTypeAssociationStats & association_stats)407 void DataTypeManagerImpl::OnSingleDataTypeAssociationDone(
408 syncer::ModelType type,
409 const syncer::DataTypeAssociationStats& association_stats) {
410 DCHECK(!association_types_queue_.empty());
411 DataTypeController::TypeMap::const_iterator c_it = controllers_->find(type);
412 DCHECK(c_it != controllers_->end());
413 if (c_it->second->state() == DataTypeController::RUNNING) {
414 // Tell the backend about the change processor for this type so it can
415 // begin routing changes to it.
416 configurer_->ActivateDataType(type, c_it->second->model_safe_group(),
417 c_it->second->GetChangeProcessor());
418 }
419
420 if (!debug_info_listener_.IsInitialized())
421 return;
422
423 AssociationTypesInfo& info = association_types_queue_.front();
424 configuration_stats_.push_back(syncer::DataTypeConfigurationStats());
425 configuration_stats_.back().model_type = type;
426 configuration_stats_.back().association_stats = association_stats;
427 if (info.types.Has(type)) {
428 // Times in |info| only apply to non-slow types.
429 configuration_stats_.back().download_wait_time =
430 info.download_start_time - last_restart_time_;
431 if (info.first_sync_types.Has(type)) {
432 configuration_stats_.back().download_time =
433 info.download_ready_time - info.download_start_time;
434 }
435 configuration_stats_.back().association_wait_time_for_high_priority =
436 info.association_request_time - info.download_ready_time;
437 configuration_stats_.back().high_priority_types_configured_before =
438 info.high_priority_types_before;
439 configuration_stats_.back().same_priority_types_configured_before =
440 info.configured_types;
441 info.configured_types.Put(type);
442 }
443 }
444
OnModelAssociationDone(const DataTypeManager::ConfigureResult & result)445 void DataTypeManagerImpl::OnModelAssociationDone(
446 const DataTypeManager::ConfigureResult& result) {
447 DCHECK(state_ == STOPPING || state_ == CONFIGURING);
448
449 if (state_ == STOPPING)
450 return;
451
452 // Don't reconfigure due to failed data types if we have an unrecoverable
453 // error or have already aborted.
454 if (result.status == PARTIAL_SUCCESS) {
455 if (!result.needs_crypto.Empty()) {
456 needs_reconfigure_ = true;
457 syncer::ModelTypeSet encrypted_types = result.needs_crypto;
458 encrypted_types.RemoveAll(
459 failed_data_types_handler_->GetCryptoErrorTypes());
460 FailedDataTypesHandler::TypeErrorMap crypto_errors =
461 GenerateCryptoErrorsForTypes(encrypted_types);
462 failed_data_types_handler_->UpdateFailedDataTypes(crypto_errors);
463 }
464 if (!result.failed_data_types.empty()) {
465 needs_reconfigure_ = true;
466 failed_data_types_handler_->UpdateFailedDataTypes(
467 result.failed_data_types);
468 }
469 }
470
471 // Ignore abort/unrecoverable error if we need to reconfigure anyways.
472 if (needs_reconfigure_) {
473 association_types_queue_ = std::queue<AssociationTypesInfo>();
474 ProcessReconfigure();
475 return;
476 }
477
478 if (result.status == ABORTED || result.status == UNRECOVERABLE_ERROR) {
479 Abort(result.status, result.failed_data_types.size() >= 1 ?
480 result.failed_data_types.begin()->second :
481 syncer::SyncError());
482 return;
483 }
484
485 DCHECK(result.status == PARTIAL_SUCCESS || result.status == OK);
486 DCHECK(result.status != OK ||
487 (result.needs_crypto.Empty() && result.failed_data_types.empty()));
488
489 // It's possible this is a retry to disable failed types, in which case
490 // the association would be SUCCESS, but the overall configuration should
491 // still be PARTIAL_SUCCESS.
492 syncer::ModelTypeSet failed_data_types =
493 failed_data_types_handler_->GetFailedTypes();
494 ConfigureStatus status = result.status;
495 if (!syncer::Intersection(last_requested_types_,
496 failed_data_types).Empty() && result.status == OK) {
497 status = PARTIAL_SUCCESS;
498 }
499
500 association_types_queue_.pop();
501 if (!association_types_queue_.empty()) {
502 StartNextAssociation();
503 } else if (download_types_queue_.empty()) {
504 state_ = CONFIGURED;
505 ConfigureResult configure_result(status,
506 result.requested_types,
507 failed_data_types_handler_->GetAllErrors(),
508 result.unfinished_data_types,
509 result.needs_crypto);
510 NotifyDone(configure_result);
511 }
512 }
513
Stop()514 void DataTypeManagerImpl::Stop() {
515 if (state_ == STOPPED)
516 return;
517
518 bool need_to_notify =
519 state_ == DOWNLOAD_PENDING || state_ == CONFIGURING;
520 StopImpl();
521
522 if (need_to_notify) {
523 ConfigureResult result(ABORTED,
524 last_requested_types_,
525 std::map<syncer::ModelType, syncer::SyncError>(),
526 syncer::ModelTypeSet(),
527 syncer::ModelTypeSet());
528 NotifyDone(result);
529 }
530 }
531
Abort(ConfigureStatus status,const syncer::SyncError & error)532 void DataTypeManagerImpl::Abort(ConfigureStatus status,
533 const syncer::SyncError& error) {
534 DCHECK(state_ == DOWNLOAD_PENDING || state_ == CONFIGURING);
535
536 StopImpl();
537
538 DCHECK_NE(OK, status);
539 std::map<syncer::ModelType, syncer::SyncError> errors;
540 if (error.IsSet())
541 errors[error.model_type()] = error;
542 ConfigureResult result(status,
543 last_requested_types_,
544 errors,
545 syncer::ModelTypeSet(),
546 syncer::ModelTypeSet());
547 NotifyDone(result);
548 }
549
StopImpl()550 void DataTypeManagerImpl::StopImpl() {
551 state_ = STOPPING;
552
553 // Invalidate weak pointer to drop download callbacks.
554 weak_ptr_factory_.InvalidateWeakPtrs();
555
556 // Stop all data types. This may trigger association callback but the
557 // callback will do nothing because state is set to STOPPING above.
558 model_association_manager_.Stop();
559
560 state_ = STOPPED;
561 }
562
NotifyStart()563 void DataTypeManagerImpl::NotifyStart() {
564 observer_->OnConfigureStart();
565 }
566
NotifyDone(const ConfigureResult & result)567 void DataTypeManagerImpl::NotifyDone(const ConfigureResult& result) {
568 AddToConfigureTime();
569
570 DVLOG(1) << "Total time spent configuring: "
571 << configure_time_delta_.InSecondsF() << "s";
572 switch (result.status) {
573 case DataTypeManager::OK:
574 DVLOG(1) << "NotifyDone called with result: OK";
575 UMA_HISTOGRAM_LONG_TIMES("Sync.ConfigureTime_Long.OK",
576 configure_time_delta_);
577 if (debug_info_listener_.IsInitialized() &&
578 !configuration_stats_.empty()) {
579 debug_info_listener_.Call(
580 FROM_HERE,
581 &syncer::DataTypeDebugInfoListener::OnDataTypeConfigureComplete,
582 configuration_stats_);
583 }
584 configuration_stats_.clear();
585 break;
586 case DataTypeManager::ABORTED:
587 DVLOG(1) << "NotifyDone called with result: ABORTED";
588 UMA_HISTOGRAM_LONG_TIMES("Sync.ConfigureTime_Long.ABORTED",
589 configure_time_delta_);
590 break;
591 case DataTypeManager::UNRECOVERABLE_ERROR:
592 DVLOG(1) << "NotifyDone called with result: UNRECOVERABLE_ERROR";
593 UMA_HISTOGRAM_LONG_TIMES("Sync.ConfigureTime_Long.UNRECOVERABLE_ERROR",
594 configure_time_delta_);
595 break;
596 case DataTypeManager::PARTIAL_SUCCESS:
597 DVLOG(1) << "NotifyDone called with result: PARTIAL_SUCCESS";
598 UMA_HISTOGRAM_LONG_TIMES("Sync.ConfigureTime_Long.PARTIAL_SUCCESS",
599 configure_time_delta_);
600 break;
601 default:
602 NOTREACHED();
603 break;
604 }
605 observer_->OnConfigureDone(result);
606 }
607
state() const608 DataTypeManager::State DataTypeManagerImpl::state() const {
609 return state_;
610 }
611
AddToConfigureTime()612 void DataTypeManagerImpl::AddToConfigureTime() {
613 DCHECK(!last_restart_time_.is_null());
614 configure_time_delta_ += (base::Time::Now() - last_restart_time_);
615 }
616
617 } // namespace browser_sync
618