blob: bf1328cc031e7f9aaaaae854312f2ac6727ddcee [file] [log] [blame]
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core/internal/mediums/ble_v2/advertisement_read_result.h"
#include <algorithm>
#include <vector>
#include "platform/public/mutex_lock.h"
#include "absl/container/flat_hash_set.h"
#include "absl/time/clock.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
const AdvertisementReadResult::Config AdvertisementReadResult::kDefaultConfig{
.backoff_multiplier = 2.0,
.base_backoff_duration = absl::Seconds(1),
.max_backoff_duration = absl::Minutes(5),
};
// Adds a successfully read advertisement for the specified slot to this read
// result. This is fundamentally different from RecordLastReadStatus() because
// we can report a read failure, but still manage to read some advertisements.
void AdvertisementReadResult::AddAdvertisement(std::int32_t slot,
const ByteArray& advertisement) {
MutexLock lock(&mutex_);
// Blindly remove from the advertisements map to make sure any existing
// key-value pair is destroyed.
advertisements_.emplace(slot, advertisement);
}
// Determines whether or not an advertisement was successfully read at the
// specified slot.
bool AdvertisementReadResult::HasAdvertisement(std::int32_t slot) const {
MutexLock lock(&mutex_);
return advertisements_.contains(slot);
}
// Retrieves all raw advertisements that were successfully read.
std::vector<const ByteArray*> AdvertisementReadResult::GetAdvertisements()
const {
MutexLock lock(&mutex_);
std::vector<const ByteArray*> all_advertisements;
all_advertisements.reserve(advertisements_.size());
for (const auto& item : advertisements_) {
all_advertisements.emplace_back(&item.second);
}
return all_advertisements;
}
// Determines what stage we're in for retrying a read from an advertisement
// GATT server.
AdvertisementReadResult::RetryStatus
AdvertisementReadResult::EvaluateRetryStatus() const {
MutexLock lock(&mutex_);
// Check if we have already succeeded reading this advertisement.
if (status_ == Status::kSuccess) {
return RetryStatus::kPreviouslySucceeded;
}
// Check if we have recently failed to read this advertisement.
if (GetDurationSinceReadLocked() < backoff_duration_) {
return RetryStatus::kTooSoon;
}
return RetryStatus::kRetry;
}
// Records the status of the latest read, and updates the next backoff
// duration for subsequent reads. Be sure to also call
// AddAdvertisement() if any advertisements were read.
void AdvertisementReadResult::RecordLastReadStatus(bool is_success) {
MutexLock lock(&mutex_);
// Update the last read timestamp.
last_read_timestamp_ = SystemClock::ElapsedRealtime();
// Update the backoff duration.
if (is_success) {
// Reset the backoff duration now that we had a successful read.
backoff_duration_ = config_.base_backoff_duration;
} else {
// Determine whether or not we were already failing before. If we were, we
// should increase the backoff duration.
if (status_ == Status::kFailure) {
// Use exponential backoff to determine the next backoff duration. This
// simply involves multiplying our current backoff duration by some
// multiplier.
absl::Duration next_backoff_duration =
config_.backoff_multiplier * backoff_duration_;
// Update the backoff duration, making sure not to blow past the
// ceiling.
backoff_duration_ =
std::min(next_backoff_duration, config_.max_backoff_duration);
} else {
// This is our first time failing, so we should only backoff for the
// initial duration.
backoff_duration_ = config_.base_backoff_duration;
}
}
// Update the internal result.
status_ = is_success ? Status::kSuccess : Status::kFailure;
}
// Returns how much time has passed since we last tried reading from an
// advertisement GATT server.
absl::Duration AdvertisementReadResult::GetDurationSinceRead() const {
MutexLock lock(&mutex_);
return GetDurationSinceReadLocked();
}
absl::Duration AdvertisementReadResult::GetDurationSinceReadLocked() const {
return SystemClock::ElapsedRealtime() - last_read_timestamp_;
}
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location