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