blob: 4fbf601bc6a380228a62e59a1ccbddd9203ba706 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/components/tether/ble_advertisement_device_queue.h"
#include <algorithm>
#include "base/logging.h"
#include "base/stl_util.h"
#include "chromeos/services/secure_channel/ble_constants.h"
namespace chromeos {
namespace tether {
BleAdvertisementDeviceQueue::PrioritizedDeviceId::PrioritizedDeviceId(
const std::string& device_id,
const secure_channel::ConnectionPriority& connection_priority)
: device_id(device_id), connection_priority(connection_priority) {}
BleAdvertisementDeviceQueue::PrioritizedDeviceId::~PrioritizedDeviceId() =
default;
BleAdvertisementDeviceQueue::BleAdvertisementDeviceQueue() = default;
BleAdvertisementDeviceQueue::~BleAdvertisementDeviceQueue() = default;
bool BleAdvertisementDeviceQueue::SetPrioritizedDeviceIds(
const std::vector<PrioritizedDeviceId>& prioritized_ids) {
bool devices_inserted =
InsertPrioritizedDeviceIdsIfNecessary(prioritized_ids);
bool devices_removed = RemoveMapEntriesIfNecessary(prioritized_ids);
return devices_inserted || devices_removed;
}
bool BleAdvertisementDeviceQueue::InsertPrioritizedDeviceIdsIfNecessary(
const std::vector<PrioritizedDeviceId>& prioritized_ids) {
bool updated = false;
// For each device provided, check to see if the device is already part of the
// queue. If it is not, add it to the end of the vector associated with the
// device's priority.
for (const auto& priotizied_id : prioritized_ids) {
std::vector<std::string>& device_ids_for_priority =
priority_to_device_ids_map_[priotizied_id.connection_priority];
if (!base::ContainsValue(device_ids_for_priority,
priotizied_id.device_id)) {
device_ids_for_priority.push_back(priotizied_id.device_id);
updated = true;
}
}
return updated;
}
bool BleAdvertisementDeviceQueue::RemoveMapEntriesIfNecessary(
const std::vector<PrioritizedDeviceId>& prioritized_ids) {
bool updated = false;
// Iterate through each priority's device IDs to see if any of the entries
// were not provided as part of the |prioritized_ids| parameter. If any such
// entries exist, remove them from the map.
for (auto& map_entry : priority_to_device_ids_map_) {
secure_channel::ConnectionPriority priority = map_entry.first;
std::vector<std::string>& device_ids_for_priority = map_entry.second;
auto device_ids_it = device_ids_for_priority.begin();
while (device_ids_it != device_ids_for_priority.end()) {
const std::string device_id = *device_ids_it;
// If the device ID in the map also exists in |prioritized_ids|, skip it.
if (std::find_if(prioritized_ids.begin(), prioritized_ids.end(),
[priority, &device_id](auto prioritized_id) {
return prioritized_id.device_id == device_id &&
prioritized_id.connection_priority == priority;
}) != prioritized_ids.end()) {
++device_ids_it;
continue;
}
// The device ID in the map does not exist in |prioritized_ids|. Remove
// it.
device_ids_it = device_ids_for_priority.erase(device_ids_it);
updated = true;
}
}
return updated;
}
void BleAdvertisementDeviceQueue::MoveDeviceToEnd(
const std::string& device_id) {
DCHECK(!device_id.empty());
for (auto& map_entry : priority_to_device_ids_map_) {
std::vector<std::string>& device_ids_for_priority = map_entry.second;
auto device_id_it = std::find(device_ids_for_priority.begin(),
device_ids_for_priority.end(), device_id);
if (device_id_it == device_ids_for_priority.end())
continue;
// Move the element to the end of |device_ids_for_priority|.
std::rotate(device_id_it, device_id_it + 1, device_ids_for_priority.end());
}
}
std::vector<std::string>
BleAdvertisementDeviceQueue::GetDeviceIdsToWhichToAdvertise() const {
std::vector<std::string> device_ids;
AddDevicesToVectorForPriority(secure_channel::ConnectionPriority::kHigh,
&device_ids);
AddDevicesToVectorForPriority(secure_channel::ConnectionPriority::kMedium,
&device_ids);
AddDevicesToVectorForPriority(secure_channel::ConnectionPriority::kLow,
&device_ids);
DCHECK(device_ids.size() <= secure_channel::kMaxConcurrentAdvertisements);
return device_ids;
}
size_t BleAdvertisementDeviceQueue::GetSize() const {
size_t count = 0;
for (const auto& map_entry : priority_to_device_ids_map_)
count += map_entry.second.size();
return count;
}
void BleAdvertisementDeviceQueue::AddDevicesToVectorForPriority(
secure_channel::ConnectionPriority connection_priority,
std::vector<std::string>* device_ids_out) const {
if (priority_to_device_ids_map_.find(connection_priority) ==
priority_to_device_ids_map_.end()) {
// Nothing to do if there is no entry for this priority.
return;
}
const std::vector<std::string>& device_ids_for_priority =
priority_to_device_ids_map_.at(connection_priority);
size_t i = 0;
while (i < device_ids_for_priority.size() &&
device_ids_out->size() <
secure_channel::kMaxConcurrentAdvertisements) {
device_ids_out->push_back(device_ids_for_priority[i]);
++i;
}
}
} // namespace tether
} // namespace chromeos