blob: 6878e260a0799f65dd1ad40a7bd39301cb18c1af [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* 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
*
* http://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 "location/lbs/contexthub/nanoapps/nearby/adv_report_cache.h"
#include <utility>
#include "chre_api/chre.h"
#include "third_party/contexthub/chre/util/include/chre/util/nanoapp/log.h"
#define LOG_TAG "[NEARBY][ADV_CACHE]"
namespace nearby {
void AdvReportCache::Clear() {
// Release all resources.
for (const auto &report : cache_reports_) {
if (report.dataLength == 0) {
continue;
}
chreHeapFree(const_cast<uint8_t *>(report.data));
}
cache_reports_.clear();
}
void AdvReportCache::Refresh() {
if (cache_expire_nanosec_ == kMaxExpireTimeNanoSec) {
return;
}
uint64_t current_time = chreGetTime();
size_t index = 0;
while (index < cache_reports_.size()) {
if (current_time - cache_reports_[index].timestamp >
cache_expire_nanosec_) {
// TODO(b/285043291): Refactor cache element by wrapper struct/class
// which deallocates data in its destructor.
chreHeapFree(const_cast<uint8_t *>(cache_reports_[index].data));
// The index does not need to increase because the current element is
// replaced by the end of the element and the list is resized.
cache_reports_.swap(index, cache_reports_.size() - 1);
cache_reports_.resize(cache_reports_.size() - 1);
} else {
++index;
}
}
}
void AdvReportCache::RefreshIfNeeded() {
if (cache_reports_.size() > kRefreshCacheCountThreshold) {
Refresh();
}
}
void AdvReportCache::Push(const chreBleAdvertisingReport &event_report) {
#ifdef NEARBY_PROFILE
ashProfileBegin(&profile_data_);
#endif
bool is_duplicate = false;
for (auto &cache_report : cache_reports_) {
if (cache_report.addressType == event_report.addressType &&
memcmp(cache_report.address, event_report.address,
CHRE_BLE_ADDRESS_LEN) == 0 &&
cache_report.dataLength == event_report.dataLength &&
memcmp(cache_report.data, event_report.data, cache_report.dataLength) ==
0) {
// Updates RSSI by max value in the duplicated report.
if (cache_report.rssi == CHRE_BLE_RSSI_NONE ||
(event_report.rssi != CHRE_BLE_RSSI_NONE &&
event_report.rssi > cache_report.rssi)) {
cache_report.rssi = event_report.rssi;
}
// Updates timestamp to latest in the duplicated report.
if (event_report.timestamp > cache_report.timestamp) {
cache_report.timestamp = event_report.timestamp;
}
is_duplicate = true;
break;
}
}
if (!is_duplicate) {
LOGD("Adds to advertising reports cache");
// Copies advertise report by value.
chreBleAdvertisingReport new_report = event_report;
// Allocates advertise data and copy it.
uint16_t dataLength = event_report.dataLength;
uint8_t *data = nullptr;
if (dataLength > 0) {
data =
static_cast<uint8_t *>(chreHeapAlloc(sizeof(uint8_t) * dataLength));
if (data == nullptr) {
LOGE("Memory allocation failed!");
// Clean up expired cache elements for which heap memory is allocated.
Refresh();
return;
}
memcpy(data, event_report.data, dataLength);
new_report.data = data;
}
if (!cache_reports_.push_back(std::move(new_report))) {
LOGE("Pushes advertise report failed!");
if (data != nullptr) {
chreHeapFree(const_cast<uint8_t *>(data));
}
}
} else {
LOGD("Duplicated report in advertising reports cache");
}
#ifdef NEARBY_PROFILE
ashProfileEnd(&profile_data_, nullptr /* output */);
#endif
}
} // namespace nearby