Commit 4761decd authored by Himanshu Jaju's avatar Himanshu Jaju Committed by Commit Bot

Refactor GetDeviceCandidates

GetDeviceCandidates + RenameDevices had become a bit complicated to understand.
Also, the number of calls to GetDeviceName has been halved (at most once per
device).

Bug: 1014107
Change-Id: I1f5a04f63cef1b3e94b719fc376ae4d47cfbf516
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1865173
Commit-Queue: Himanshu Jaju <himanshujaju@chromium.org>
Reviewed-by: default avatarRichard Knoll <knollr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706528}
parent 1a064aad
...@@ -67,67 +67,61 @@ std::string GetDeviceType(sync_pb::SyncEnums::DeviceType type) { ...@@ -67,67 +67,61 @@ std::string GetDeviceType(sync_pb::SyncEnums::DeviceType type) {
return l10n_util::GetStringUTF8(device_type_message_id); return l10n_util::GetStringUTF8(device_type_message_id);
} }
// Util function to get name for a single device. |is_full_name| determines struct DeviceNames {
// whether we should add the model name for the device. std::string full_name;
std::string GetDeviceName(const syncer::DeviceInfo* device, bool is_full_name) { std::string short_name;
};
// Returns full and short names for |device|.
DeviceNames GetDeviceNames(const syncer::DeviceInfo* device) {
DCHECK(device); DCHECK(device);
DeviceNames device_names;
base::SysInfo::HardwareInfo hardware_info = device->hardware_info(); base::SysInfo::HardwareInfo hardware_info = device->hardware_info();
// The model might be empty if other device is still on M78 or lower with sync // The model might be empty if other device is still on M78 or lower with sync
// turned on. // turned on.
if (hardware_info.model.empty()) if (hardware_info.model.empty()) {
return device->client_name(); device_names.full_name = device_names.short_name = device->client_name();
return device_names;
}
sync_pb::SyncEnums::DeviceType type = device->device_type(); sync_pb::SyncEnums::DeviceType type = device->device_type();
// For chromeOS, return manufacturer + model. // For chromeOS, return manufacturer + model.
if (type == sync_pb::SyncEnums::TYPE_CROS) { if (type == sync_pb::SyncEnums::TYPE_CROS) {
return base::StrCat({device->hardware_info().manufacturer, " ", device_names.short_name = device_names.full_name =
device->hardware_info().model}); base::StrCat({device->hardware_info().manufacturer, " ",
device->hardware_info().model});
return device_names;
} }
if (hardware_info.manufacturer == "Apple Inc.") { if (hardware_info.manufacturer == "Apple Inc.") {
if (is_full_name) // Internal names of Apple devices are formatted as MacbookPro2,3 or
return hardware_info.model; // iPhone2,1 or Ipad4,1.
device_names.short_name = hardware_info.model.substr(
// Returns a more readable hardware model. Internal names of Apple devices
// are formatted as MacbookPro2,3 or iPhone2,1 or Ipad4,1.
return hardware_info.model.substr(
0, hardware_info.model.find_first_of("0123456789,")); 0, hardware_info.model.find_first_of("0123456789,"));
device_names.full_name = hardware_info.model;
return device_names;
} }
std::string device_name = device_names.short_name =
base::StrCat({hardware_info.manufacturer, " ", GetDeviceType(type)}); base::StrCat({hardware_info.manufacturer, " ", GetDeviceType(type)});
if (is_full_name) device_names.full_name =
base::StrAppend(&device_name, {" ", hardware_info.model}); base::StrCat({device_names.short_name, " ", hardware_info.model});
return device_names;
return device_name;
} }
// Util function to rename devices for Sharing. // Clones device with new device name.
std::vector<std::unique_ptr<syncer::DeviceInfo>> RenameDevices( std::unique_ptr<syncer::DeviceInfo> CloneDevice(
const std::vector<std::unique_ptr<syncer::DeviceInfo>>& devices) { const syncer::DeviceInfo* device,
std::map<std::string, int> similar_devices_counter; const std::string& device_name) {
for (const auto& device : devices) return std::make_unique<syncer::DeviceInfo>(
similar_devices_counter[GetDeviceName(device.get(), device->guid(), device_name, device->chrome_version(),
/*is_full_name=*/false)]++; device->sync_user_agent(), device->device_type(),
device->signin_scoped_device_id(), device->hardware_info(),
std::vector<std::unique_ptr<syncer::DeviceInfo>> renamed_devices; device->last_updated_timestamp(),
for (const auto& device : devices) { device->send_tab_to_self_receiving_enabled(), device->sharing_info());
bool is_full_name_required = similar_devices_counter[GetDeviceName(
device.get(), /*is_full_name=*/false)] > 1;
std::string device_name =
GetDeviceName(device.get(), is_full_name_required);
renamed_devices.push_back(std::make_unique<syncer::DeviceInfo>(
device->guid(), device_name, device->chrome_version(),
device->sync_user_agent(), device->device_type(),
device->signin_scoped_device_id(), device->hardware_info(),
device->last_updated_timestamp(),
device->send_tab_to_self_receiving_enabled(), device->sharing_info()));
}
return renamed_devices;
} }
} // namespace } // namespace
...@@ -225,61 +219,16 @@ std::unique_ptr<syncer::DeviceInfo> SharingService::GetDeviceByGuid( ...@@ -225,61 +219,16 @@ std::unique_ptr<syncer::DeviceInfo> SharingService::GetDeviceByGuid(
return device_info_tracker_->GetDeviceInfo(guid); return device_info_tracker_->GetDeviceInfo(guid);
} }
// TODO(crbug.com/1014107) - Simplify this function. The function does a number SharingService::SharingDeviceList SharingService::GetDeviceCandidates(
// of things and some calls are duplicated at the moment.
std::vector<std::unique_ptr<syncer::DeviceInfo>>
SharingService::GetDeviceCandidates(
sync_pb::SharingSpecificFields::EnabledFeatures required_feature) const { sync_pb::SharingSpecificFields::EnabledFeatures required_feature) const {
std::vector<std::unique_ptr<syncer::DeviceInfo>> device_candidates; if (IsSyncDisabled() || !local_device_info_provider_->GetLocalDeviceInfo())
std::vector<std::unique_ptr<syncer::DeviceInfo>> all_devices = return {};
device_info_tracker_->GetAllDeviceInfo();
const syncer::DeviceInfo* local_device_info =
local_device_info_provider_->GetLocalDeviceInfo();
if (IsSyncDisabled() || all_devices.empty() || !local_device_info)
return device_candidates;
const base::Time min_updated_time = base::Time::Now() - kDeviceExpiration;
// Sort the DeviceInfo vector so the most recently modified devices are first.
std::sort(all_devices.begin(), all_devices.end(),
[](const auto& device1, const auto& device2) {
return device1->last_updated_timestamp() >
device2->last_updated_timestamp();
});
std::unordered_set<std::string> full_device_names;
// To prevent adding candidates with same name as local device.
full_device_names.insert(
GetDeviceName(local_device_info, /*is_full_name=*/true));
for (auto& device : all_devices) { SharingDeviceList device_candidates =
// If the current device is considered expired for our purposes, stop here device_info_tracker_->GetAllDeviceInfo();
// since the next devices in the vector are at least as expired than this device_candidates =
// one. FilterDeviceCandidates(std::move(device_candidates), required_feature);
if (device->last_updated_timestamp() < min_updated_time) return RenameAndDeduplicateDevices(std::move(device_candidates));
break;
base::Optional<syncer::DeviceInfo::SharingInfo> sharing_info =
sync_prefs_->GetSharingInfo(device.get());
if (!sharing_info ||
!sharing_info->enabled_features.count(required_feature)) {
continue;
}
// Only insert the first occurrence of each device name.
auto inserted = full_device_names.insert(
GetDeviceName(device.get(), /*is_full_name=*/true));
if (inserted.second)
device_candidates.push_back(std::move(device));
}
// TODO(knollr): Remove devices from |sync_prefs_| that are in
// |synced_devices| but not in |all_devices|?
device_candidates = RenameDevices(device_candidates);
return device_candidates;
} }
void SharingService::AddDeviceCandidatesInitializedObserver( void SharingService::AddDeviceCandidatesInitializedObserver(
...@@ -590,3 +539,76 @@ syncer::ModelTypeSet SharingService::GetRequiredSyncDataTypes() const { ...@@ -590,3 +539,76 @@ syncer::ModelTypeSet SharingService::GetRequiredSyncDataTypes() const {
return required_data_types; return required_data_types;
} }
SharingService::SharingDeviceList SharingService::FilterDeviceCandidates(
SharingDeviceList devices,
sync_pb::SharingSpecificFields::EnabledFeatures required_feature) const {
const base::Time min_updated_time = base::Time::Now() - kDeviceExpiration;
SharingDeviceList filtered_devices;
for (auto& device : devices) {
// Checks if |last_updated_timestamp| is not too old.
if (device->last_updated_timestamp() < min_updated_time)
continue;
// Checks whether |device| supports |required_feature|.
base::Optional<syncer::DeviceInfo::SharingInfo> sharing_info =
sync_prefs_->GetSharingInfo(device.get());
if (!sharing_info ||
!sharing_info->enabled_features.count(required_feature)) {
continue;
}
filtered_devices.push_back(std::move(device));
}
return filtered_devices;
}
SharingService::SharingDeviceList SharingService::RenameAndDeduplicateDevices(
SharingDeviceList devices) const {
// Sort the devices so the most recently modified devices are first.
std::sort(devices.begin(), devices.end(),
[](const auto& device1, const auto& device2) {
return device1->last_updated_timestamp() >
device2->last_updated_timestamp();
});
std::unordered_map<std::string, DeviceNames> device_candidate_names;
std::unordered_set<std::string> full_device_names;
std::unordered_map<std::string, int> short_device_name_counter;
// To prevent adding candidates with same full name as local device.
full_device_names.insert(
GetDeviceNames(local_device_info_provider_->GetLocalDeviceInfo())
.full_name);
for (const auto& device : devices) {
DeviceNames device_names = GetDeviceNames(device.get());
// Only insert the first occurrence of each device name.
auto inserted = full_device_names.insert(device_names.full_name);
if (!inserted.second)
continue;
short_device_name_counter[device_names.short_name]++;
device_candidate_names.insert({device->guid(), std::move(device_names)});
}
// Rename filtered devices.
SharingDeviceList device_candidates;
for (const auto& device : devices) {
auto it = device_candidate_names.find(device->guid());
if (it == device_candidate_names.end())
continue;
const DeviceNames& device_names = it->second;
bool is_short_name_unique =
short_device_name_counter[device_names.short_name] == 1;
device_candidates.push_back(CloneDevice(
device.get(), is_short_name_unique ? device_names.short_name
: device_names.full_name));
}
return device_candidates;
}
...@@ -61,6 +61,7 @@ class SharingService : public KeyedService, ...@@ -61,6 +61,7 @@ class SharingService : public KeyedService,
public: public:
using SendMessageCallback = using SendMessageCallback =
base::OnceCallback<void(SharingSendMessageResult)>; base::OnceCallback<void(SharingSendMessageResult)>;
using SharingDeviceList = std::vector<std::unique_ptr<syncer::DeviceInfo>>;
enum class State { enum class State {
// Device is unregistered with FCM and Sharing is unavailable. // Device is unregistered with FCM and Sharing is unavailable.
...@@ -92,7 +93,7 @@ class SharingService : public KeyedService, ...@@ -92,7 +93,7 @@ class SharingService : public KeyedService,
// Returns a list of DeviceInfo that is available to receive messages. // Returns a list of DeviceInfo that is available to receive messages.
// All returned devices have the specified |required_feature|. // All returned devices have the specified |required_feature|.
virtual std::vector<std::unique_ptr<syncer::DeviceInfo>> GetDeviceCandidates( virtual SharingDeviceList GetDeviceCandidates(
sync_pb::SharingSpecificFields::EnabledFeatures required_feature) const; sync_pb::SharingSpecificFields::EnabledFeatures required_feature) const;
// Register |callback| so it will be invoked after all dependencies of // Register |callback| so it will be invoked after all dependencies of
...@@ -163,6 +164,21 @@ class SharingService : public KeyedService, ...@@ -163,6 +164,21 @@ class SharingService : public KeyedService,
// Returns all required sync data types to enable Sharing feature. // Returns all required sync data types to enable Sharing feature.
syncer::ModelTypeSet GetRequiredSyncDataTypes() const; syncer::ModelTypeSet GetRequiredSyncDataTypes() const;
// Returns list of devices that have |required_feature| enabled. Also
// filters out devices which have not been online for more than
// |SharingConstants::kDeviceExpiration| time.
SharingDeviceList FilterDeviceCandidates(
SharingDeviceList devices,
sync_pb::SharingSpecificFields::EnabledFeatures required_feature) const;
// Deduplicates devices based on client name. For devices with duplicate
// client names, only the most recently updated device is filtered in.
// Returned devices are renamed using the RenameDevice function
// and are sorted in (not strictly) descending order by
// last_updated_timestamp.
SharingDeviceList RenameAndDeduplicateDevices(
SharingDeviceList devices) const;
std::unique_ptr<SharingSyncPreference> sync_prefs_; std::unique_ptr<SharingSyncPreference> sync_prefs_;
std::unique_ptr<VapidKeyManager> vapid_key_manager_; std::unique_ptr<VapidKeyManager> vapid_key_manager_;
std::unique_ptr<SharingDeviceRegistration> sharing_device_registration_; std::unique_ptr<SharingDeviceRegistration> sharing_device_registration_;
......
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