Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / components / sync_driver / data_type_manager_impl.cc
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
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
44 DataTypeManagerImpl::AssociationTypesInfo::AssociationTypesInfo() {}
45 DataTypeManagerImpl::AssociationTypesInfo::~AssociationTypesInfo() {}
46
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
73 DataTypeManagerImpl::~DataTypeManagerImpl() {}
74
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
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
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
150 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
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
265 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
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
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
320 void DataTypeManagerImpl::OnDownloadRetry() {
321   DCHECK(state_ == DOWNLOAD_PENDING || state_ == CONFIGURING);
322   observer_->OnConfigureRetry();
323 }
324
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
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
402 void DataTypeManagerImpl::OnSingleDataTypeWillStop(
403     syncer::ModelType type) {
404   configurer_->DeactivateDataType(type);
405 }
406
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
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
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
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
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
563 void DataTypeManagerImpl::NotifyStart() {
564   observer_->OnConfigureStart();
565 }
566
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
608 DataTypeManager::State DataTypeManagerImpl::state() const {
609   return state_;
610 }
611
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