blob: 8d7deade4bdf76b866460ac459f2f61ecaf1c79d [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/sync/service/local_data_migration_item_queue.h"
#include "base/time/time.h"
#include "components/sync/base/data_type.h"
#include "components/sync/service/data_type_manager.h"
#include "components/sync/service/sync_service.h"
namespace syncer {
namespace {
// The time limit for activating the data type is set to 50 minutes, as this is
// in line with the `SigninPromoTabHelper` waiting for a sign in event.
constexpr base::TimeDelta kTimeLimitForActivatingDataType = base::Minutes(50);
// Removes items which had been added to the queue before the time limit
// has been exceeded, or have a data type that is non-preferred.
void RemoveExpiredItemsAndItemsOfNonPreferredDataTypes(
std::map<LocalDataItemModel::DataId, std::tuple<DataType, base::Time>>&
items,
const DataTypeSet& preferred_data_types,
const base::Time& current_time_stamp) {
// Use this to keep the items for which the data type is not active yet.
std::map<LocalDataItemModel::DataId, std::tuple<DataType, base::Time>>
items_to_keep;
for (auto& item : items) {
DataType data_type = std::get<0>(item.second);
base::Time initialized_time_stamp = std::get<1>(item.second);
LocalDataItemModel::DataId data_id = item.first;
// Do not include the item if the time limit since the initialization
// of its move has been exceeded. This can happen for example if a user
// with custom passphrase enabled signs in after a sign in promo which
// initializes this queue, but the user still has to enter their
// passphrase. As they may forget that entering their passphrase would
// move the data, we do nothing instead. Also, remove items which have a
// data type which is non-preferred.
if (current_time_stamp - initialized_time_stamp <
kTimeLimitForActivatingDataType &&
preferred_data_types.Has(data_type)) {
items_to_keep[data_id] = std::move(item.second);
}
}
items = std::move(items_to_keep);
}
// Returns those items which have a data type that is active, so that their
// migration to account storage can be triggered. The items for which the data
// type is not active are kept in `items` in case it will be activated later,
// e.g. if the user enters their custom passphrase.
std::map<DataType, std::vector<LocalDataItemModel::DataId>>
MoveItemsOfActiveDataTypesToVector(
std::map<LocalDataItemModel::DataId, std::tuple<DataType, base::Time>>&
items,
const DataTypeSet& active_data_types) {
// Use this to keep the items for which the data type is not active yet.
std::map<LocalDataItemModel::DataId, std::tuple<DataType, base::Time>>
items_to_keep;
// Items that are added here will be migrated to account storage.
std::map<DataType, std::vector<LocalDataItemModel::DataId>> result;
for (auto& item : items) {
DataType data_type = std::get<0>(item.second);
LocalDataItemModel::DataId data_id = item.first;
// Only include those items in the vector for which the data type is already
// active.
if (active_data_types.Has(data_type)) {
result[data_type].push_back(data_id);
} else {
items_to_keep[data_id] = std::move(item.second);
}
}
items = std::move(items_to_keep);
return result;
}
} // namespace
LocalDataMigrationItemQueue::LocalDataMigrationItemQueue(
SyncService* sync_service,
DataTypeManager* data_type_manager)
: sync_service_(sync_service),
data_type_manager_(data_type_manager),
clock_(base::DefaultClock::GetInstance()) {
CHECK(sync_service);
CHECK(data_type_manager);
sync_service_observer_.Observe(sync_service_);
}
LocalDataMigrationItemQueue::~LocalDataMigrationItemQueue() = default;
void LocalDataMigrationItemQueue::
TriggerLocalDataMigrationForItemsWhenTypeBecomesActive(
DataType data_type,
std::vector<LocalDataItemModel::DataId> items) {
base::Time current_timestamp = clock_->Now();
for (const auto& item : items) {
items_[item] = std::tuple(data_type, current_timestamp);
}
// Fire once in case the sync service is already active.
OnStateChanged(sync_service_);
}
void LocalDataMigrationItemQueue::OnStateChanged(SyncService* sync_service) {
CHECK_EQ(sync_service, sync_service_);
// Do not move the data if the user has consented to sync in the meantime. In
// this case, simply leave the data in local storage.
if (sync_service->HasSyncConsent()) {
items_.clear();
return;
}
switch (sync_service->GetTransportState()) {
case SyncService::TransportState::DISABLED:
case SyncService::TransportState::PAUSED: {
items_.clear();
return;
}
case SyncService::TransportState::START_DEFERRED:
case SyncService::TransportState::INITIALIZING:
case SyncService::TransportState::PENDING_DESIRED_CONFIGURATION:
case SyncService::TransportState::CONFIGURING:
// Keep waiting if the sync service is not active yet.
return;
case SyncService::TransportState::ACTIVE:
break;
}
CHECK_EQ(DataTypeManager::CONFIGURED, data_type_manager_->state());
RemoveExpiredItemsAndItemsOfNonPreferredDataTypes(
items_, sync_service->GetPreferredDataTypes(), clock_->Now());
std::map<DataType, std::vector<LocalDataItemModel::DataId>> items_to_migrate =
MoveItemsOfActiveDataTypesToVector(items_,
sync_service->GetActiveDataTypes());
if (items_to_migrate.empty()) {
return;
}
// Use the data type manager directly rather than
// `SyncService::TriggerLocalDataMigration()`, since this object is used for a
// single data item move operation from the sign in promo. This is different
// from batch upload, so we shouldn't record the batch upload histogram in
// that case.
data_type_manager_->TriggerLocalDataMigrationForItems(items_to_migrate);
}
void LocalDataMigrationItemQueue::OnSyncShutdown(SyncService* sync_service) {
items_.clear();
}
void LocalDataMigrationItemQueue::SetClockForTesting(base::Clock* clock) {
clock_ = clock;
}
size_t LocalDataMigrationItemQueue::GetItemsCountForTesting() const {
return items_.size();
}
} // namespace syncer