data_type_manager_impl.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  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. #include "components/sync/driver/data_type_manager_impl.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/callback.h"
  10. #include "base/logging.h"
  11. #include "base/metrics/histogram_functions.h"
  12. #include "base/metrics/histogram_macros.h"
  13. #include "base/task/sequenced_task_runner.h"
  14. #include "base/threading/sequenced_task_runner_handle.h"
  15. #include "components/sync/driver/configure_context.h"
  16. #include "components/sync/driver/data_type_encryption_handler.h"
  17. #include "components/sync/driver/data_type_manager_observer.h"
  18. #include "components/sync/driver/data_type_status_table.h"
  19. #include "components/sync/engine/data_type_activation_response.h"
  20. namespace syncer {
  21. namespace {
  22. DataTypeStatusTable::TypeErrorMap GenerateCryptoErrorsForTypes(
  23. ModelTypeSet encrypted_types) {
  24. DataTypeStatusTable::TypeErrorMap crypto_errors;
  25. for (ModelType type : encrypted_types) {
  26. crypto_errors[type] =
  27. SyncError(FROM_HERE, SyncError::CRYPTO_ERROR, "", type);
  28. }
  29. return crypto_errors;
  30. }
  31. ConfigureReason GetReasonForProgrammaticReconfigure(
  32. ConfigureReason original_reason) {
  33. // This reconfiguration can happen within the first configure cycle and in
  34. // this case we want to stick to the original reason -- doing the first sync
  35. // cycle.
  36. return (original_reason == ConfigureReason::CONFIGURE_REASON_NEW_CLIENT)
  37. ? ConfigureReason::CONFIGURE_REASON_NEW_CLIENT
  38. : ConfigureReason::CONFIGURE_REASON_PROGRAMMATIC;
  39. }
  40. // Divides |types| into sets by their priorities and return the sets from
  41. // high priority to low priority.
  42. base::queue<ModelTypeSet> PrioritizeTypes(const ModelTypeSet& types) {
  43. // Control types are usually configured before all other types during
  44. // initialization of sync engine even before data type manager gets
  45. // constructed. However, listing control types here with the highest priority
  46. // makes the behavior consistent also for various flows for restarting sync
  47. // such as migrating all data types or reconfiguring sync in ephemeral mode
  48. // when all local data is wiped.
  49. ModelTypeSet control_types = ControlTypes();
  50. control_types.RetainAll(types);
  51. ModelTypeSet priority_types = PriorityUserTypes();
  52. priority_types.RetainAll(types);
  53. ModelTypeSet regular_types =
  54. Difference(types, Union(control_types, priority_types));
  55. base::queue<ModelTypeSet> result;
  56. if (!control_types.Empty())
  57. result.push(control_types);
  58. if (!priority_types.Empty())
  59. result.push(priority_types);
  60. if (!regular_types.Empty())
  61. result.push(regular_types);
  62. // Could be empty in case of purging for migration, sync nothing, etc.
  63. // Configure empty set to purge data from backend.
  64. if (result.empty())
  65. result.push(ModelTypeSet());
  66. return result;
  67. }
  68. } // namespace
  69. DataTypeManagerImpl::DataTypeManagerImpl(
  70. const DataTypeController::TypeMap* controllers,
  71. const DataTypeEncryptionHandler* encryption_handler,
  72. ModelTypeConfigurer* configurer,
  73. DataTypeManagerObserver* observer)
  74. : configurer_(configurer),
  75. controllers_(controllers),
  76. model_load_manager_(controllers, this),
  77. observer_(observer),
  78. encryption_handler_(encryption_handler) {
  79. DCHECK(configurer_);
  80. DCHECK(observer_);
  81. // This class does not really handle NIGORI (whose controller lives on a
  82. // different thread).
  83. DCHECK_EQ(controllers_->count(NIGORI), 0u);
  84. // Check if any of the controllers are already in a FAILED state, and if so,
  85. // mark them accordingly in the status table.
  86. DataTypeStatusTable::TypeErrorMap existing_errors;
  87. for (const auto& [type, controller] : *controllers_) {
  88. DataTypeController::State state = controller->state();
  89. DCHECK(state == DataTypeController::NOT_RUNNING ||
  90. state == DataTypeController::STOPPING ||
  91. state == DataTypeController::FAILED);
  92. if (state == DataTypeController::FAILED) {
  93. existing_errors[type] =
  94. SyncError(FROM_HERE, SyncError::DATATYPE_ERROR,
  95. "Preexisting controller error on Sync startup", type);
  96. }
  97. }
  98. data_type_status_table_.UpdateFailedDataTypes(existing_errors);
  99. }
  100. DataTypeManagerImpl::~DataTypeManagerImpl() = default;
  101. void DataTypeManagerImpl::Configure(ModelTypeSet preferred_types,
  102. const ConfigureContext& context) {
  103. preferred_types.PutAll(ControlTypes());
  104. ModelTypeSet allowed_types = ControlTypes();
  105. // Add types with controllers.
  106. for (const auto& [type, controller] : *controllers_) {
  107. allowed_types.Put(type);
  108. }
  109. ConfigureImpl(Intersection(preferred_types, allowed_types), context);
  110. }
  111. void DataTypeManagerImpl::DataTypePreconditionChanged(ModelType type) {
  112. if (!UpdatePreconditionError(type)) {
  113. // Nothing changed.
  114. return;
  115. }
  116. switch (controllers_->find(type)->second->GetPreconditionState()) {
  117. case DataTypeController::PreconditionState::kPreconditionsMet:
  118. if (preferred_types_.Has(type)) {
  119. // Only reconfigure if the type is both ready and desired. This will
  120. // internally also update ready state of all other requested types.
  121. ForceReconfiguration();
  122. }
  123. break;
  124. case DataTypeController::PreconditionState::kMustStopAndClearData:
  125. model_load_manager_.StopDatatype(
  126. type, ShutdownReason::DISABLE_SYNC_AND_CLEAR_DATA,
  127. SyncError(FROM_HERE, syncer::SyncError::DATATYPE_POLICY_ERROR,
  128. "Datatype preconditions not met.", type));
  129. break;
  130. case DataTypeController::PreconditionState::kMustStopAndKeepData:
  131. model_load_manager_.StopDatatype(
  132. type, ShutdownReason::STOP_SYNC_AND_KEEP_DATA,
  133. SyncError(FROM_HERE, syncer::SyncError::UNREADY_ERROR,
  134. "Data type is unready.", type));
  135. break;
  136. }
  137. }
  138. void DataTypeManagerImpl::ForceReconfiguration() {
  139. needs_reconfigure_ = true;
  140. last_requested_context_.reason =
  141. GetReasonForProgrammaticReconfigure(last_requested_context_.reason);
  142. ProcessReconfigure();
  143. }
  144. void DataTypeManagerImpl::ResetDataTypeErrors() {
  145. data_type_status_table_.Reset();
  146. }
  147. void DataTypeManagerImpl::PurgeForMigration(ModelTypeSet undesired_types) {
  148. ModelTypeSet remainder = Difference(preferred_types_, undesired_types);
  149. last_requested_context_.reason = CONFIGURE_REASON_MIGRATION;
  150. ConfigureImpl(remainder, last_requested_context_);
  151. }
  152. void DataTypeManagerImpl::ConfigureImpl(ModelTypeSet preferred_types,
  153. const ConfigureContext& context) {
  154. DCHECK_NE(context.reason, CONFIGURE_REASON_UNKNOWN);
  155. DVLOG(1) << "Configuring for " << ModelTypeSetToDebugString(preferred_types)
  156. << " with reason " << context.reason;
  157. if (state_ == STOPPING) {
  158. // You can not set a configuration while stopping.
  159. LOG(ERROR) << "Configuration set while stopping.";
  160. return;
  161. }
  162. if (state_ != STOPPED) {
  163. DCHECK_EQ(context.authenticated_account_id,
  164. last_requested_context_.authenticated_account_id);
  165. DCHECK_EQ(context.cache_guid, last_requested_context_.cache_guid);
  166. }
  167. // TODO(zea): consider not performing a full configuration once there's a
  168. // reliable way to determine if the requested set of enabled types matches the
  169. // current set.
  170. preferred_types_ = preferred_types;
  171. last_requested_context_ = context;
  172. // Only proceed if we're in a steady state or retrying.
  173. if (state_ != STOPPED && state_ != CONFIGURED && state_ != RETRYING) {
  174. DVLOG(1) << "Received configure request while configuration in flight. "
  175. << "Postponing until current configuration complete.";
  176. needs_reconfigure_ = true;
  177. return;
  178. }
  179. Restart();
  180. }
  181. void DataTypeManagerImpl::ConnectDataTypes() {
  182. for (ModelType type : preferred_types_without_errors_) {
  183. auto dtc_iter = controllers_->find(type);
  184. if (dtc_iter == controllers_->end()) {
  185. continue;
  186. }
  187. DataTypeController* dtc = dtc_iter->second.get();
  188. if (dtc->state() != DataTypeController::MODEL_LOADED) {
  189. continue;
  190. }
  191. // Only call Connect() for types that completed LoadModels()
  192. // successfully. Such types shouldn't be in an error state at the same
  193. // time.
  194. DCHECK(!data_type_status_table_.GetFailedTypes().Has(dtc->type()));
  195. std::unique_ptr<DataTypeActivationResponse> activation_response =
  196. dtc->Connect();
  197. DCHECK(activation_response);
  198. DCHECK_EQ(dtc->state(), DataTypeController::RUNNING);
  199. if (activation_response->skip_engine_connection) {
  200. // |skip_engine_connection| means ConnectDataType() shouldn't be invoked
  201. // because the datatype has some alternative way to sync changes to the
  202. // server, without relying on this instance of the sync engine. This is
  203. // currently possible for PROXY_TABS and, on Android, for PASSWORDS.
  204. DCHECK(!activation_response->type_processor);
  205. downloaded_types_.Put(type);
  206. configured_proxy_types_.Put(type);
  207. continue;
  208. }
  209. if (activation_response->model_type_state.initial_sync_done()) {
  210. downloaded_types_.Put(type);
  211. } else {
  212. downloaded_types_.Remove(type);
  213. }
  214. if (force_redownload_types_.Has(type)) {
  215. downloaded_types_.Remove(type);
  216. }
  217. configurer_->ConnectDataType(type, std::move(activation_response));
  218. }
  219. }
  220. // static
  221. ModelTypeSet DataTypeManagerImpl::GetDataTypesInState(
  222. DataTypeConfigState state,
  223. const DataTypeConfigStateMap& state_map) {
  224. ModelTypeSet types;
  225. for (const auto& [type, config_state] : state_map) {
  226. if (config_state == state)
  227. types.Put(type);
  228. }
  229. return types;
  230. }
  231. // static
  232. void DataTypeManagerImpl::SetDataTypesState(DataTypeConfigState state,
  233. ModelTypeSet types,
  234. DataTypeConfigStateMap* state_map) {
  235. for (ModelType type : types) {
  236. (*state_map)[type] = state;
  237. }
  238. }
  239. DataTypeManagerImpl::DataTypeConfigStateMap
  240. DataTypeManagerImpl::BuildDataTypeConfigStateMap(
  241. const ModelTypeSet& types_being_configured) const {
  242. // 1. Get the failed types (due to fatal, crypto, and unready errors).
  243. // 2. Add the difference between preferred_types_ and the failed types as
  244. // CONFIGURE_INACTIVE.
  245. // 3. Flip |types_being_configured| to CONFIGURE_ACTIVE.
  246. // 4. Set non-enabled user types as DISABLED.
  247. // 5. Set the fatal, crypto, and unready types to their respective states.
  248. const ModelTypeSet fatal_types = data_type_status_table_.GetFatalErrorTypes();
  249. const ModelTypeSet crypto_types =
  250. data_type_status_table_.GetCryptoErrorTypes();
  251. // Types with unready errors do not count as unready if they've been disabled.
  252. const ModelTypeSet unready_types = Intersection(
  253. data_type_status_table_.GetUnreadyErrorTypes(), preferred_types_);
  254. const ModelTypeSet enabled_types = GetEnabledTypes();
  255. const ModelTypeSet disabled_types =
  256. Difference(Union(UserTypes(), ControlTypes()), enabled_types);
  257. const ModelTypeSet to_configure =
  258. Intersection(enabled_types, types_being_configured);
  259. DVLOG(1) << "Enabling: " << ModelTypeSetToDebugString(enabled_types);
  260. DVLOG(1) << "Configuring: " << ModelTypeSetToDebugString(to_configure);
  261. DVLOG(1) << "Disabling: " << ModelTypeSetToDebugString(disabled_types);
  262. DataTypeConfigStateMap config_state_map;
  263. SetDataTypesState(CONFIGURE_INACTIVE, enabled_types, &config_state_map);
  264. SetDataTypesState(CONFIGURE_ACTIVE, to_configure, &config_state_map);
  265. SetDataTypesState(DISABLED, disabled_types, &config_state_map);
  266. SetDataTypesState(FATAL, fatal_types, &config_state_map);
  267. SetDataTypesState(CRYPTO, crypto_types, &config_state_map);
  268. SetDataTypesState(UNREADY, unready_types, &config_state_map);
  269. return config_state_map;
  270. }
  271. void DataTypeManagerImpl::Restart() {
  272. DVLOG(1) << "Restarting...";
  273. const ConfigureReason reason = last_requested_context_.reason;
  274. // Only record the type histograms for user-triggered configurations or
  275. // restarts.
  276. if (reason == CONFIGURE_REASON_RECONFIGURATION ||
  277. reason == CONFIGURE_REASON_NEW_CLIENT ||
  278. reason == CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE) {
  279. for (ModelType type : preferred_types_) {
  280. UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureDataTypes",
  281. ModelTypeHistogramValue(type));
  282. }
  283. }
  284. // Check for new or resolved data type crypto errors.
  285. if (encryption_handler_->HasCryptoError()) {
  286. ModelTypeSet encrypted_types = encryption_handler_->GetEncryptedDataTypes();
  287. encrypted_types.RetainAll(preferred_types_);
  288. encrypted_types.RemoveAll(data_type_status_table_.GetCryptoErrorTypes());
  289. DataTypeStatusTable::TypeErrorMap crypto_errors =
  290. GenerateCryptoErrorsForTypes(encrypted_types);
  291. data_type_status_table_.UpdateFailedDataTypes(crypto_errors);
  292. } else {
  293. data_type_status_table_.ResetCryptoErrors();
  294. }
  295. UpdatePreconditionErrors(preferred_types_);
  296. last_restart_time_ = base::Time::Now();
  297. DCHECK(state_ == STOPPED || state_ == CONFIGURED || state_ == RETRYING);
  298. const State old_state = state_;
  299. state_ = CONFIGURING;
  300. // Starting from a "steady state" (stopped or configured) state
  301. // should send a start notification.
  302. // Note: NotifyStart() must be called with the updated (non-idle) state,
  303. // otherwise logic listening for the configuration start might not be aware
  304. // of the fact that the DTM is in a configuration state.
  305. if (old_state == STOPPED || old_state == CONFIGURED)
  306. NotifyStart();
  307. // Compute `preferred_types_without_errors_` after NotifyStart() to be sure to
  308. // provide consistent values to ModelLoadManager. (Namely, observers may
  309. // trigger another reconfiguration which may change the value of
  310. // `preferred_types_`.)
  311. preferred_types_without_errors_ = GetEnabledTypes();
  312. configuration_types_queue_ = PrioritizeTypes(preferred_types_without_errors_);
  313. model_load_manager_.Initialize(
  314. /*preferred_types_without_errors=*/preferred_types_without_errors_,
  315. /*preferred_types=*/preferred_types_, last_requested_context_);
  316. }
  317. void DataTypeManagerImpl::OnAllDataTypesReadyForConfigure() {
  318. // If a reconfigure was requested while the data types were loading, process
  319. // it now.
  320. if (needs_reconfigure_) {
  321. configuration_types_queue_ = base::queue<ModelTypeSet>();
  322. ProcessReconfigure();
  323. return;
  324. }
  325. // TODO(pavely): By now some of datatypes in |configuration_types_queue_|
  326. // could have failed loading and should be excluded from configuration. I need
  327. // to adjust |configuration_types_queue_| for such types.
  328. ConnectDataTypes();
  329. // Propagate the state of PROXY_TABS to the sync engine.
  330. auto dtc_iter = controllers_->find(PROXY_TABS);
  331. if (dtc_iter != controllers_->end()) {
  332. configurer_->SetProxyTabsDatatypeEnabled(dtc_iter->second->state() ==
  333. DataTypeController::RUNNING);
  334. }
  335. StartNextConfiguration();
  336. }
  337. void DataTypeManagerImpl::UpdatePreconditionErrors(
  338. const ModelTypeSet& desired_types) {
  339. for (ModelType type : desired_types) {
  340. UpdatePreconditionError(type);
  341. }
  342. }
  343. bool DataTypeManagerImpl::UpdatePreconditionError(ModelType type) {
  344. auto iter = controllers_->find(type);
  345. if (iter == controllers_->end())
  346. return false;
  347. switch (iter->second->GetPreconditionState()) {
  348. case DataTypeController::PreconditionState::kPreconditionsMet: {
  349. const bool data_type_policy_error_changed =
  350. data_type_status_table_.ResetDataTypePolicyErrorFor(type);
  351. const bool unready_status_changed =
  352. data_type_status_table_.ResetUnreadyErrorFor(type);
  353. if (!data_type_policy_error_changed && !unready_status_changed) {
  354. // Nothing changed.
  355. return false;
  356. }
  357. // If preconditions are newly met, the datatype should be immediately
  358. // redownloaded as part of the datatype configuration (most relevant for
  359. // the UNREADY_ERROR case which usually won't clear sync metadata).
  360. force_redownload_types_.Put(type);
  361. return true;
  362. }
  363. case DataTypeController::PreconditionState::kMustStopAndClearData: {
  364. return data_type_status_table_.UpdateFailedDataType(
  365. type, SyncError(FROM_HERE, SyncError::DATATYPE_POLICY_ERROR,
  366. "Datatype preconditions not met.", type));
  367. }
  368. case DataTypeController::PreconditionState::kMustStopAndKeepData: {
  369. return data_type_status_table_.UpdateFailedDataType(
  370. type, SyncError(FROM_HERE, SyncError::UNREADY_ERROR,
  371. "Datatype not ready at config time.", type));
  372. }
  373. }
  374. NOTREACHED();
  375. return false;
  376. }
  377. void DataTypeManagerImpl::ProcessReconfigure() {
  378. // This may have been called asynchronously; no-op if it is no longer needed.
  379. if (!needs_reconfigure_) {
  380. return;
  381. }
  382. // Wait for current configuration to finish.
  383. if (!configuration_types_queue_.empty()) {
  384. return;
  385. }
  386. // An attempt was made to reconfigure while we were already configuring.
  387. // This can be because a passphrase was accepted or the user changed the
  388. // set of desired types. Either way, |preferred_types_| will contain the most
  389. // recent set of desired types, so we just call configure.
  390. // Note: we do this whether or not GetControllersNeedingStart is true,
  391. // because we may need to stop datatypes.
  392. DVLOG(1) << "Reconfiguring due to previous configure attempt occurring while"
  393. << " busy.";
  394. // Note: ConfigureImpl is called directly, rather than posted, in order to
  395. // ensure that any purging happens while the set of failed types is still up
  396. // to date. If stack unwinding were to be done via PostTask, the failed data
  397. // types may be reset before the purging was performed.
  398. state_ = RETRYING;
  399. needs_reconfigure_ = false;
  400. ConfigureImpl(preferred_types_, last_requested_context_);
  401. }
  402. void DataTypeManagerImpl::ConfigurationCompleted(
  403. ModelTypeSet succeeded_configuration_types,
  404. ModelTypeSet failed_configuration_types) {
  405. // |succeeded_configuration_types| are the types that were actually downloaded
  406. // just now.
  407. DCHECK_EQ(CONFIGURING, state_);
  408. if (!failed_configuration_types.Empty()) {
  409. DataTypeStatusTable::TypeErrorMap errors;
  410. for (ModelType type : failed_configuration_types) {
  411. SyncError error(FROM_HERE, SyncError::DATATYPE_ERROR,
  412. "Backend failed to download and configure type.", type);
  413. errors[type] = error;
  414. }
  415. data_type_status_table_.UpdateFailedDataTypes(errors);
  416. needs_reconfigure_ = true;
  417. }
  418. // If a reconfigure was requested while this configuration was ongoing,
  419. // process it now.
  420. if (needs_reconfigure_) {
  421. configuration_types_queue_ = base::queue<ModelTypeSet>();
  422. ProcessReconfigure();
  423. return;
  424. }
  425. DCHECK(!configuration_types_queue_.empty());
  426. configuration_types_queue_.pop();
  427. if (configuration_types_queue_.empty()) {
  428. state_ = CONFIGURED;
  429. NotifyDone(ConfigureResult(OK, preferred_types_));
  430. return;
  431. }
  432. StartNextConfiguration();
  433. }
  434. void DataTypeManagerImpl::StartNextConfiguration() {
  435. if (configuration_types_queue_.empty())
  436. return;
  437. // The engine's state was initially derived from the types detected to have
  438. // been downloaded in the database. Afterwards it is modified only by this
  439. // function. We expect |downloaded_types_| to remain consistent because
  440. // configuration requests are never aborted; they are retried until they
  441. // succeed or the engine is shut down.
  442. //
  443. // Only one configure is allowed at a time. This is guaranteed by our callers.
  444. // The sync engine requests one configure as it is initializing and waits for
  445. // it to complete. After engine initialization, all configurations pass
  446. // through the DataTypeManager, and we are careful to never send a new
  447. // configure request until the current request succeeds.
  448. configurer_->ConfigureDataTypes(PrepareConfigureParams());
  449. }
  450. ModelTypeConfigurer::ConfigureParams
  451. DataTypeManagerImpl::PrepareConfigureParams() {
  452. // Divide up the types into their corresponding actions:
  453. // - Types which are newly enabled are downloaded.
  454. // - Types which have encountered a cryptographer error (crypto_types) are
  455. // unapplied (local state is purged but sync state is not).
  456. // - All types not in the routing info (types just disabled) are deleted.
  457. // - Everything else (enabled types and already disabled types) is not
  458. // touched.
  459. const DataTypeConfigStateMap config_state_map =
  460. BuildDataTypeConfigStateMap(configuration_types_queue_.front());
  461. const ModelTypeSet fatal_types = GetDataTypesInState(FATAL, config_state_map);
  462. const ModelTypeSet crypto_types =
  463. GetDataTypesInState(CRYPTO, config_state_map);
  464. const ModelTypeSet unready_types =
  465. GetDataTypesInState(UNREADY, config_state_map);
  466. const ModelTypeSet active_types =
  467. GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map);
  468. const ModelTypeSet inactive_types =
  469. GetDataTypesInState(CONFIGURE_INACTIVE, config_state_map);
  470. ModelTypeSet disabled_types = GetDataTypesInState(DISABLED, config_state_map);
  471. disabled_types.PutAll(fatal_types);
  472. disabled_types.PutAll(crypto_types);
  473. disabled_types.PutAll(unready_types);
  474. DCHECK(Intersection(active_types, disabled_types).Empty());
  475. ModelTypeSet types_to_download = Difference(active_types, downloaded_types_);
  476. // Commit-only types never require downloading.
  477. types_to_download.RemoveAll(CommitOnlyTypes());
  478. if (!types_to_download.Empty()) {
  479. types_to_download.PutAll(ControlTypes());
  480. }
  481. // All types to download are expected to be protocol types (proxy types should
  482. // have skipped full activation via
  483. // |DataTypeActivationResponse::skip_engine_connection|).
  484. DCHECK(ProtocolTypes().HasAll(types_to_download));
  485. // Already (optimistically) update the |downloaded_types_|, so that the next
  486. // time we get here, it has the correct value.
  487. downloaded_types_.PutAll(active_types);
  488. // Assume that disabled types are not downloaded anymore - if they get
  489. // re-enabled, we'll want to re-download them as well.
  490. downloaded_types_.RemoveAll(disabled_types);
  491. force_redownload_types_.RemoveAll(types_to_download);
  492. ModelTypeSet types_to_purge;
  493. // If we're using transport-only mode, don't clear any old data. The reason is
  494. // that if a user temporarily disables Sync, we don't want to wipe (and later
  495. // redownload) all their data, just because Sync restarted in transport-only
  496. // mode.
  497. // TODO(crbug.com/1142771): "Purging" logic is only implemented for NIGORI -
  498. // verify whether it is actually needed at all.
  499. if (last_requested_context_.sync_mode == SyncMode::kFull) {
  500. types_to_purge = Difference(ModelTypeSet::All(), downloaded_types_);
  501. types_to_purge.RemoveAll(inactive_types);
  502. types_to_purge.RemoveAll(unready_types);
  503. }
  504. DCHECK(Intersection(active_types, types_to_purge).Empty());
  505. DCHECK(Intersection(downloaded_types_, crypto_types).Empty());
  506. // |downloaded_types_| was already updated to include all enabled types.
  507. DCHECK(downloaded_types_.HasAll(types_to_download));
  508. DVLOG(1) << "Types " << ModelTypeSetToDebugString(types_to_download)
  509. << " added; calling ConfigureDataTypes";
  510. ModelTypeConfigurer::ConfigureParams params;
  511. params.reason = last_requested_context_.reason;
  512. params.to_download = types_to_download;
  513. params.to_purge = types_to_purge;
  514. params.ready_task =
  515. base::BindOnce(&DataTypeManagerImpl::ConfigurationCompleted,
  516. weak_ptr_factory_.GetWeakPtr());
  517. params.is_sync_feature_enabled =
  518. last_requested_context_.sync_mode == SyncMode::kFull;
  519. return params;
  520. }
  521. void DataTypeManagerImpl::OnSingleDataTypeWillStop(ModelType type,
  522. const SyncError& error) {
  523. // No-op if the type is not connected.
  524. configurer_->DisconnectDataType(type);
  525. configured_proxy_types_.Remove(type);
  526. if (error.IsSet()) {
  527. data_type_status_table_.UpdateFailedDataType(type, error);
  528. needs_reconfigure_ = true;
  529. last_requested_context_.reason =
  530. GetReasonForProgrammaticReconfigure(last_requested_context_.reason);
  531. // Do this asynchronously so the ModelLoadManager has a chance to
  532. // finish stopping this type, otherwise Disconnect() and Stop()
  533. // end up getting called twice on the controller.
  534. base::SequencedTaskRunnerHandle::Get()->PostTask(
  535. FROM_HERE, base::BindOnce(&DataTypeManagerImpl::ProcessReconfigure,
  536. weak_ptr_factory_.GetWeakPtr()));
  537. }
  538. }
  539. void DataTypeManagerImpl::Stop(ShutdownReason reason) {
  540. if (state_ == STOPPED)
  541. return;
  542. bool need_to_notify = state_ == CONFIGURING;
  543. StopImpl(reason);
  544. if (need_to_notify) {
  545. ConfigureResult result(ABORTED, preferred_types_);
  546. NotifyDone(result);
  547. }
  548. }
  549. void DataTypeManagerImpl::StopImpl(ShutdownReason reason) {
  550. state_ = STOPPING;
  551. // Invalidate weak pointer to drop configuration callbacks.
  552. weak_ptr_factory_.InvalidateWeakPtrs();
  553. // Stop all data types.
  554. model_load_manager_.Stop(reason);
  555. // Individual data type controllers might still be STOPPING, but we don't
  556. // reflect that in |state_| because, for all practical matters, the manager is
  557. // in a ready state and reconfguration can be triggered.
  558. // TODO(mastiz): Reconsider waiting in STOPPING state until all datatypes have
  559. // stopped.
  560. state_ = STOPPED;
  561. }
  562. void DataTypeManagerImpl::NotifyStart() {
  563. observer_->OnConfigureStart();
  564. }
  565. void DataTypeManagerImpl::NotifyDone(const ConfigureResult& raw_result) {
  566. DCHECK(!last_restart_time_.is_null());
  567. base::TimeDelta configure_time = base::Time::Now() - last_restart_time_;
  568. ConfigureResult result = raw_result;
  569. result.data_type_status_table = data_type_status_table_;
  570. const std::string prefix_uma =
  571. (last_requested_context_.reason == CONFIGURE_REASON_NEW_CLIENT)
  572. ? "Sync.ConfigureTime_Initial"
  573. : "Sync.ConfigureTime_Subsequent";
  574. DVLOG(1) << "Total time spent configuring: " << configure_time.InSecondsF()
  575. << "s";
  576. switch (result.status) {
  577. case DataTypeManager::OK:
  578. DVLOG(1) << "NotifyDone called with result: OK";
  579. base::UmaHistogramLongTimes(prefix_uma + ".OK", configure_time);
  580. break;
  581. case DataTypeManager::ABORTED:
  582. DVLOG(1) << "NotifyDone called with result: ABORTED";
  583. base::UmaHistogramLongTimes(prefix_uma + ".ABORTED", configure_time);
  584. break;
  585. case DataTypeManager::UNKNOWN:
  586. NOTREACHED();
  587. break;
  588. }
  589. observer_->OnConfigureDone(result);
  590. }
  591. ModelTypeSet DataTypeManagerImpl::GetActiveDataTypes() const {
  592. if (state_ != CONFIGURED)
  593. return ModelTypeSet();
  594. return GetEnabledTypes();
  595. }
  596. ModelTypeSet DataTypeManagerImpl::GetPurgedDataTypes() const {
  597. ModelTypeSet purged_types;
  598. for (const auto& [type, controller] : *controllers_) {
  599. // TODO(crbug.com/897628): NOT_RUNNING doesn't necessarily mean the sync
  600. // metadata was cleared, if KEEP_METADATA was used when stopping.
  601. if (controller->state() == DataTypeController::NOT_RUNNING) {
  602. purged_types.Put(type);
  603. }
  604. }
  605. return purged_types;
  606. }
  607. ModelTypeSet DataTypeManagerImpl::GetActiveProxyDataTypes() const {
  608. if (state_ != CONFIGURED) {
  609. return ModelTypeSet();
  610. }
  611. return configured_proxy_types_;
  612. }
  613. DataTypeManager::State DataTypeManagerImpl::state() const {
  614. return state_;
  615. }
  616. ModelTypeSet DataTypeManagerImpl::GetEnabledTypes() const {
  617. return Difference(preferred_types_, data_type_status_table_.GetFailedTypes());
  618. }
  619. } // namespace syncer