namespace wifi {
namespace wificond {
+const uint32_t PnoSettings::kFastScanIterations = 3;
+const uint32_t PnoSettings::kSlowScanIntervalMultiplier = 3;
+
status_t PnoSettings::writeToParcel(::android::Parcel* parcel) const {
RETURN_IF_FAILED(parcel->writeInt32(interval_ms_));
RETURN_IF_FAILED(parcel->writeInt32(min_2g_rssi_));
class PnoSettings : public ::android::Parcelable {
public:
+ static const uint32_t kFastScanIterations;
+ static const uint32_t kSlowScanIntervalMultiplier;
+
PnoSettings()
: interval_ms_(0),
min_2g_rssi_(0),
namespace {
constexpr uint8_t kElemIdSsid = 0;
+constexpr unsigned int kMsecPerSec = 1000;
} // namespace
bool ScanUtils::StartScheduledScan(
uint32_t interface_index,
- uint32_t interval_ms,
+ const SchedScanIntervalSetting& interval_setting,
int32_t rssi_threshold,
bool request_random_mac,
const std::vector<std::vector<uint8_t>>& scan_ssids,
NL80211Attr<int32_t>(NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, rssi_threshold));
scan_match_attr.AddAttribute(match_group);
}
+ start_sched_scan.AddAttribute(scan_match_attr);
// Append all attributes to the NL80211_CMD_START_SCHED_SCAN packet.
start_sched_scan.AddAttribute(
if (!freqs.empty()) {
start_sched_scan.AddAttribute(freqs_attr);
}
- start_sched_scan.AddAttribute(
- NL80211Attr<uint32_t>(NL80211_ATTR_SCHED_SCAN_INTERVAL, interval_ms));
- start_sched_scan.AddAttribute(scan_match_attr);
+
+ if (!interval_setting.plans.empty()) {
+ NL80211NestedAttr scan_plans(NL80211_ATTR_SCHED_SCAN_PLANS);
+ for (unsigned int i = 0; i < interval_setting.plans.size(); i++) {
+ NL80211NestedAttr scan_plan(i + 1);
+ scan_plan.AddAttribute(
+ NL80211Attr<uint32_t>(NL80211_SCHED_SCAN_PLAN_INTERVAL,
+ interval_setting.plans[i].interval_ms / kMsecPerSec));
+ scan_plan.AddAttribute(
+ NL80211Attr<uint32_t>(NL80211_SCHED_SCAN_PLAN_ITERATIONS,
+ interval_setting.plans[i].n_iterations));
+ scan_plans.AddAttribute(scan_plan);
+ }
+ NL80211NestedAttr last_scan_plan(interval_setting.plans.size() + 1);
+ last_scan_plan.AddAttribute(
+ NL80211Attr<uint32_t>(NL80211_SCHED_SCAN_PLAN_INTERVAL,
+ interval_setting.final_interval_ms / kMsecPerSec));
+ scan_plans.AddAttribute(last_scan_plan);
+ start_sched_scan.AddAttribute(scan_plans);
+ } else {
+ start_sched_scan.AddAttribute(
+ NL80211Attr<uint32_t>(NL80211_ATTR_SCHED_SCAN_INTERVAL,
+ interval_setting.final_interval_ms));
+ }
+
if (request_random_mac) {
start_sched_scan.AddAttribute(
NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,
class NL80211NestedAttr;
class NL80211Packet;
+struct SchedScanIntervalSetting {
+ struct ScanPlan {
+ uint32_t interval_ms;
+ uint32_t n_iterations;
+ };
+ std::vector<ScanPlan> plans;
+ // After |plans| has been exhausted, scan at every
+ // |final_interval_ms|.
+ uint32_t final_interval_ms{0};
+};
+
// Provides scanning helper functions.
class ScanUtils {
public:
// Returns true on success.
virtual bool StartScheduledScan(
uint32_t interface_index,
- uint32_t interval_ms,
+ const SchedScanIntervalSetting& interval_setting,
int32_t rssi_threshold,
bool request_random_mac,
const std::vector<std::vector<uint8_t>>& scan_ssids,
using com::android::server::wifi::wificond::PnoSettings;
using com::android::server::wifi::wificond::SingleScanSettings;
+using std::pair;
using std::string;
using std::vector;
using std::weak_ptr;
int error_code = 0;
if (!scan_utils_->StartScheduledScan(interface_index_,
- pno_settings.interval_ms_,
+ GenerateIntervalSetting(pno_settings),
// TODO: honor both rssi thresholds.
pno_settings.min_5g_rssi_,
request_random_mac,
}
}
+SchedScanIntervalSetting ScannerImpl::GenerateIntervalSetting(
+ const ::com::android::server::wifi::wificond::PnoSettings&
+ pno_settings) const {
+ bool support_num_scan_plans = scan_capabilities_.max_num_scan_plans >= 2;
+ bool support_scan_plan_interval =
+ scan_capabilities_.max_scan_plan_interval * 1000 >=
+ pno_settings.interval_ms_ * PnoSettings::kSlowScanIntervalMultiplier;
+ bool support_scan_plan_iterations =
+ scan_capabilities_.max_scan_plan_iterations >=
+ PnoSettings::kFastScanIterations;
+
+ uint32_t fast_scan_interval =
+ static_cast<uint32_t>(pno_settings.interval_ms_);
+ if (support_num_scan_plans && support_scan_plan_interval &&
+ support_scan_plan_iterations) {
+ return SchedScanIntervalSetting{
+ {{fast_scan_interval, PnoSettings::kFastScanIterations}},
+ fast_scan_interval * PnoSettings::kSlowScanIntervalMultiplier};
+ } else {
+ // Device doesn't support the provided scan plans.
+ // Specify single interval instead.
+ // In this case, the driver/firmware is expected to implement back off
+ // logic internally using |pno_settings.interval_ms_| as "fast scan"
+ // interval.
+ return SchedScanIntervalSetting{{}, fast_scan_interval};
+ }
+}
+
void ScannerImpl::LogSsidList(vector<vector<uint8_t>>& ssid_list,
string prefix) {
if (ssid_list.empty()) {
#include "android/net/wifi/BnWifiScannerImpl.h"
#include "wificond/net/netlink_utils.h"
#include "wificond/scanning/offload/offload_scan_manager.h"
+#include "wificond/scanning/scan_utils.h"
namespace android {
namespace wificond {
class ClientInterfaceImpl;
class OffloadServiceUtils;
-class ScanUtils;
class ScannerImpl : public android::net::wifi::BnWifiScannerImpl {
public:
std::vector<std::vector<uint8_t>>* match_ssids,
std::vector<uint32_t>* freqs,
std::vector<uint8_t>* match_security);
+ SchedScanIntervalSetting GenerateIntervalSetting(
+ const ::com::android::server::wifi::wificond::PnoSettings& pno_settings) const;
+
// Boolean variables describing current scanner status.
bool valid_;
bool scan_started_;
MOCK_METHOD8(StartScheduledScan, bool(
uint32_t interface_index,
- uint32_t interval_ms,
+ const SchedScanIntervalSetting& interval_setting,
int32_t rssi_threshold,
bool request_random_mac,
const std::vector<std::vector<uint8_t>>& scan_ssids,
using std::placeholders::_2;
using std::unique_ptr;
using std::vector;
+using testing::AllOf;
using testing::Invoke;
using testing::NiceMock;
+using testing::Not;
using testing::Return;
using testing::_;
return arg.GetCommand() == command;
}
+MATCHER_P(DoesNL80211PacketHaveAttribute, attr,
+ "Check if the netlink packet has atttribute |attr|") {
+ return arg.HasAttribute(attr);
+}
+
TEST_F(ScanUtilsTest, CanGetScanResult) {
vector<NativeScanResult> scan_results;
EXPECT_CALL(
int errno_ignored;
EXPECT_TRUE(scan_utils_.StartScheduledScan(
kFakeInterfaceIndex,
- kFakeScheduledScanIntervalMs,
+ SchedScanIntervalSetting(),
kFakeRssiThreshold, kFakeUseRandomMAC, {}, {}, {}, &errno_ignored));
// TODO(b/34231420): Add validation of requested scan ssids, threshold,
// and frequencies.
int error_code;
EXPECT_FALSE(scan_utils_.StartScheduledScan(
kFakeInterfaceIndex,
- kFakeScheduledScanIntervalMs,
+ SchedScanIntervalSetting(),
kFakeRssiThreshold, kFakeUseRandomMAC, {}, {}, {}, &error_code));
EXPECT_EQ(kFakeErrorCode, error_code);
}
+TEST_F(ScanUtilsTest, CanSpecifyScanPlansForSchedScanRequest) {
+ EXPECT_CALL(
+ netlink_manager_,
+ SendMessageAndGetResponses(
+ AllOf(
+ DoesNL80211PacketMatchCommand(NL80211_CMD_START_SCHED_SCAN),
+ DoesNL80211PacketHaveAttribute(NL80211_ATTR_SCHED_SCAN_PLANS),
+ Not(DoesNL80211PacketHaveAttribute(
+ NL80211_ATTR_SCHED_SCAN_INTERVAL))),
+ _));
+ int errno_ignored;
+ SchedScanIntervalSetting interval_setting{
+ {{kFakeScheduledScanIntervalMs, 10 /* repeated times */}},
+ kFakeScheduledScanIntervalMs * 3 /* interval for infinite scans */};
+
+ scan_utils_.StartScheduledScan(
+ kFakeInterfaceIndex,
+ interval_setting,
+ kFakeRssiThreshold, kFakeUseRandomMAC, {}, {}, {}, &errno_ignored);
+}
+
+TEST_F(ScanUtilsTest, CanSpecifySingleIntervalForSchedScanRequest) {
+ EXPECT_CALL(
+ netlink_manager_,
+ SendMessageAndGetResponses(
+ AllOf(
+ DoesNL80211PacketMatchCommand(NL80211_CMD_START_SCHED_SCAN),
+ DoesNL80211PacketHaveAttribute(NL80211_ATTR_SCHED_SCAN_INTERVAL),
+ Not(DoesNL80211PacketHaveAttribute(
+ NL80211_ATTR_SCHED_SCAN_PLANS))),
+ _));
+ int errno_ignored;
+ SchedScanIntervalSetting interval_setting{{}, kFakeScheduledScanIntervalMs};
+
+ scan_utils_.StartScheduledScan(
+ kFakeInterfaceIndex,
+ interval_setting,
+ kFakeRssiThreshold, kFakeUseRandomMAC, {}, {}, {}, &errno_ignored);
+}
+
TEST_F(ScanUtilsTest, CanPrioritizeLastSeenSinceBootNetlinkAttribute) {
constexpr uint64_t kLastSeenTimestampNanoSeconds = 123456;
constexpr uint64_t kBssTsfTimestampMicroSeconds = 654321;
constexpr uint32_t kFakeInterfaceIndex = 12;
constexpr uint32_t kFakeWiphyIndex = 5;
+constexpr uint32_t kFakeScanIntervalMs = 10000;
// This is a helper function to mock the behavior of ScanUtils::Scan()
// when we expect a error code.
return false;
}
+bool CaptureSchedScanIntervalSetting(
+ uint32_t /* interface_index */,
+ const SchedScanIntervalSetting& interval_setting,
+ int32_t /* rssi_threshold */,
+ bool /* request_random_mac */,
+ const std::vector<std::vector<uint8_t>>& /* scan_ssids */,
+ const std::vector<std::vector<uint8_t>>& /* match_ssids */,
+ const std::vector<uint32_t>& /* freqs */,
+ int* /* error_code */,
+ SchedScanIntervalSetting* out_interval_setting) {
+ *out_interval_setting = interval_setting;
+ return true;
+}
+
} // namespace
class ScannerTest : public ::testing::Test {
EXPECT_TRUE(success);
}
+TEST_F(ScannerTest, TestGenerateScanPlansIfDeviceSupports) {
+ ScanCapabilities scan_capabilities_scan_plan_supported(
+ 0 /* max_num_scan_ssids */,
+ 0 /* max_num_sched_scan_ssids */,
+ 0 /* max_match_sets */,
+ // Parameters above are not related to this test.
+ 2 /* 1 plan for finite repeated scan and 1 plan for ininfite scan loop */,
+ kFakeScanIntervalMs * PnoSettings::kSlowScanIntervalMultiplier / 1000,
+ PnoSettings::kFastScanIterations);
+ ScannerImpl scanner(
+ kFakeWiphyIndex, kFakeInterfaceIndex,
+ scan_capabilities_scan_plan_supported, wiphy_features_,
+ &client_interface_impl_,
+ &netlink_utils_, &scan_utils_, offload_service_utils_);
+
+ PnoSettings pno_settings;
+ pno_settings.interval_ms_ = kFakeScanIntervalMs;
+
+ SchedScanIntervalSetting interval_setting;
+ EXPECT_CALL(
+ scan_utils_,
+ StartScheduledScan(_, _, _, _, _, _, _, _)).
+ WillOnce(Invoke(bind(
+ CaptureSchedScanIntervalSetting,
+ _1, _2, _3, _4, _5, _6, _7, _8, &interval_setting)));
+
+ bool success_ignored = 0;
+ EXPECT_TRUE(scanner.startPnoScan(pno_settings, &success_ignored).isOk());
+ /* 1 plan for finite repeated scan */
+ EXPECT_EQ(1U, interval_setting.plans.size());
+ EXPECT_EQ(kFakeScanIntervalMs * PnoSettings::kSlowScanIntervalMultiplier,
+ interval_setting.final_interval_ms);
+}
+
+TEST_F(ScannerTest, TestGenerateSingleIntervalIfDeviceDoesNotSupportScanPlan) {
+ ScanCapabilities scan_capabilities_no_scan_plan_support(
+ 0 /* max_num_scan_ssids */,
+ 0 /* max_num_sched_scan_ssids */,
+ 0 /* max_match_sets */,
+ // Parameters above are not related to this test.
+ 0 /* max_num_scan_plans */,
+ 0 /* max_scan_plan_interval */,
+ 0 /* max_scan_plan_iterations */);
+ ScannerImpl scanner(
+ kFakeWiphyIndex, kFakeInterfaceIndex,
+ scan_capabilities_no_scan_plan_support, wiphy_features_,
+ &client_interface_impl_,
+ &netlink_utils_, &scan_utils_, offload_service_utils_);
+ PnoSettings pno_settings;
+ pno_settings.interval_ms_ = kFakeScanIntervalMs;
+
+ SchedScanIntervalSetting interval_setting;
+ EXPECT_CALL(
+ scan_utils_,
+ StartScheduledScan(_, _, _, _, _, _, _, _)).
+ WillOnce(Invoke(bind(
+ CaptureSchedScanIntervalSetting,
+ _1, _2, _3, _4, _5, _6, _7, _8, &interval_setting)));
+
+ bool success_ignored = 0;
+ EXPECT_TRUE(scanner.startPnoScan(pno_settings, &success_ignored).isOk());
+
+ EXPECT_EQ(0U, interval_setting.plans.size());
+ EXPECT_EQ(kFakeScanIntervalMs, interval_setting.final_interval_ms);
+}
+
} // namespace wificond
} // namespace android