Commit db1d912f authored by Rushan Suleymanov's avatar Rushan Suleymanov Committed by Chromium LUCI CQ

[Sync] Introduce an FCM token list as part of a commit message

The list can be used by the server to send invalidations to other
clients on commit request. The list contains all known FCM tokens from
all active devices known to the client via DeviceInfo data type.

A device is considered active if it sent DeviceInfo specifics within its
pulse time interval (with an additional margin interval).

The list might contain the FCM token of the local device to support
reflections. There is also a limit of the size of the list to restrict
the additional data in a commit request.

The empty list means that there is no known information about all other
clients and the server should decide itself where to send invalidations.
To distinguish the case when there is the only client (which doesn't
expect a reflection invalidation), the client should provide the single
client flag.

Bug: 1164849
Change-Id: I4770091d8e5a577ad9581f899676feeaf381ba97
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2620560Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Commit-Queue: Rushan Suleymanov <rushans@google.com>
Cr-Commit-Position: refs/heads/master@{#843003}
parent 2b5725c3
......@@ -11,17 +11,23 @@
#include "chrome/browser/sync/test/integration/sync_test.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/sync/base/model_type.h"
#include "components/sync/base/time.h"
#include "components/sync/invalidations/switches.h"
#include "components/sync/invalidations/sync_invalidations_service.h"
#include "components/sync/protocol/sync.pb.h"
#include "components/sync/test/fake_server/bookmark_entity_builder.h"
#include "components/sync/test/fake_server/entity_builder_factory.h"
#include "components/sync_device_info/device_info_util.h"
#include "content/public/test/browser_test.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
using bookmarks::BookmarkNode;
using bookmarks_helper::AddFolder;
using bookmarks_helper::GetBookmarkBarNode;
using bookmarks_helper::ServerBookmarksEqualityChecker;
using testing::AllOf;
using testing::ElementsAre;
using testing::Not;
......@@ -76,6 +82,23 @@ MATCHER_P(HasInstanceIdToken, expected_token, "") {
.instance_id_token() == expected_token;
}
sync_pb::DeviceInfoSpecifics CreateDeviceInfoSpecifics(
const std::string& cache_guid,
const std::string& fcm_registration_token) {
sync_pb::DeviceInfoSpecifics specifics;
specifics.set_cache_guid(cache_guid);
specifics.set_client_name("client name");
specifics.set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_LINUX);
specifics.set_sync_user_agent("user agent");
specifics.set_chrome_version("chrome version");
specifics.set_signin_scoped_device_id("scoped device id");
specifics.set_last_updated_timestamp(
syncer::TimeToProtoTime(base::Time::Now()));
specifics.mutable_invalidation_fields()->set_instance_id_token(
fcm_registration_token);
return specifics;
}
class SingleClientWithSyncSendInterestedDataTypesTest : public SyncTest {
public:
SingleClientWithSyncSendInterestedDataTypesTest() : SyncTest(SINGLE_CLIENT) {
......@@ -134,6 +157,24 @@ class SingleClientWithUseSyncInvalidationsTest : public SyncTest {
}
~SingleClientWithUseSyncInvalidationsTest() override = default;
// Injects a test DeviceInfo entity to the fake server.
void InjectDeviceInfoEntityToServer(
const std::string& cache_guid,
const std::string& fcm_registration_token) {
sync_pb::EntitySpecifics specifics;
*specifics.mutable_device_info() =
CreateDeviceInfoSpecifics(cache_guid, fcm_registration_token);
GetFakeServer()->InjectEntity(
syncer::PersistentUniqueClientEntity::CreateFromSpecificsForTesting(
/*non_unique_name=*/"",
/*client_tag=*/
syncer::DeviceInfoUtil::SpecificsToTag(specifics.device_info()),
specifics,
/*creation_time=*/specifics.device_info().last_updated_timestamp(),
/*last_modified_time=*/
specifics.device_info().last_updated_timestamp()));
}
private:
base::test::ScopedFeatureList override_features_;
......@@ -172,6 +213,33 @@ IN_PROC_BROWSER_TEST_F(SingleClientWithUseSyncInvalidationsTest,
.Wait());
}
IN_PROC_BROWSER_TEST_F(SingleClientWithUseSyncInvalidationsTest,
ShouldPopulateFCMRegistrationTokens) {
const std::string kTitle = "title";
const std::string kRemoteDeviceCacheGuid = "other_cache_guid";
const std::string kRemoteFCMRegistrationToken = "other_fcm_token";
// Simulate the case when the server already knows one other device.
InjectDeviceInfoEntityToServer(kRemoteDeviceCacheGuid,
kRemoteFCMRegistrationToken);
ASSERT_TRUE(SetupSync());
// Commit a new bookmark to check if the next commit message has FCM
// registration tokens.
AddFolder(0, GetBookmarkBarNode(0), 0, kTitle);
ASSERT_TRUE(ServerBookmarksEqualityChecker(GetSyncService(0), GetFakeServer(),
{{kTitle, GURL()}},
/*cryptographer=*/nullptr)
.Wait());
sync_pb::ClientToServerMessage message;
GetFakeServer()->GetLastCommitMessage(&message);
EXPECT_THAT(
message.commit().config_params().devices_fcm_registration_tokens(),
ElementsAre(kRemoteFCMRegistrationToken));
}
class SingleClientWithUseSyncInvalidationsForWalletAndOfferTest
: public SyncTest {
public:
......
......@@ -8,22 +8,12 @@
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/stl_util.h"
#include "components/browser_sync/active_devices_provider_impl.h"
#include "components/browser_sync/browser_sync_switches.h"
namespace browser_sync {
// Enables filtering out inactive devices which haven't sent DeviceInfo update
// recently (depending on the device's pulse_interval and an additional margin).
const base::Feature kSyncFilterOutInactiveDevicesForSingleClient{
"SyncFilterOutInactiveDevicesForSingleClient",
base::FEATURE_ENABLED_BY_DEFAULT};
// An additional threshold to consider devices as active. It extends device's
// pulse interval to mitigate possible latency after DeviceInfo commit.
const base::FeatureParam<base::TimeDelta> kSyncActiveDeviceMargin{
&kSyncFilterOutInactiveDevicesForSingleClient, "SyncActiveDeviceMargin",
base::TimeDelta::FromMinutes(30)};
ActiveDevicesProviderImpl::ActiveDevicesProviderImpl(
syncer::DeviceInfoTracker* device_info_tracker,
base::Clock* clock)
......@@ -40,25 +30,43 @@ ActiveDevicesProviderImpl::~ActiveDevicesProviderImpl() {
size_t ActiveDevicesProviderImpl::CountActiveDevicesIfAvailable() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<std::unique_ptr<syncer::DeviceInfo>> all_devices =
device_info_tracker_->GetAllDeviceInfo();
return GetActiveDevices().size();
}
std::vector<std::string>
ActiveDevicesProviderImpl::CollectFCMRegistrationTokensForInvalidations(
const std::string& local_cache_guid) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<std::string> fcm_registration_tokens;
if (!base::FeatureList::IsEnabled(
kSyncFilterOutInactiveDevicesForSingleClient)) {
return all_devices.size();
switches::kSyncUseFCMRegistrationTokensList)) {
return fcm_registration_tokens;
}
size_t active_devices = 0;
for (const auto& device : all_devices) {
const base::Time expected_expiration_time =
device->last_updated_timestamp() + device->pulse_interval() +
kSyncActiveDeviceMargin.Get();
// If the device's expiration time hasn't been reached, then it is
// considered active device.
if (expected_expiration_time > clock_->Now()) {
active_devices++;
for (const std::unique_ptr<syncer::DeviceInfo>& device : GetActiveDevices()) {
if (!local_cache_guid.empty() && device->guid() == local_cache_guid) {
continue;
}
if (device->fcm_registration_token().empty()) {
continue;
}
fcm_registration_tokens.push_back(device->fcm_registration_token());
}
return active_devices;
// Do not send tokens if the list of active devices is huge. This is similar
// to the case when the client doesn't know about other devices, so return an
// empty list. Otherwise the client would return only a part of all active
// clients and other clients might miss an invalidation.
if (fcm_registration_tokens.size() >
static_cast<size_t>(
switches::kSyncFCMRegistrationTokensListMaxSize.Get())) {
return std::vector<std::string>();
}
return fcm_registration_tokens;
}
void ActiveDevicesProviderImpl::SetActiveDevicesChangedCallback(
......@@ -77,4 +85,26 @@ void ActiveDevicesProviderImpl::OnDeviceInfoChange() {
}
}
std::vector<std::unique_ptr<syncer::DeviceInfo>>
ActiveDevicesProviderImpl::GetActiveDevices() const {
std::vector<std::unique_ptr<syncer::DeviceInfo>> all_devices =
device_info_tracker_->GetAllDeviceInfo();
if (!base::FeatureList::IsEnabled(
switches::kSyncFilterOutInactiveDevicesForSingleClient)) {
return all_devices;
}
base::EraseIf(
all_devices, [this](const std::unique_ptr<syncer::DeviceInfo>& device) {
const base::Time expected_expiration_time =
device->last_updated_timestamp() + device->pulse_interval() +
switches::kSyncActiveDeviceMargin.Get();
// If the device's expiration time hasn't been reached, then
// it is considered active device.
return expected_expiration_time <= clock_->Now();
});
return all_devices;
}
} // namespace browser_sync
......@@ -5,6 +5,10 @@
#ifndef COMPONENTS_BROWSER_SYNC_ACTIVE_DEVICES_PROVIDER_IMPL_H_
#define COMPONENTS_BROWSER_SYNC_ACTIVE_DEVICES_PROVIDER_IMPL_H_
#include <memory>
#include <string>
#include <vector>
#include "base/sequence_checker.h"
#include "base/time/default_clock.h"
#include "components/sync/driver/active_devices_provider.h"
......@@ -26,6 +30,9 @@ class ActiveDevicesProviderImpl : public syncer::ActiveDevicesProvider,
// syncer::ActiveDevicesProvider implementation.
size_t CountActiveDevicesIfAvailable() override;
std::vector<std::string> CollectFCMRegistrationTokensForInvalidations(
const std::string& local_cache_guid) override;
void SetActiveDevicesChangedCallback(
ActiveDevicesChangedCallback callback) override;
......@@ -33,6 +40,8 @@ class ActiveDevicesProviderImpl : public syncer::ActiveDevicesProvider,
void OnDeviceInfoChange() override;
private:
std::vector<std::unique_ptr<syncer::DeviceInfo>> GetActiveDevices() const;
syncer::DeviceInfoTracker* const device_info_tracker_;
const base::Clock* const clock_;
ActiveDevicesChangedCallback callback_;
......
......@@ -9,15 +9,19 @@
#include <vector>
#include "base/guid.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/mock_callback.h"
#include "base/test/simple_test_clock.h"
#include "base/time/time.h"
#include "components/browser_sync/browser_sync_switches.h"
#include "components/sync_device_info/device_info_util.h"
#include "components/sync_device_info/fake_device_info_tracker.h"
#include "testing/gtest/include/gtest/gtest.h"
using syncer::DeviceInfo;
using syncer::FakeDeviceInfoTracker;
using testing::IsEmpty;
using testing::UnorderedElementsAre;
namespace browser_sync {
namespace {
......@@ -26,15 +30,15 @@ constexpr int kPulseIntervalMinutes = 60;
std::unique_ptr<DeviceInfo> CreateFakeDeviceInfo(
const std::string& name,
const std::string& fcm_registration_token,
base::Time last_updated_timestamp) {
return std::make_unique<syncer::DeviceInfo>(
base::GenerateGUID(), name, "chrome_version", "user_agent",
sync_pb::SyncEnums::TYPE_UNSET, "device_id", "manufacturer_name",
"model_name", last_updated_timestamp,
base::GUID::GenerateRandomV4().AsLowercaseString(), name,
"chrome_version", "user_agent", sync_pb::SyncEnums::TYPE_UNSET,
"device_id", "manufacturer_name", "model_name", last_updated_timestamp,
base::TimeDelta::FromMinutes(kPulseIntervalMinutes),
/*send_tab_to_self_receiving_enabled=*/false,
/*sharing_info=*/base::nullopt,
/*fcm_registration_token=*/std::string(),
/*sharing_info=*/base::nullopt, fcm_registration_token,
/*interested_data_types=*/syncer::ModelTypeSet());
}
......@@ -45,8 +49,11 @@ class ActiveDevicesProviderImplTest : public testing::Test {
~ActiveDevicesProviderImplTest() override = default;
void AddDevice(const std::string& name, base::Time last_updated_timestamp) {
device_list_.push_back(CreateFakeDeviceInfo(name, last_updated_timestamp));
void AddDevice(const std::string& name,
const std::string& fcm_registration_token,
base::Time last_updated_timestamp) {
device_list_.push_back(CreateFakeDeviceInfo(name, fcm_registration_token,
last_updated_timestamp));
fake_device_info_tracker_.Add(device_list_.back().get());
}
......@@ -58,16 +65,19 @@ class ActiveDevicesProviderImplTest : public testing::Test {
};
TEST_F(ActiveDevicesProviderImplTest, ShouldFilterInactiveDevices) {
AddDevice("device_recent", clock_.Now() - base::TimeDelta::FromMinutes(1));
AddDevice("device_recent", /*fcm_registration_token=*/"",
clock_.Now() - base::TimeDelta::FromMinutes(1));
// Should be considered as active device due to margin even though the device
// is outside the pulse interval.
AddDevice(
"device_pulse_interval",
/*fcm_registration_token=*/"",
clock_.Now() - base::TimeDelta::FromMinutes(kPulseIntervalMinutes + 1));
// Very old device.
AddDevice("device_inactive", clock_.Now() - base::TimeDelta::FromDays(100));
AddDevice("device_inactive", /*fcm_registration_token=*/"",
clock_.Now() - base::TimeDelta::FromDays(100));
EXPECT_EQ(2u, active_devices_provider_.CountActiveDevicesIfAvailable());
}
......@@ -87,5 +97,44 @@ TEST_F(ActiveDevicesProviderImplTest, ShouldInvokeCallback) {
base::RepeatingClosure());
}
TEST_F(ActiveDevicesProviderImplTest, ShouldReturnActiveFCMRegistrationTokens) {
AddDevice("device_1", "fcm_token_1",
clock_.Now() - base::TimeDelta::FromMinutes(1));
AddDevice("device_2", "fcm_token_2",
clock_.Now() - base::TimeDelta::FromMinutes(1));
AddDevice("device_inactive", "fcm_token_3",
clock_.Now() - base::TimeDelta::FromDays(100));
ASSERT_EQ(3u, device_list_.size());
EXPECT_THAT(
active_devices_provider_.CollectFCMRegistrationTokensForInvalidations(
"other_guid"),
UnorderedElementsAre(device_list_[0]->fcm_registration_token(),
device_list_[1]->fcm_registration_token()));
EXPECT_THAT(
active_devices_provider_.CollectFCMRegistrationTokensForInvalidations(
device_list_[0]->guid()),
UnorderedElementsAre(device_list_[1]->fcm_registration_token()));
}
TEST_F(ActiveDevicesProviderImplTest, ShouldReturnEmptyListWhenTooManyDevices) {
// Create many devices to exceed the limit of the list.
const size_t kActiveDevicesNumber =
switches::kSyncFCMRegistrationTokensListMaxSize.Get() + 1;
for (size_t i = 0; i < kActiveDevicesNumber; ++i) {
const std::string device_name = "device_" + base::NumberToString(i);
const std::string fcm_token = "fcm_token_" + device_name;
AddDevice(device_name, fcm_token,
clock_.Now() - base::TimeDelta::FromMinutes(1));
}
EXPECT_THAT(
active_devices_provider_.CollectFCMRegistrationTokensForInvalidations(
"guid"),
IsEmpty());
}
} // namespace
} // namespace browser_sync
......@@ -26,4 +26,27 @@ const base::Feature kSyncUseSessionsUnregisterDelay{
"SyncUseSessionsUnregisterDelay", base::FEATURE_DISABLED_BY_DEFAULT};
#endif // defined(OS_ANDROID)
// Enables filtering out inactive devices which haven't sent DeviceInfo update
// recently (depending on the device's pulse_interval and an additional margin).
const base::Feature kSyncFilterOutInactiveDevicesForSingleClient{
"SyncFilterOutInactiveDevicesForSingleClient",
base::FEATURE_ENABLED_BY_DEFAULT};
// An additional threshold to consider devices as active. It extends device's
// pulse interval to mitigate possible latency after DeviceInfo commit.
const base::FeatureParam<base::TimeDelta> kSyncActiveDeviceMargin{
&kSyncFilterOutInactiveDevicesForSingleClient, "SyncActiveDeviceMargin",
base::TimeDelta::FromMinutes(30)};
// Enables providing the list of FCM registration tokens in the commit request.
const base::Feature kSyncUseFCMRegistrationTokensList{
"SyncUseFCMRegistrationTokensList", base::FEATURE_ENABLED_BY_DEFAULT};
// Max size of FCM registration tokens list. If the number of active devices
// having FCM registration tokens is higher, then the resulting list will be
// empty meaning unknown FCM registration tokens.
const base::FeatureParam<int> kSyncFCMRegistrationTokensListMaxSize{
&kSyncUseFCMRegistrationTokensList, "SyncFCMRegistrationTokensListMaxSize",
5};
} // namespace switches
......@@ -18,6 +18,11 @@ extern const char kLocalSyncBackendDir[];
extern const base::Feature kSyncUseSessionsUnregisterDelay;
#endif
extern const base::Feature kSyncFilterOutInactiveDevicesForSingleClient;
extern const base::FeatureParam<base::TimeDelta> kSyncActiveDeviceMargin;
extern const base::Feature kSyncUseFCMRegistrationTokensList;
extern const base::FeatureParam<int> kSyncFCMRegistrationTokensListMaxSize;
} // namespace switches
#endif // COMPONENTS_BROWSER_SYNC_BROWSER_SYNC_SWITCHES_H_
......@@ -5,11 +5,14 @@
#ifndef COMPONENTS_SYNC_DRIVER_ACTIVE_DEVICES_PROVIDER_H_
#define COMPONENTS_SYNC_DRIVER_ACTIVE_DEVICES_PROVIDER_H_
#include <string>
#include <vector>
#include "base/callback.h"
namespace syncer {
// An interface helping to get the number of active devices. Devices are
// An interface helping to get the information about active devices. Devices are
// considered active if there are DeviceInfo entries that are (typically) less
// than one day old (with a little margin around half an hour).
class ActiveDevicesProvider {
......@@ -22,6 +25,12 @@ class ActiveDevicesProvider {
// known yet (e.g. data types are not configured).
virtual size_t CountActiveDevicesIfAvailable() = 0;
// Returns a list with all remote FCM registration tokens known to the current
// device. If |local_cache_guid| is not empty, then the corresponding device
// will be filtered out.
virtual std::vector<std::string> CollectFCMRegistrationTokensForInvalidations(
const std::string& local_cache_guid) = 0;
// The |callback| will be called on each change in device infos. It might be
// called multiple times with the same number of active devices. The
// |callback| must be cleared before this object is destroyed.
......
......@@ -527,12 +527,16 @@ void SyncEngineBackend::DoOnInvalidationReceived(const std::string& payload) {
}
}
void SyncEngineBackend::DoOnActiveDevicesChanged(size_t active_devices) {
void SyncEngineBackend::DoOnActiveDevicesChanged(
size_t active_devices,
std::vector<std::string> fcm_registration_tokens) {
// If |active_devices| is 0, then current client doesn't know if there are any
// other devices. It's safer to consider that there are some other active
// devices.
const bool single_client = active_devices == 1;
sync_manager_->UpdateSingleClientStatus(single_client);
sync_manager_->UpdateActiveDeviceFCMRegistrationTokens(
std::move(fcm_registration_tokens));
}
void SyncEngineBackend::GetNigoriNodeForDebugging(AllNodesCallback callback) {
......
......@@ -154,8 +154,12 @@ class SyncEngineBackend : public base::RefCountedThreadSafe<SyncEngineBackend>,
bool HasUnsyncedItemsForTest() const;
// Called on each device infos change and might be called more than once with
// the same |active_devices|.
void DoOnActiveDevicesChanged(size_t active_devices);
// the same |active_devices|. |fcm_registration_tokens| contains a list of
// tokens for all known active devices (if available and excluding the local
// device if reflections are disabled).
void DoOnActiveDevicesChanged(
size_t active_devices,
std::vector<std::string> fcm_registration_tokens);
private:
friend class base::RefCountedThreadSafe<SyncEngineBackend>;
......
......@@ -18,6 +18,7 @@
#include "components/invalidation/public/topic_invalidation_map.h"
#include "components/sync/base/bind_to_task_runner.h"
#include "components/sync/base/invalidation_helper.h"
#include "components/sync/base/sync_base_switches.h"
#include "components/sync/base/sync_prefs.h"
#include "components/sync/driver/active_devices_provider.h"
#include "components/sync/driver/glue/sync_engine_backend.h"
......@@ -459,11 +460,19 @@ void SyncEngineImpl::SendInterestedTopicsToInvalidator() {
void SyncEngineImpl::OnActiveDevicesChanged() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::string local_cache_guid;
if (!base::FeatureList::IsEnabled(switches::kSyncE2ELatencyMeasurement)) {
// End-to-end latency measurement relies on reflection, so if this is
// enabled, don't filter out the local device.
local_cache_guid = cached_status_.sync_id;
}
sync_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&SyncEngineBackend::DoOnActiveDevicesChanged, backend_,
active_devices_provider_->CountActiveDevicesIfAvailable()));
base::BindOnce(&SyncEngineBackend::DoOnActiveDevicesChanged, backend_,
active_devices_provider_->CountActiveDevicesIfAvailable(),
active_devices_provider_
->CollectFCMRegistrationTokensForInvalidations(
local_cache_guid)));
}
} // namespace syncer
......@@ -182,6 +182,10 @@ class MockActiveDevicesProvider : public ActiveDevicesProvider {
SetActiveDevicesChangedCallback,
(ActiveDevicesProvider::ActiveDevicesChangedCallback),
(override));
MOCK_METHOD(std::vector<std::string>,
CollectFCMRegistrationTokensForInvalidations,
(const std::string&),
(override));
};
std::unique_ptr<HttpPostProviderFactory> CreateHttpBridgeFactory() {
......
......@@ -243,6 +243,10 @@ class SyncManager {
// Notifies SyncManager that there are no other known active devices.
virtual void UpdateSingleClientStatus(bool single_client) = 0;
// Updates the list of known active device FCM registration tokens.
virtual void UpdateActiveDeviceFCMRegistrationTokens(
std::vector<std::string> fcm_registration_tokens) = 0;
};
} // namespace syncer
......
......@@ -86,14 +86,16 @@ Commit::Commit(ContributionMap contributions,
Commit::~Commit() = default;
// static
std::unique_ptr<Commit> Commit::Init(ModelTypeSet enabled_types,
size_t max_entries,
const std::string& account_name,
const std::string& cache_guid,
bool cookie_jar_mismatch,
bool single_client,
CommitProcessor* commit_processor,
ExtensionsActivity* extensions_activity) {
std::unique_ptr<Commit> Commit::Init(
ModelTypeSet enabled_types,
size_t max_entries,
const std::string& account_name,
const std::string& cache_guid,
bool cookie_jar_mismatch,
bool single_client,
const std::vector<std::string>& fcm_registration_tokens,
CommitProcessor* commit_processor,
ExtensionsActivity* extensions_activity) {
// Gather per-type contributions.
ContributionMap contributions =
commit_processor->GatherCommitContributions(max_entries);
......@@ -124,7 +126,8 @@ std::unique_ptr<Commit> Commit::Init(ModelTypeSet enabled_types,
// Set the client config params.
commit_util::AddClientConfigParamsToMessage(
enabled_types, cookie_jar_mismatch, single_client, commit_message);
enabled_types, cookie_jar_mismatch, single_client,
fcm_registration_tokens, commit_message);
// Finally, serialize all our contributions.
for (const auto& contribution : contributions) {
......
......@@ -10,6 +10,7 @@
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/macros.h"
#include "components/sync/base/extensions_activity.h"
......@@ -45,14 +46,16 @@ class Commit {
~Commit();
// |extensions_activity| may be null.
static std::unique_ptr<Commit> Init(ModelTypeSet enabled_types,
size_t max_entries,
const std::string& account_name,
const std::string& cache_guid,
bool cookie_jar_mismatch,
bool single_client,
CommitProcessor* commit_processor,
ExtensionsActivity* extensions_activity);
static std::unique_ptr<Commit> Init(
ModelTypeSet enabled_types,
size_t max_entries,
const std::string& account_name,
const std::string& cache_guid,
bool cookie_jar_mismatch,
bool single_client,
const std::vector<std::string>& fcm_registration_tokens,
CommitProcessor* commit_processor,
ExtensionsActivity* extensions_activity);
// |extensions_activity| may be null.
SyncerError PostAndProcessResponse(NudgeTracker* nudge_tracker,
......
......@@ -32,10 +32,12 @@ void AddExtensionsActivityToMessage(
}
}
void AddClientConfigParamsToMessage(ModelTypeSet enabled_types,
bool cookie_jar_mismatch,
bool single_client,
sync_pb::CommitMessage* message) {
void AddClientConfigParamsToMessage(
ModelTypeSet enabled_types,
bool cookie_jar_mismatch,
bool single_client,
const std::vector<std::string>& fcm_registration_tokens,
sync_pb::CommitMessage* message) {
sync_pb::ClientConfigParams* config_params = message->mutable_config_params();
for (ModelType type : enabled_types) {
if (ProxyTypes().Has(type))
......@@ -46,6 +48,9 @@ void AddClientConfigParamsToMessage(ModelTypeSet enabled_types,
config_params->set_tabs_datatype_enabled(enabled_types.Has(PROXY_TABS));
config_params->set_cookie_jar_mismatch(cookie_jar_mismatch);
config_params->set_single_client(single_client);
for (const std::string& token : fcm_registration_tokens) {
*config_params->add_devices_fcm_registration_tokens() = token;
}
}
} // namespace commit_util
......
......@@ -6,6 +6,8 @@
#define COMPONENTS_SYNC_ENGINE_IMPL_COMMIT_UTIL_H_
#include <stdint.h>
#include <string>
#include <vector>
#include "components/sync/base/extensions_activity.h"
#include "components/sync/base/model_type.h"
......@@ -26,10 +28,12 @@ void AddExtensionsActivityToMessage(
sync_pb::CommitMessage* message);
// Fills the config_params field of |message|.
void AddClientConfigParamsToMessage(ModelTypeSet enabled_types,
bool cookie_jar_mismatch,
bool single_client,
sync_pb::CommitMessage* message);
void AddClientConfigParamsToMessage(
ModelTypeSet enabled_types,
bool cookie_jar_mismatch,
bool single_client,
const std::vector<std::string>& fcm_registration_tokens,
sync_pb::CommitMessage* message);
} // namespace commit_util
......
......@@ -8,6 +8,7 @@
#include <stdint.h>
#include <string>
#include <utility>
#include <vector>
#include "base/macros.h"
......@@ -121,6 +122,15 @@ class SyncCycleContext {
poll_interval_ = interval;
}
const std::vector<std::string>& active_device_fcm_registration_tokens()
const {
return active_device_fcm_registration_tokens_;
}
void set_active_device_fcm_registration_tokens(
std::vector<std::string> fcm_registration_tokens) {
active_device_fcm_registration_tokens_ = std::move(fcm_registration_tokens);
}
private:
base::ObserverList<SyncEngineEventListener>::Unchecked listeners_;
......@@ -169,6 +179,9 @@ class SyncCycleContext {
// If there are no other known active devices.
bool single_client_;
// A list of FCM registration tokens to send invalidations.
std::vector<std::string> active_device_fcm_registration_tokens_;
base::TimeDelta poll_interval_;
DISALLOW_COPY_AND_ASSIGN(SyncCycleContext);
......
......@@ -568,4 +568,10 @@ void SyncManagerImpl::UpdateSingleClientStatus(bool single_client) {
cycle_context_->set_single_client(single_client);
}
void SyncManagerImpl::UpdateActiveDeviceFCMRegistrationTokens(
std::vector<std::string> fcm_registration_tokens) {
cycle_context_->set_active_device_fcm_registration_tokens(
std::move(fcm_registration_tokens));
}
} // namespace syncer
......@@ -85,6 +85,8 @@ class SyncManagerImpl
void OnCookieJarChanged(bool account_mismatch) override;
void UpdateInvalidationClientId(const std::string& client_id) override;
void UpdateSingleClientStatus(bool single_client) override;
void UpdateActiveDeviceFCMRegistrationTokens(
std::vector<std::string> fcm_registration_tokens) override;
// SyncEncryptionHandler::Observer implementation.
void OnPassphraseRequired(
......
......@@ -150,8 +150,9 @@ SyncerError Syncer::BuildAndPostCommits(const ModelTypeSet& request_types,
cycle->context()->max_commit_batch_size(),
cycle->context()->account_name(), cycle->context()->cache_guid(),
cycle->context()->cookie_jar_mismatch(),
cycle->context()->single_client(), &commit_processor,
cycle->context()->extensions_activity()));
cycle->context()->single_client(),
cycle->context()->active_device_fcm_registration_tokens(),
&commit_processor, cycle->context()->extensions_activity()));
if (!commit) {
break;
}
......
......@@ -447,6 +447,20 @@ message ClientConfigParams {
// the committed data. The client is considered active if it's DeviceInfo has
// updated recent enough.
optional bool single_client = 4;
// A list of FCM registration tokens which are obtained from other clients.
// This list is used by the server to send invalidations to all other clients.
// If the list is empty, the server should treat this as "there is no
// information about other clients". In practice, this happens by the next
// causes:
// 1. This is the old client which doesn't set this field.
// 2. There are too many active devices and the list would have too many
// items.
// 3. An empty list could also mean that the current client is the only
// client. This case should be covered by the |single_client| field instead
// (otherwise it could be mixed up with older clients). The server doesn't
// have to use this field and can ignore it.
repeated string devices_fcm_registration_tokens = 5;
}
message CommitMessage {
......
......@@ -196,4 +196,9 @@ void FakeSyncManager::UpdateSingleClientStatus(bool single_client) {
// Do nothing.
}
void FakeSyncManager::UpdateActiveDeviceFCMRegistrationTokens(
std::vector<std::string> fcm_registration_tokens) {
// Do nothing.
}
} // namespace syncer
......@@ -98,6 +98,8 @@ class FakeSyncManager : public SyncManager {
void OnCookieJarChanged(bool account_mismatch) override;
void UpdateInvalidationClientId(const std::string&) override;
void UpdateSingleClientStatus(bool single_client) override;
void UpdateActiveDeviceFCMRegistrationTokens(
std::vector<std::string> fcm_registration_tokens) override;
private:
scoped_refptr<base::SequencedTaskRunner> sync_task_runner_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment