Home | History | Annotate | Download | only in sync_driver
      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
    618