#include "services/device/geolocation/position_cache_impl.h"
#include "base/ranges/algorithm.h"
#include "base/strings/utf_string_conversions.h"
#include "components/device_event_log/device_event_log.h"
#include "services/device/geolocation/wifi_data.h"
#include "services/device/public/mojom/geoposition.mojom.h"
namespace device {
const size_t PositionCacheImpl::kMaximumSize = 10;
const base::TimeDelta PositionCacheImpl::kMaximumLifetime = base::Days(1);
PositionCacheImpl::CacheEntry::CacheEntry(
const Hash& hash,
mojom::GeopositionPtr position,
std::unique_ptr<base::OneShotTimer> eviction_timer)
: hash_(hash),
position_(std::move(position)),
eviction_timer_(std::move(eviction_timer)) {}
PositionCacheImpl::CacheEntry::~CacheEntry() = default;
PositionCacheImpl::CacheEntry::CacheEntry(CacheEntry&&) = default;
PositionCacheImpl::CacheEntry& PositionCacheImpl::CacheEntry::operator=(
CacheEntry&&) = default;
PositionCacheImpl::Hash PositionCacheImpl::MakeKey(const WifiData& wifi_data) {
std::u16string key;
const size_t kCharsPerMacAddress = 6 * 3 + 1;
key.reserve(wifi_data.access_point_data.size() * kCharsPerMacAddress);
const std::u16string separator(u"|");
for (const auto& access_point_data : wifi_data.access_point_data) {
key += separator;
key += access_point_data.mac_address;
key += separator;
}
return key;
}
PositionCacheImpl::PositionCacheImpl(const base::TickClock* clock)
: clock_(clock) {
net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
}
PositionCacheImpl::~PositionCacheImpl() {
net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
}
void PositionCacheImpl::CachePosition(const WifiData& wifi_data,
const mojom::Geoposition& position) {
const Hash key = MakeKey(wifi_data);
if (data_.size() == kMaximumSize) {
data_.erase(data_.begin());
}
DCHECK_LT(data_.size(), kMaximumSize);
auto eviction_timer = std::make_unique<base::OneShotTimer>(clock_);
eviction_timer->Start(FROM_HERE, kMaximumLifetime,
base::BindOnce(&PositionCacheImpl::EvictEntry,
base::Unretained(this), key));
data_.emplace_back(key, position.Clone(), std::move(eviction_timer));
}
const mojom::Geoposition* PositionCacheImpl::FindPosition(
const WifiData& wifi_data) const {
const Hash key = MakeKey(wifi_data);
auto it = base::ranges::find(data_, key);
return it == data_.end() ? nullptr : (it->position());
}
size_t PositionCacheImpl::GetPositionCacheSize() const {
return data_.size();
}
const mojom::GeopositionResult* PositionCacheImpl::GetLastUsedNetworkPosition()
const {
GEOLOCATION_LOG(DEBUG) << "Get last used network position";
return last_used_result_.get();
}
void PositionCacheImpl::SetLastUsedNetworkPosition(
const mojom::GeopositionResult& result) {
last_used_result_ = result.Clone();
}
void PositionCacheImpl::OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType) {
GEOLOCATION_LOG(DEBUG) << "Network changed";
EvictEntry(MakeKey(WifiData()));
last_used_result_.reset();
}
void PositionCacheImpl::EvictEntry(const Hash& hash) {
data_.erase(std::remove(data_.begin(), data_.end(), hash), data_.end());
}
}