Commit fc66ae44 authored by Tiansong Cui's avatar Tiansong Cui Committed by Commit Bot

[chromecast][BLE] Limit scan result to 1024 entries

Continuous Bluetooth scan may cause scan results to accumulate.
This can result in large memory usage if there are other devices
advertising with randomized MAC addresses.
We limit the scan result cache to 1024 entries to prevent this situation.
We kick out the least recently used entry when limit is reached.

Bug: internal 116650055
Test: cast_bluetooth_unittests, manual.
Change-Id: Ife0161a6edbc4354133dc158d0901ddce6ef876a
Reviewed-on: https://chromium-review.googlesource.com/1255630
Commit-Queue: Tiansong Cui <tiansong@google.com>
Reviewed-by: default avatarBailey Forrest <bcf@chromium.org>
Cr-Commit-Position: refs/heads/master@{#595692}
parent e30fab22
......@@ -41,6 +41,9 @@ const int kMaxMessagesInQueue = 5;
} // namespace
// static
constexpr int LeScanManagerImpl::kMaxScanResultEntries;
class LeScanManagerImpl::ScanHandleImpl : public LeScanManager::ScanHandle {
public:
explicit ScanHandleImpl(LeScanManagerImpl* manager, int32_t id)
......@@ -120,18 +123,34 @@ void LeScanManagerImpl::OnScanResult(
scan_result.addr = scan_result_shlib.addr;
scan_result.rssi = scan_result_shlib.rssi;
// Remove results with the same data as the current result to avoid duplicate
// messages in the queue
auto& previous_scan_results = addr_to_scan_results_[scan_result.addr];
previous_scan_results.remove_if([&scan_result](const auto& previous_result) {
return previous_result.adv_data == scan_result.adv_data;
});
if (previous_scan_results.size() > 0) {
// Remove results with the same data as the current result to avoid
// duplicate messages in the queue
previous_scan_results.remove_if(
[&scan_result](const auto& previous_result) {
return previous_result.adv_data == scan_result.adv_data;
});
// Remove scan_result.addr to avoid duplicate addresses in
// recent_scan_result_addr_list_.
base::Erase(scan_result_addr_list_, scan_result.addr);
}
previous_scan_results.push_front(scan_result);
if (previous_scan_results.size() > kMaxMessagesInQueue) {
previous_scan_results.pop_back();
}
// Update recent_scan_result_addr_list_.
scan_result_addr_list_.push_front(scan_result.addr);
while (scan_result_addr_list_.size() > kMaxScanResultEntries) {
// Remove least recently used address in recent_scan_result_addr_list_.
auto least_recently_used_addr = scan_result_addr_list_.back();
scan_result_addr_list_.pop_back();
addr_to_scan_results_.erase(least_recently_used_addr);
}
// Update observers.
observers_->Notify(FROM_HERE, &Observer::OnNewScanResult, scan_result);
}
......
......@@ -5,6 +5,7 @@
#ifndef CHROMECAST_DEVICE_BLUETOOTH_LE_LE_SCAN_MANAGER_IMPL_H_
#define CHROMECAST_DEVICE_BLUETOOTH_LE_LE_SCAN_MANAGER_IMPL_H_
#include <deque>
#include <list>
#include <map>
#include <set>
......@@ -28,6 +29,8 @@ class LeScanManagerImpl : public LeScanManager,
explicit LeScanManagerImpl(bluetooth_v2_shlib::LeScannerImpl* le_scanner);
~LeScanManagerImpl() override;
static constexpr int kMaxScanResultEntries = 1024;
void Initialize(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
void Finalize();
......@@ -61,6 +64,10 @@ class LeScanManagerImpl : public LeScanManager,
std::map<bluetooth_v2_shlib::Addr, std::list<LeScanResult>>
addr_to_scan_results_;
// List of addresses in scan results. Addresses are sorted from most recently
// used to least recently used.
std::deque<bluetooth_v2_shlib::Addr> scan_result_addr_list_;
int32_t next_scan_handle_id_ = 0;
std::set<int32_t> scan_handle_ids_;
......
......@@ -283,5 +283,41 @@ TEST_F(LeScanManagerTest, TestOnNewScanResult) {
ASSERT_EQ(1, result.rssi);
}
TEST_F(LeScanManagerTest, TestMaxScanResultEntries) {
EXPECT_CALL(mock_observer_, OnNewScanResult(_))
.Times(LeScanManagerImpl::kMaxScanResultEntries + 5);
// Add scan results with different addrs.
bluetooth_v2_shlib::LeScanner::ScanResult raw_scan_result;
for (int i = 0; i < LeScanManagerImpl::kMaxScanResultEntries + 5; ++i) {
uint8_t addr_bit0 = i & 0xFF;
uint8_t addr_bit1 = (i & 0xFF00) >> 8;
raw_scan_result.addr = {{addr_bit0, addr_bit1, 0xFF, 0xFF, 0xFF, 0xFF}};
raw_scan_result.adv_data = {0x03, 0x02, 0x44, 0x44};
raw_scan_result.rssi = -i;
delegate()->OnScanResult(raw_scan_result);
}
scoped_task_environment_.RunUntilIdle();
std::vector<LeScanResult> results;
// Get asynchronous scan results.
le_scan_manager_.GetScanResults(
base::BindOnce(&CopyResult<std::vector<LeScanResult>>, &results));
scoped_task_environment_.RunUntilIdle();
// First 5 addresses should have been kicked out.
ASSERT_EQ(1024u, results.size());
bluetooth_v2_shlib::Addr test_addr;
for (int i = 0; i < LeScanManagerImpl::kMaxScanResultEntries; ++i) {
uint8_t addr_bit0 = (i + 5) & 0xFF;
uint8_t addr_bit1 = ((i + 5) & 0xFF00) >> 8;
test_addr = {{addr_bit0, addr_bit1, 0xFF, 0xFF, 0xFF, 0xFF}};
EXPECT_EQ(test_addr, results[i].addr);
EXPECT_EQ(-(i + 5), results[i].rssi);
}
}
} // namespace bluetooth
} // namespace chromecast
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