#include "components/browser_sync/active_devices_provider_impl.h"
#include <algorithm>
#include <map>
#include <memory>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "components/browser_sync/browser_sync_switches.h"
#include "components/sync/base/data_type.h"
#include "components/sync/engine/active_devices_invalidation_info.h"
namespace browser_sync {
constexpr size_t kSyncFCMRegistrationTokensListMaxSize = 5;
constexpr base::TimeDelta kSyncActiveDeviceMargin = base::Days(7);
ActiveDevicesProviderImpl::ActiveDevicesProviderImpl(
syncer::DeviceInfoTracker* device_info_tracker,
base::Clock* clock)
: device_info_tracker_(device_info_tracker), clock_(clock) {
DCHECK(device_info_tracker_);
device_info_tracker_observation_.Observe(device_info_tracker_);
}
ActiveDevicesProviderImpl::~ActiveDevicesProviderImpl() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(callback_.is_null());
}
syncer::ActiveDevicesInvalidationInfo
ActiveDevicesProviderImpl::CalculateInvalidationInfo(
const std::string& local_cache_guid) const {
TRACE_EVENT0("ui", "ActiveDevicesProviderImpl::CalculateInvalidationInfo");
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableSyncInvalidationOptimizations)) {
return syncer::ActiveDevicesInvalidationInfo::CreateUninitialized();
}
const std::vector<const syncer::DeviceInfo*> active_devices =
GetActiveDevicesSortedByUpdateTime();
if (active_devices.empty()) {
return syncer::ActiveDevicesInvalidationInfo::CreateUninitialized();
}
std::vector<std::string> all_fcm_registration_tokens;
syncer::DataTypeSet all_interested_data_types;
syncer::DataTypeSet old_invalidations_interested_data_types;
std::map<std::string, syncer::DataTypeSet>
fcm_token_and_interested_data_types;
for (const syncer::DeviceInfo* device : active_devices) {
if (!local_cache_guid.empty() && device->guid() == local_cache_guid) {
continue;
}
all_interested_data_types.PutAll(device->interested_data_types());
if (!device->fcm_registration_token().empty()) {
fcm_token_and_interested_data_types[device->fcm_registration_token()] =
device->interested_data_types();
all_fcm_registration_tokens.push_back(device->fcm_registration_token());
} else if (!device->interested_data_types().empty()) {
old_invalidations_interested_data_types.PutAll(
device->interested_data_types());
} else {
old_invalidations_interested_data_types.PutAll(syncer::ProtocolTypes());
}
}
if (all_fcm_registration_tokens.size() >
kSyncFCMRegistrationTokensListMaxSize) {
all_fcm_registration_tokens.clear();
}
TRACE_EVENT0("ui",
"ActiveDevicesProviderImpl::CalculateInvalidationInfo() => "
"ActiveDevicesInvalidationInfo::Create");
return syncer::ActiveDevicesInvalidationInfo::Create(
std::move(all_fcm_registration_tokens), all_interested_data_types,
std::move(fcm_token_and_interested_data_types),
old_invalidations_interested_data_types);
}
void ActiveDevicesProviderImpl::SetActiveDevicesChangedCallback(
ActiveDevicesChangedCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(callback_.is_null() || callback.is_null());
callback_ = std::move(callback);
}
void ActiveDevicesProviderImpl::OnDeviceInfoChange() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (callback_) {
callback_.Run();
}
}
std::vector<const syncer::DeviceInfo*>
ActiveDevicesProviderImpl::GetActiveDevicesSortedByUpdateTime() const {
std::vector<const syncer::DeviceInfo*> device_infos =
device_info_tracker_->GetAllDeviceInfo();
std::erase_if(device_infos, [this](const syncer::DeviceInfo* device) {
const base::Time expected_expiration_time =
device->last_updated_timestamp() + device->pulse_interval() +
kSyncActiveDeviceMargin;
return !device->chrome_version().empty() &&
expected_expiration_time <= clock_->Now();
});
std::ranges::sort(device_infos, [](const syncer::DeviceInfo* left_device,
const syncer::DeviceInfo* right_device) {
return left_device->last_updated_timestamp() <
right_device->last_updated_timestamp();
});
return device_infos;
}
}