OSDN Git Service

Support scan plan attribute for scheduled scan
authorNingyuan Wang <nywang@google.com>
Wed, 19 Jul 2017 17:58:36 +0000 (10:58 -0700)
committerNingyuan Wang <nywang@google.com>
Wed, 2 Aug 2017 00:55:19 +0000 (17:55 -0700)
This adds the support of the scan plan attribute.
With kernel updates, driver can no longer diffrentiate interval
attribute from single scan plan attribute, so driver's pno scan
back off logic cannot be triggered in that case.
To solve the PNO back-off problem, this CL allows wificond to explicitly
specify scan plans (if the driver supports it). With explicit scan
plans, the driver will have the information it needs to back-off PNO
scans.

Bug: 63837760
Test: compile, unit tests
Test: Manually test that pno scan works on multiple devices
Test: Integration sanity test

Change-Id: Ic7e38caa482a2d72f45bf3c8177fa656e534db08

scanning/pno_settings.cpp
scanning/pno_settings.h
scanning/scan_utils.cpp
scanning/scan_utils.h
scanning/scanner_impl.cpp
scanning/scanner_impl.h
tests/mock_scan_utils.h
tests/scan_utils_unittest.cpp
tests/scanner_unittest.cpp

index c8b5ff6..be051dd 100644 (file)
@@ -28,6 +28,9 @@ namespace server {
 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_));
index e236ec8..a606b0f 100644 (file)
@@ -32,6 +32,9 @@ namespace wificond {
 
 class PnoSettings : public ::android::Parcelable {
  public:
+  static const uint32_t kFastScanIterations;
+  static const uint32_t kSlowScanIntervalMultiplier;
+
   PnoSettings()
       : interval_ms_(0),
         min_2g_rssi_(0),
index 5f0a6e3..dfd051c 100644 (file)
@@ -36,6 +36,7 @@ namespace wificond {
 namespace {
 
 constexpr uint8_t kElemIdSsid = 0;
+constexpr unsigned int kMsecPerSec = 1000;
 
 }  // namespace
 
@@ -348,7 +349,7 @@ bool ScanUtils::AbortScan(uint32_t interface_index) {
 
 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,
@@ -385,6 +386,7 @@ bool ScanUtils::StartScheduledScan(
         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(
@@ -395,9 +397,31 @@ bool ScanUtils::StartScheduledScan(
   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,
index dbc2556..87df13a 100644 (file)
@@ -44,6 +44,17 @@ namespace wificond {
 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:
@@ -98,7 +109,7 @@ class ScanUtils {
   // 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,
index a1ea261..9bf13b3 100644 (file)
@@ -35,6 +35,7 @@ using com::android::server::wifi::wificond::NativeScanResult;
 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;
@@ -305,7 +306,7 @@ bool ScannerImpl::StartPnoScanDefault(const PnoSettings& pno_settings) {
 
   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,
@@ -447,6 +448,34 @@ void ScannerImpl::OnSchedScanResultsReady(uint32_t interface_index,
   }
 }
 
+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()) {
index fe66f17..2bb9262 100644 (file)
 #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:
@@ -99,6 +99,9 @@ class ScannerImpl : public android::net::wifi::BnWifiScannerImpl {
     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_;
index f3e1777..3e5cc7f 100644 (file)
@@ -50,7 +50,7 @@ class MockScanUtils : public ScanUtils {
 
   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,
index 9e36ab2..28ea283 100644 (file)
@@ -32,8 +32,10 @@ using std::placeholders::_1;
 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::_;
 
@@ -106,6 +108,11 @@ MATCHER_P(DoesNL80211PacketMatchCommand, command,
   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(
@@ -162,7 +169,7 @@ TEST_F(ScanUtilsTest, CanSendSchedScanRequest) {
   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.
@@ -179,11 +186,51 @@ TEST_F(ScanUtilsTest, CanHandleSchedScanRequestFailure) {
   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;
index 85f6330..bbaeffd 100644 (file)
@@ -51,6 +51,7 @@ namespace {
 
 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.
@@ -69,6 +70,20 @@ bool ReturnErrorCodeForScanRequest(
   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 {
@@ -168,5 +183,71 @@ TEST_F(ScannerTest, TestStopPnoScanViaNetlink) {
   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