OSDN Git Service

release-request-323db86e-b638-4d24-8eb1-d2e3bf4a9d1a-for-git_oc-mr1-release-4017779...
authorandroid-build-team Robot <android-build-team-robot@google.com>
Wed, 17 May 2017 14:23:30 +0000 (14:23 +0000)
committerandroid-build-team Robot <android-build-team-robot@google.com>
Wed, 17 May 2017 14:23:30 +0000 (14:23 +0000)
Change-Id: Ie6fa7fc3062460fdc8c420d4059f1dbd8351c3b1

19 files changed:
Android.mk
aidl/android/net/wifi/IWifiScannerImpl.aidl
scanning/offload/offload_scan_manager.cpp
scanning/offload/offload_scan_manager.h
scanning/offload/offload_scan_utils.cpp
scanning/offload/offload_scan_utils.h
scanning/offload/scan_stats.cpp [new file with mode: 0644]
scanning/offload/scan_stats.h [new file with mode: 0644]
scanning/scan_utils.cpp
scanning/scan_utils.h
scanning/scanner_impl.cpp
scanning/scanner_impl.h
tests/offload_hal_test_constants.cpp [new file with mode: 0644]
tests/offload_hal_test_constants.h [new file with mode: 0644]
tests/offload_scan_manager_test.cpp
tests/offload_scan_utils_test.cpp
tests/offload_test_utils.cpp
tests/offload_test_utils.h
tests/scan_stats_unittest.cpp [new file with mode: 0644]

index 0a193e3..385eb54 100644 (file)
@@ -14,6 +14,9 @@
 
 LOCAL_PATH := $(call my-dir)
 wificond_cpp_flags := -Wall -Werror -Wno-unused-parameter
+ifdef WIFI_OFFLOAD_SCANS
+wificond_cpp_flags += -DWIFI_OFFLOAD_SCANS=\"$(WIFI_OFFLOAD_SCANS)\"
+endif
 wificond_parent_dir := $(LOCAL_PATH)/../
 wificond_includes := \
     $(wificond_parent_dir)
@@ -66,6 +69,7 @@ LOCAL_SRC_FILES := \
     scanning/pno_network.cpp \
     scanning/pno_settings.cpp \
     scanning/scan_result.cpp \
+    scanning/offload/scan_stats.cpp \
     scanning/single_scan_settings.cpp \
     scanning/scan_utils.cpp \
     scanning/scanner_impl.cpp \
@@ -177,11 +181,13 @@ LOCAL_SRC_FILES := \
     tests/nl80211_attribute_unittest.cpp \
     tests/nl80211_packet_unittest.cpp \
     tests/offload_callback_test.cpp \
+    tests/offload_hal_test_constants.cpp \
     tests/offload_scan_manager_test.cpp \
     tests/offload_scan_utils_test.cpp \
     tests/offload_test_utils.cpp \
     tests/scan_result_unittest.cpp \
     tests/scan_settings_unittest.cpp \
+    tests/scan_stats_unittest.cpp \
     tests/scan_utils_unittest.cpp \
     tests/server_unittest.cpp
 LOCAL_STATIC_LIBRARIES := \
index ce8f5c5..145310d 100644 (file)
@@ -65,5 +65,10 @@ interface IWifiScannerImpl {
   // Returns false on failure or there is no existing scheduled scan.
   boolean stopPnoScan();
 
+  // Abort ongoing scan.
+  // Returns true on success.
+  // Returns false on failure or there is no ongoing scan.
+  boolean abortScan();
+
   // TODO(nywang) add more interfaces.
 }
index 760f448..b8dfcd8 100644 (file)
 #include "wificond/scanning/offload/offload_scan_utils.h"
 #include "wificond/scanning/offload/offload_service_utils.h"
 #include "wificond/scanning/scan_result.h"
+#include "wificond/scanning/offload/scan_stats.h"
 
 using ::android::hardware::hidl_vec;
 using android::hardware::wifi::offload::V1_0::IOffload;
 using android::hardware::wifi::offload::V1_0::ScanResult;
+using android::hardware::wifi::offload::V1_0::ScanFilter;
+using android::hardware::wifi::offload::V1_0::ScanParam;
+using android::hardware::wifi::offload::V1_0::ScanStats;
 using android::hardware::wifi::offload::V1_0::OffloadStatus;
 
 using android::wificond::OffloadCallback;
 using android::wificond::OnNativeScanResultsReadyHandler;
 using ::com::android::server::wifi::wificond::NativeScanResult;
-
+using ::com::android::server::wifi::wificond::NativeScanStats;
 using namespace std::placeholders;
+using std::vector;
+
+namespace {
+  const uint32_t kSubscriptionDelayMs = 5000;
+}
 
 namespace android {
 namespace wificond {
 
-OffloadCallbackHandlersImpl::OffloadCallbackHandlersImpl(OffloadScanManager* offload_scan_manager)
-    : offload_scan_manager_(offload_scan_manager) {
+OffloadCallbackHandlersImpl::OffloadCallbackHandlersImpl(
+    OffloadScanManager* offload_scan_manager)
+        : offload_scan_manager_(offload_scan_manager) {
 }
 
 OffloadCallbackHandlersImpl::~OffloadCallbackHandlersImpl() {}
 
-void OffloadCallbackHandlersImpl::OnScanResultHandler(const std::vector<ScanResult>& scanResult) {
+void OffloadCallbackHandlersImpl::OnScanResultHandler(
+    const vector<ScanResult>& scanResult) {
   if (offload_scan_manager_ != nullptr) {
     offload_scan_manager_->ReportScanResults(scanResult);
   }
@@ -59,9 +70,11 @@ OffloadScanManager::OffloadScanManager(OffloadServiceUtils *utils,
     OnNativeScanResultsReadyHandler handler)
     : wifi_offload_hal_(nullptr),
       wifi_offload_callback_(nullptr),
-      scan_result_handler_(handler),
       offload_status_(OffloadScanManager::kError),
-      offload_callback_handlers_(new OffloadCallbackHandlersImpl(this)) {
+      subscription_enabled_(false),
+      service_available_(false),
+      offload_callback_handlers_(new OffloadCallbackHandlersImpl(this)),
+      scan_result_handler_(handler) {
   if (utils == nullptr) {
     LOG(ERROR) << "Invalid arguments for Offload ScanManager";
     return;
@@ -72,34 +85,109 @@ OffloadScanManager::OffloadScanManager(OffloadServiceUtils *utils,
   }
   wifi_offload_hal_ = utils->GetOffloadService();
   if (wifi_offload_hal_ == nullptr) {
-    LOG(WARNING) << "No Offload Service available";
-    offload_status_ = OffloadScanManager::kNoService;
+    LOG(ERROR) << "No Offload Service available";
     return;
   }
   wifi_offload_callback_ = utils->GetOffloadCallback(
       offload_callback_handlers_.get());
   if (wifi_offload_callback_ == nullptr) {
-    offload_status_ = OffloadScanManager::kNoService;
     LOG(ERROR) << "Invalid Offload callback object";
     return;
   }
   wifi_offload_hal_->setEventCallback(wifi_offload_callback_);
+  service_available_ = true;
   offload_status_ = OffloadScanManager::kNoError;
 }
 
+bool OffloadScanManager::stopScan(OffloadScanManager::ReasonCode* reason_code) {
+  if (!subscription_enabled_) {
+    LOG(VERBOSE) << "Scans are not subscribed over Offload HAL";
+    *reason_code = OffloadScanManager::kNotSubscribed;
+    return false;
+  }
+  if (service_available_) {
+    wifi_offload_hal_->unsubscribeScanResults();
+    subscription_enabled_ = false;
+  }
+  *reason_code = OffloadScanManager::kNone;
+  return true;
+}
+
+bool OffloadScanManager::startScan(
+    uint32_t interval_ms,
+    int32_t rssi_threshold,
+    const vector<vector<uint8_t>>& scan_ssids,
+    const vector<vector<uint8_t>>& match_ssids,
+    const vector<uint8_t>& match_security,
+    const vector<uint32_t> &freqs,
+    OffloadScanManager::ReasonCode* reason_code) {
+  if (!service_available_) {
+    *reason_code = OffloadScanManager::kNotSupported;
+    LOG(WARNING) << "Offload HAL scans are not supported";
+    return false;
+  } else if (offload_status_ == OffloadScanManager::kNotConnected) {
+    LOG(WARNING) << "Offload HAL scans are not available";
+    *reason_code = OffloadScanManager::kNotAvailable;
+    return false;
+  }
+
+  ScanParam param = OffloadScanUtils::createScanParam(scan_ssids, freqs,
+      interval_ms);
+  ScanFilter filter = OffloadScanUtils::createScanFilter(match_ssids,
+      match_security, rssi_threshold);
+
+  wifi_offload_hal_->configureScans(param, filter);
+  if (!subscription_enabled_) {
+    wifi_offload_hal_->subscribeScanResults(kSubscriptionDelayMs);
+  }
+  subscription_enabled_ = true;
+  *reason_code = OffloadScanManager::kNone;
+  return true;
+}
+
+OffloadScanManager::StatusCode OffloadScanManager::getOffloadStatus() const {
+  if (!service_available_) {
+    return OffloadScanManager::kNoService;
+  }
+  return offload_status_;
+}
+
+bool OffloadScanManager::isOffloadScanSupported() const {
+    bool result = false;
+#ifdef WIFI_OFFLOAD_SCANS
+    LOG(VERBOSE) << "Offload HAL supported";
+    result = true;
+#endif
+    return result;
+}
+
+bool OffloadScanManager::getScanStats(NativeScanStats* native_scan_stats) {
+  if (getOffloadStatus() != OffloadScanManager::kNoError) {
+    LOG(WARNING) << "Unable to get scan stats due to Wifi Offload HAL error";
+    return false;
+  }
+  wifi_offload_hal_->getScanStats(
+      [&native_scan_stats] (ScanStats offload_scan_stats)-> void {
+          *native_scan_stats =
+              OffloadScanUtils::convertToNativeScanStats(offload_scan_stats);
+      });
+  return true;
+}
+
 OffloadScanManager::~OffloadScanManager() {}
 
 void OffloadScanManager::ReportScanResults(
-    const std::vector<ScanResult> scanResult) {
+    const vector<ScanResult> scanResult) {
   if (scan_result_handler_ != nullptr) {
-    scan_result_handler_(OffloadScanUtils::convertToNativeScanResults(scanResult));
+    scan_result_handler_(
+        OffloadScanUtils::convertToNativeScanResults(scanResult));
   } else {
     LOG(ERROR) << "No scan result handler for Offload ScanManager";
   }
 }
 
 void OffloadScanManager::ReportError(OffloadStatus status) {
-  StatusCode status_result = OffloadScanManager::kNoError;
+  OffloadScanManager::StatusCode status_result = OffloadScanManager::kNoError;
   switch(status) {
     case OffloadStatus::OFFLOAD_STATUS_OK:
       status_result = OffloadScanManager::kNoError;
@@ -123,9 +211,5 @@ void OffloadScanManager::ReportError(OffloadStatus status) {
   offload_status_ = status_result;
 }
 
-OffloadScanManager::StatusCode OffloadScanManager::getOffloadStatus() const {
-  return offload_status_;
-}
-
 }  // namespace wificond
 }  // namespace android
index 3c6c736..5f589d8 100644 (file)
@@ -35,6 +35,7 @@ namespace wifi {
 namespace wificond {
 
 class NativeScanResult;
+class NativeScanStats;
 
 }  // namespace wificond
 }  // namespace wifi
@@ -80,12 +81,45 @@ class OffloadScanManager {
       kError
   };
 
+  enum ReasonCode {
+      /* Default value */
+      kNone,
+      /* Offload HAL service not available */
+      kNotSupported,
+      /* Offload HAL service is not connected */
+      kNotAvailable,
+      /* Offload HAL service is not subscribed to */
+      kNotSubscribed,
+  };
+
   explicit OffloadScanManager(OffloadServiceUtils* utils,
       OnNativeScanResultsReadyHandler handler);
   virtual ~OffloadScanManager();
-  /* Caller can use this method to obtain status of the Offload HAL service
-   * before invoking methods to perform disconnected PNO scans */
+  /* Request start of offload scans with scan parameters and scan filter
+   * settings. Internally calls Offload HAL service with configureScans()
+   * and subscribeScanResults() APIs. If already subscribed, it updates
+   * the scan configuration only. Reason code is updated in failure case
+   */
+  bool startScan(
+      uint32_t /* interval_ms */,
+      int32_t /* rssi_threshold */,
+      const std::vector<std::vector<uint8_t>>& /* scan_ssids */,
+      const std::vector<std::vector<uint8_t>>& /* match_ssids */,
+      const std::vector<uint8_t>& /* match_security */,
+      const std::vector<uint32_t>& /* freqs */,
+      ReasonCode* /* failure reason */);
+  /* Request stop of offload scans, returns true if scans were subscribed
+   * to from the Offload HAL service. Otherwise, returns false. Reason code
+   * is updated in case of failure.
+   */
+  bool stopScan(ReasonCode* /* failure reason */);
+  /* Get statistics for scans performed by Offload HAL */
+  bool getScanStats(
+      ::com::android::server::wifi::wificond::NativeScanStats* /* scanStats */);
+  /* Otain status of the Offload HAL service */
   StatusCode getOffloadStatus() const;
+  /* Check if Offload service is supported on this device */
+  bool isOffloadScanSupported() const;
 
  private:
   void ReportScanResults(const std::vector<ScanResult> scanResult);
@@ -93,9 +127,12 @@ class OffloadScanManager {
 
   android::sp<IOffload> wifi_offload_hal_;
   android::sp<OffloadCallback> wifi_offload_callback_;
-  OnNativeScanResultsReadyHandler scan_result_handler_;
   StatusCode offload_status_;
+  bool subscription_enabled_;
+  bool service_available_;
+
   const std::unique_ptr<OffloadCallbackHandlersImpl> offload_callback_handlers_;
+  OnNativeScanResultsReadyHandler scan_result_handler_;
 
   friend class OffloadCallbackHandlersImpl;
 };
index 7f468b5..2ccae10 100644 (file)
  * limitations under the License.
  */
 #include "wificond/scanning/offload/offload_scan_utils.h"
+
+#include <android-base/logging.h>
+
 #include "wificond/scanning/scan_result.h"
+#include "wificond/scanning/offload/scan_stats.h"
 
 using ::com::android::server::wifi::wificond::NativeScanResult;
+using ::com::android::server::wifi::wificond::NativeScanStats;
 using android::hardware::wifi::offload::V1_0::ScanResult;
+using android::hardware::wifi::offload::V1_0::ScanParam;
+using android::hardware::wifi::offload::V1_0::ScanFilter;
+using android::hardware::wifi::offload::V1_0::ScanStats;
+using android::hardware::wifi::offload::V1_0::NetworkInfo;
+using android::hardware::hidl_vec;
+using std::vector;
 
 namespace android {
 namespace wificond {
 
-std::vector<NativeScanResult> OffloadScanUtils::convertToNativeScanResults(
-    const std::vector<ScanResult>& scanResult) {
-  std::vector<NativeScanResult> nativeScanResult;
-  nativeScanResult.reserve(scanResult.size());
-  for (size_t i = 0; i < scanResult.size(); i++) {
-    NativeScanResult singleScanResult;
-    singleScanResult.ssid = scanResult[i].networkInfo.ssid;
-    singleScanResult.bssid.assign(scanResult[i].networkInfo.ssid.begin(),
-      scanResult[i].networkInfo.ssid.end());
-    singleScanResult.frequency = scanResult[i].frequency;
-    singleScanResult.signal_mbm = scanResult[i].rssi;
-    singleScanResult.tsf = scanResult[i].tsf;
-    singleScanResult.capability = scanResult[i].capability;
-    singleScanResult.associated = false;
-    nativeScanResult.emplace_back(singleScanResult);
+vector<NativeScanResult> OffloadScanUtils::convertToNativeScanResults(
+    const vector<ScanResult>& scan_result) {
+  vector<NativeScanResult> native_scan_result;
+  native_scan_result.reserve(scan_result.size());
+  for (size_t i = 0; i < scan_result.size(); i++) {
+    NativeScanResult single_scan_result;
+    single_scan_result.ssid = scan_result[i].networkInfo.ssid;
+    single_scan_result.bssid.assign(scan_result[i].networkInfo.ssid.begin(),
+        scan_result[i].networkInfo.ssid.end());
+    single_scan_result.frequency = scan_result[i].frequency;
+    single_scan_result.signal_mbm = scan_result[i].rssi;
+    single_scan_result.tsf = scan_result[i].tsf;
+    single_scan_result.capability = scan_result[i].capability;
+    single_scan_result.associated = false;
+    native_scan_result.emplace_back(single_scan_result);
+  }
+  return native_scan_result;
+}
+
+ScanParam OffloadScanUtils::createScanParam(
+    const vector<vector<uint8_t>>& ssid_list,
+    const vector<uint32_t>& frequency_list, uint32_t scan_interval_ms) {
+  ScanParam scan_param;
+  scan_param.disconnectedModeScanIntervalMs = scan_interval_ms;
+  scan_param.frequencyList = frequency_list;
+  vector<hidl_vec<uint8_t>> ssid_list_tmp;
+  for (const auto& ssid : ssid_list) {
+    ssid_list_tmp.push_back(ssid);
+  }
+  scan_param.ssidList = ssid_list_tmp;
+  return scan_param;
+}
+
+ScanFilter OffloadScanUtils::createScanFilter(
+    const vector<vector<uint8_t>>& ssids,
+    const vector<uint8_t>& flags, int8_t rssi_threshold) {
+  ScanFilter scan_filter;
+  vector<NetworkInfo> nw_info_list;
+  size_t i = 0;
+  scan_filter.rssiThreshold = rssi_threshold;
+  // Note that the number of ssids should match the number of security flags
+  for (const auto& ssid : ssids) {
+      NetworkInfo nw_info;
+      nw_info.ssid = ssid;
+      if (i < flags.size()) {
+        nw_info.flags = flags[i++];
+      } else {
+        continue;
+      }
+      nw_info_list.push_back(nw_info);
   }
-  return nativeScanResult;
+  scan_filter.preferredNetworkInfoList = nw_info_list;
+  return scan_filter;
+}
+
+NativeScanStats OffloadScanUtils::convertToNativeScanStats(
+    const ScanStats& scanStats) {
+  uint32_t num_channels_scanned = 0;
+  uint32_t scan_duration_ms = 0;
+  vector<uint8_t> histogram_channels;
+
+  for (size_t i = 0; i < scanStats.scanRecord.size(); i++) {
+    scan_duration_ms += scanStats.scanRecord[i].durationMs;
+    num_channels_scanned +=
+        scanStats.scanRecord[i].numChannelsScanned;
+  }
+  for (size_t i = 0; i < scanStats.histogramChannelsScanned.size(); i++) {
+    histogram_channels.push_back(
+      scanStats.histogramChannelsScanned[i]);
+  }
+
+  NativeScanStats native_scan_stats(scanStats.numScansRequestedByWifi,
+      scanStats.numScansServicedByWifi,
+      scanStats.subscriptionDurationMs,
+      scan_duration_ms,
+      num_channels_scanned,
+      histogram_channels);
+  return native_scan_stats;
 }
 
-} // wificond
-} // android
+} // namespace wificond
+} // namespace android
 
index e1f20a3..34fe21a 100644 (file)
@@ -22,6 +22,9 @@
 #include <vector>
 
 using android::hardware::wifi::offload::V1_0::ScanResult;
+using android::hardware::wifi::offload::V1_0::ScanParam;
+using android::hardware::wifi::offload::V1_0::ScanFilter;
+using android::hardware::wifi::offload::V1_0::ScanStats;
 
 namespace com {
 namespace android {
@@ -30,6 +33,7 @@ namespace wifi {
 namespace wificond {
 
 class NativeScanResult;
+class NativeScanStats;
 
 }  // namespace wificond
 }  // namespace wifi
@@ -45,6 +49,19 @@ class OffloadScanUtils {
  public:
   static std::vector<::com::android::server::wifi::wificond::NativeScanResult>
       convertToNativeScanResults(const std::vector<ScanResult>&);
+  static ScanParam createScanParam(
+      const std::vector<std::vector<uint8_t>>& ssid_list,
+      const std::vector<uint32_t>& frequency_list, uint32_t scan_interval_ms);
+  /* Creates ScanFilter using ssids, security flags and rssi_threshold
+   * The caller must ensure that the number of ssids match the number of security
+   * flags, also there must be ordering maintained among the two lists. For eg:
+   * (ssid[0], flags[0]) describe the SSID and security settings of one network
+   */
+  static ScanFilter createScanFilter(
+      const std::vector<std::vector<uint8_t>>& ssids,
+      const std::vector<uint8_t>& flags, int8_t rssi_threshold);
+  static ::com::android::server::wifi::wificond::NativeScanStats
+      convertToNativeScanStats(const ScanStats& /* scanStats */);
 };
 
 }  // namespace wificond
diff --git a/scanning/offload/scan_stats.cpp b/scanning/offload/scan_stats.cpp
new file mode 100644 (file)
index 0000000..554e113
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 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 "wificond/scanning/offload/scan_stats.h"
+
+#include <android-base/logging.h>
+
+#include "wificond/parcelable_utils.h"
+
+using android::status_t;
+
+namespace com {
+namespace android {
+namespace server {
+namespace wifi {
+namespace wificond {
+
+NativeScanStats::NativeScanStats(uint32_t num_scans_requested_by_wifi,
+    uint32_t num_scans_serviced_by_wifi,
+    uint32_t subscription_duration_ms,
+    uint32_t scan_duration_ms,
+    uint32_t num_channels_scanned,
+    std::vector<uint8_t> histogram_channels)
+    : num_scans_requested_by_wifi_(num_scans_requested_by_wifi),
+      num_scans_serviced_by_wifi_(num_scans_serviced_by_wifi),
+      subscription_duration_ms_(subscription_duration_ms),
+      scan_duration_ms_(scan_duration_ms),
+      num_channels_scanned_(num_channels_scanned),
+      time_stamp_(0),
+      histogram_channels_(histogram_channels) {
+}
+
+NativeScanStats::NativeScanStats()
+    : num_scans_requested_by_wifi_(0),
+      num_scans_serviced_by_wifi_(0),
+      subscription_duration_ms_(0),
+      num_channels_scanned_(0),
+      time_stamp_(0) {
+}
+
+bool NativeScanStats::operator==(const NativeScanStats& rhs) const {
+  bool result = true;
+  if ((rhs.num_scans_requested_by_wifi_ != num_scans_requested_by_wifi_) ||
+      (rhs.num_scans_serviced_by_wifi_ != num_scans_serviced_by_wifi_) ||
+      (rhs.scan_duration_ms_ != scan_duration_ms_) ||
+      (rhs.num_channels_scanned_ != num_channels_scanned_)) {
+    result = false;
+  }
+  if (rhs.histogram_channels_.size() != histogram_channels_.size()) {
+    return false;
+  }
+  for (size_t i = 0; i < histogram_channels_.size(); i++) {
+    if (rhs.histogram_channels_[i] != histogram_channels_[i]) {
+      result = false;
+    }
+  }
+  return result;
+}
+
+status_t NativeScanStats::writeToParcel(::android::Parcel* parcel) const {
+  RETURN_IF_FAILED(parcel->writeUint32(num_scans_requested_by_wifi_));
+  RETURN_IF_FAILED(parcel->writeUint32(num_scans_serviced_by_wifi_));
+  RETURN_IF_FAILED(parcel->writeUint32(subscription_duration_ms_));
+  RETURN_IF_FAILED(parcel->writeUint32(scan_duration_ms_));
+  RETURN_IF_FAILED(parcel->writeUint32(num_channels_scanned_));
+  RETURN_IF_FAILED(parcel->writeByteVector(histogram_channels_));
+  return ::android::OK;
+}
+
+status_t NativeScanStats::readFromParcel(const ::android::Parcel* parcel) {
+  RETURN_IF_FAILED(parcel->readUint32(&num_scans_requested_by_wifi_));
+  RETURN_IF_FAILED(parcel->readUint32(&num_scans_serviced_by_wifi_));
+  RETURN_IF_FAILED(parcel->readUint32(&subscription_duration_ms_));
+  RETURN_IF_FAILED(parcel->readUint32(&scan_duration_ms_));
+  RETURN_IF_FAILED(parcel->readUint32(&num_channels_scanned_));
+  RETURN_IF_FAILED(parcel->readByteVector(&histogram_channels_));
+  return ::android::OK;
+}
+
+
+}  // namespace wificond
+}  // namespace wifi
+}  // namespace server
+}  // namespace android
+}  // namespace com
diff --git a/scanning/offload/scan_stats.h b/scanning/offload/scan_stats.h
new file mode 100644 (file)
index 0000000..cae3e7e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef WIFICOND_SCAN_STATS_H
+#define WIFICOND_SCAN_STATS_H
+
+#include <vector>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+namespace com {
+namespace android {
+namespace server {
+namespace wifi {
+namespace wificond {
+
+class NativeScanStats : public ::android::Parcelable {
+ public:
+  NativeScanStats();
+  NativeScanStats(uint32_t num_scans_requested_by_wifi,
+      uint32_t num_scans_serviced_by_wifi,
+      uint32_t subscription_duration_ms,
+      uint32_t scan_duration_ms,
+      uint32_t num_channels_scanned,
+      std::vector<uint8_t> histogram_channels);
+
+  bool operator==(const NativeScanStats&) const;
+  ::android::status_t writeToParcel(::android::Parcel* parcel) const override;
+  ::android::status_t readFromParcel(const ::android::Parcel* parcel) override;
+
+  uint32_t num_scans_requested_by_wifi_;
+  uint32_t num_scans_serviced_by_wifi_;
+  uint32_t subscription_duration_ms_;
+  uint32_t scan_duration_ms_;
+  uint32_t num_channels_scanned_;
+  uint32_t time_stamp_;
+  std::vector<uint8_t> histogram_channels_;
+};
+
+}  // namespace wificond
+}  // namespace wifi
+}  // namespace server
+}  // namespace android
+}  // namespace com
+#endif // WIFICOND_SCAN_STATS_H
+
index 40a4355..5199e2b 100644 (file)
@@ -148,13 +148,7 @@ bool ScanUtils::ParseScanResult(unique_ptr<const NL80211Packet> packet,
     vector<uint8_t> ssid;
     if (!GetSSIDFromInfoElement(ie, &ssid)) {
       // Skip BSS without SSID IE.
-      // It might be from a hidden network. Framework doesn't need it.
-      return false;
-    }
-    if (ssid.empty() ||
-        std::all_of(ssid.begin(), ssid.end(), [](uint8_t c) {return c == 0;})) {
-      // Skip BSS with empty or all-zero SSID.
-      // It might be from a hidden network. Framework doesn't need it.
+      // These scan results are considered as malformed.
       return false;
     }
     uint64_t tsf;
@@ -303,6 +297,25 @@ bool ScanUtils::StopScheduledScan(uint32_t interface_index) {
   return true;
 }
 
+bool ScanUtils::AbortScan(uint32_t interface_index) {
+  NL80211Packet abort_scan(
+      netlink_manager_->GetFamilyId(),
+      NL80211_CMD_ABORT_SCAN,
+      netlink_manager_->GetSequenceNumber(),
+      getpid());
+
+  // Force an ACK response upon success.
+  abort_scan.AddFlag(NLM_F_ACK);
+  abort_scan.AddAttribute(
+      NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index));
+
+  if (!netlink_manager_->SendMessageAndGetAck(abort_scan)) {
+    LOG(ERROR) << "NL80211_CMD_ABORT_SCAN failed";
+    return false;
+  }
+  return true;
+}
+
 bool ScanUtils::StartScheduledScan(
     uint32_t interface_index,
     uint32_t interval_ms,
index 72398b6..84baeec 100644 (file)
@@ -106,6 +106,10 @@ class ScanUtils {
   // Returns false on error or when there is no scheduled scan running.
   virtual bool StopScheduledScan(uint32_t interface_index);
 
+  // Abort ongoing single scan on interface with index |interface_index|.
+  // Returns true on success.
+  virtual bool AbortScan(uint32_t interface_index);
+
   // Sign up to be notified when new scan results are available.
   // |handler| will be called when the kernel signals to wificond that a scan
   // has been completed on the given |interface_index|.  See the declaration of
index 91bed84..05ebedf 100644 (file)
@@ -53,6 +53,7 @@ ScannerImpl::ScannerImpl(uint32_t wiphy_index,
     : valid_(true),
       scan_started_(false),
       pno_scan_started_(false),
+      offload_scan_supported_(false),
       wiphy_index_(wiphy_index),
       interface_index_(interface_index),
       scan_capabilities_(scan_capabilities),
@@ -79,6 +80,7 @@ ScannerImpl::ScannerImpl(uint32_t wiphy_index,
       new OffloadScanManager(new OffloadServiceUtils(),
           std::bind(&ScannerImpl::OnOffloadScanResult,
               this, _1)));
+  offload_scan_supported_ = offload_scan_manager_->isOffloadScanSupported();
 }
 
 ScannerImpl::~ScannerImpl() {
@@ -213,41 +215,84 @@ Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
 
 Status ScannerImpl::startPnoScan(const PnoSettings& pno_settings,
                                  bool* out_success) {
-  if (!CheckIsValid()) {
-    *out_success = false;
-    return Status::ok();
-  }
-  if (pno_scan_started_) {
-    LOG(WARNING) << "Pno scan already started";
+  if (!offload_scan_supported_ || !StartPnoScanOffload(pno_settings)) {
+    *out_success = StartPnoScanDefault(pno_settings);
+  } else {
+    // scanning over offload succeeded
+    *out_success = true;
   }
-  // An empty ssid for a wild card scan.
-  vector<vector<uint8_t>> scan_ssids = {{}};
+  return Status::ok();
+}
+
+bool ScannerImpl::StartPnoScanOffload(const PnoSettings& pno_settings) {
+  OffloadScanManager::ReasonCode reason_code;
+  vector<vector<uint8_t>> scan_ssids;
   vector<vector<uint8_t>> match_ssids;
+  vector<uint8_t> match_security;
   // Empty frequency list: scan all frequencies.
   vector<uint32_t> freqs;
 
+  ParsePnoSettings(pno_settings, &scan_ssids, &match_ssids, &freqs, &match_security);
+
+  bool success = offload_scan_manager_->startScan(
+          pno_settings.interval_ms_,
+          // TODO: honor both rssi thresholds.
+          pno_settings.min_5g_rssi_,
+          scan_ssids,
+          match_ssids,
+          match_security,
+          freqs,
+          &reason_code);
+  return success;
+}
+
+void ScannerImpl::ParsePnoSettings(const PnoSettings& pno_settings,
+    vector<vector<uint8_t>>* scan_ssids,
+    vector<vector<uint8_t>>* match_ssids,
+    vector<uint32_t>* freqs,
+    vector<uint8_t>* match_security) {
+  // TODO provide actionable security match parameters
+  const uint8_t kNetworkFlagsDefault = 0;
   vector<vector<uint8_t>> skipped_scan_ssids;
   vector<vector<uint8_t>> skipped_match_ssids;
   for (auto& network : pno_settings.pno_networks_) {
     // Add hidden network ssid.
     if (network.is_hidden_) {
-      if (scan_ssids.size() + 1 > scan_capabilities_.max_num_sched_scan_ssids) {
+      // TODO remove pruning for Offload Scans
+      if (scan_ssids->size() + 1 > scan_capabilities_.max_num_sched_scan_ssids) {
         skipped_scan_ssids.emplace_back(network.ssid_);
         continue;
       }
-      scan_ssids.push_back(network.ssid_);
+      scan_ssids->push_back(network.ssid_);
     }
 
-    if (match_ssids.size() + 1 > scan_capabilities_.max_match_sets) {
+    if (match_ssids->size() + 1 > scan_capabilities_.max_match_sets) {
       skipped_match_ssids.emplace_back(network.ssid_);
       continue;
     }
-    match_ssids.push_back(network.ssid_);
+    match_ssids->push_back(network.ssid_);
+    match_security->push_back(kNetworkFlagsDefault);
   }
 
   LogSsidList(skipped_scan_ssids, "Skip scan ssid for pno scan");
   LogSsidList(skipped_match_ssids, "Skip match ssid for pno scan");
+}
+
+bool ScannerImpl::StartPnoScanDefault(const PnoSettings& pno_settings) {
+  if (!CheckIsValid()) {
+      return false;
+  }
+  if (pno_scan_started_) {
+    LOG(WARNING) << "Pno scan already started";
+  }
+  // An empty ssid for a wild card scan.
+  vector<vector<uint8_t>> scan_ssids = {{}};
+  vector<vector<uint8_t>> match_ssids;
+  vector<uint8_t> unused;
+  // Empty frequency list: scan all frequencies.
+  vector<uint32_t> freqs;
 
+  ParsePnoSettings(pno_settings, &scan_ssids, &match_ssids, &freqs, &unused);
   // Only request MAC address randomization when station is not associated.
   bool request_random_mac = wiphy_features_.supports_random_mac_sched_scan &&
       !client_interface_->IsAssociated();
@@ -260,32 +305,56 @@ Status ScannerImpl::startPnoScan(const PnoSettings& pno_settings,
                                        scan_ssids,
                                        match_ssids,
                                        freqs)) {
-    *out_success = false;
     LOG(ERROR) << "Failed to start pno scan";
-    return Status::ok();
+    return false;
   }
   LOG(INFO) << "Pno scan started";
   pno_scan_started_ = true;
-  *out_success = true;
-  return Status::ok();
+  return true;
 }
 
 Status ScannerImpl::stopPnoScan(bool* out_success) {
+  if (!offload_scan_supported_ || !StopPnoScanOffload()) {
+    *out_success = StopPnoScanDefault();
+  } else {
+    // Pno scans over offload stopped successfully
+    *out_success = true;
+  }
+  return Status::ok();
+}
+
+bool ScannerImpl::StopPnoScanOffload() {
+  OffloadScanManager::ReasonCode reason_code;
+  return(offload_scan_manager_->stopScan(&reason_code));
+}
+
+bool ScannerImpl::StopPnoScanDefault() {
   if (!CheckIsValid()) {
-    *out_success = false;
-    return Status::ok();
+    return false;
   }
 
   if (!pno_scan_started_) {
     LOG(WARNING) << "No pno scan started";
   }
   if (!scan_utils_->StopScheduledScan(interface_index_)) {
-    *out_success = false;
-    return Status::ok();
+    return false;
   }
   LOG(INFO) << "Pno scan stopped";
   pno_scan_started_ = false;
-  *out_success = true;
+  return true;
+}
+
+Status ScannerImpl::abortScan(bool* out_success) {
+  *out_success = false;
+  if (!CheckIsValid()) {
+    return Status::ok();
+  }
+
+  if (!scan_started_) {
+    LOG(WARNING) << "Scan is not started. Ignore abort request";
+  } else if (scan_utils_->AbortScan(interface_index_)) {
+    *out_success = true;
+  }
   return Status::ok();
 }
 
@@ -385,9 +454,9 @@ void ScannerImpl::LogSsidList(vector<vector<uint8_t>>& ssid_list,
 
 void ScannerImpl::OnOffloadScanResult(
     std::vector<NativeScanResult> scanResult) {
-  // TODO: Process scan result
-  if (scan_event_handler_ != nullptr) {
-    scan_event_handler_->OnScanResultReady();
+  LOG(INFO) << "Offload Scan results received";
+  if (pno_scan_event_handler_ != nullptr) {
+    pno_scan_event_handler_->OnPnoNetworkFound();
   } else {
     LOG(WARNING) << "No scan event handler Offload Scan result";
   }
index 5950cae..20bed00 100644 (file)
@@ -63,6 +63,7 @@ class ScannerImpl : public android::net::wifi::BnWifiScannerImpl {
       const ::com::android::server::wifi::wificond::PnoSettings& pno_settings,
       bool* out_success) override;
   ::android::binder::Status stopPnoScan(bool* out_success) override;
+  ::android::binder::Status abortScan(bool* out_success) override;
 
   ::android::binder::Status subscribeScanEvents(
       const ::android::sp<::android::net::wifi::IScanEvent>& handler) override;
@@ -84,11 +85,23 @@ class ScannerImpl : public android::net::wifi::BnWifiScannerImpl {
   void OnSchedScanResultsReady(uint32_t interface_index, bool scan_stopped);
   void LogSsidList(std::vector<std::vector<uint8_t>>& ssid_list,
                    std::string prefix);
-
+  bool StartPnoScanDefault(
+      const ::com::android::server::wifi::wificond::PnoSettings& pno_settings);
+  bool StartPnoScanOffload(
+      const ::com::android::server::wifi::wificond::PnoSettings& pno_settings);
+  bool StopPnoScanDefault();
+  bool StopPnoScanOffload();
+  void ParsePnoSettings(
+    const ::com::android::server::wifi::wificond::PnoSettings& pno_settings,
+    std::vector<std::vector<uint8_t>>* scan_ssids,
+    std::vector<std::vector<uint8_t>>* match_ssids,
+    std::vector<uint32_t>* freqs,
+    std::vector<uint8_t>* match_security);
   // Boolean variables describing current scanner status.
   bool valid_;
   bool scan_started_;
   bool pno_scan_started_;
+  bool offload_scan_supported_;
 
   const uint32_t wiphy_index_;
   const uint32_t interface_index_;
diff --git a/tests/offload_hal_test_constants.cpp b/tests/offload_hal_test_constants.cpp
new file mode 100644 (file)
index 0000000..4214f56
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 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 "offload_hal_test_constants.h"
+
+namespace android {
+namespace wificond {
+namespace offload_hal_test_constants {
+
+const uint8_t kSsid1[] = { 'G', 'o', 'o', 'g', 'l', 'e' };
+const size_t kSsid1_size = sizeof(kSsid1);
+const uint8_t kSsid2[] = { 'X', 'f', 'i', 'n', 'i', 't', 'y' };
+const size_t kSsid2_size = sizeof(kSsid2);
+const uint8_t kBssid [6] = { 0x12, 0xef, 0xa1, 0x2c, 0x97, 0x8b };
+const int16_t kRssi = -60;
+const int16_t kRssiThreshold = -76;
+const uint32_t kFrequency1 = 2412;
+const uint32_t kFrequency2 = 2437;
+const uint8_t kBssidSize = 6;
+const uint64_t kTsf = 0;
+const uint16_t kCapability = 0;
+const uint8_t kNetworkFlags = 0;
+const uint32_t kDisconnectedModeScanIntervalMs = 5000;
+const uint64_t kSubscriptionDurationMs = 10000;
+const uint64_t kScanDurationMs[2] = { 2000, 500 };
+const uint32_t kNumChannelsScanned[2] = { 14, 6 };
+const uint8_t kDefaultNumTimesAChannelsIsScanned = 1;
+const uint8_t kChannelNotScanned = 0;
+const uint32_t kDefaultNumScansRequestedByWifi = 2;
+const uint32_t kDefaultNumScansServicedByWifi = 2;
+const uint64_t kScanDurationTotalMs = 2000;
+const uint32_t kNumChannelsTotalScanned = 20;
+
+}  // namespace offload_hal_test_constants
+}  // namespace wificond
+}  // namespace android
+
diff --git a/tests/offload_hal_test_constants.h b/tests/offload_hal_test_constants.h
new file mode 100644 (file)
index 0000000..d0b7138
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef WIFICOND_OFFLOAD_HAL_TEST_CONSTANTS_H_
+#define WIFICOND_OFFLOAD_HAL_TEST_CONSTANTS_H_
+
+#include <cstdint>
+
+namespace android {
+namespace wificond {
+namespace offload_hal_test_constants {
+
+extern const uint8_t kSsid1[];
+extern const size_t kSsid1_size;
+extern const uint8_t kSsid2[];
+extern const size_t kSsid2_size;
+extern const uint8_t kBssid [6];
+extern const int16_t kRssi;
+extern const int16_t kRssiThreshold;
+extern const uint32_t kFrequency1;
+extern const uint32_t kFrequency2;
+extern const uint8_t kBssidSize;
+extern const uint64_t kTsf;
+extern const uint16_t kCapability;
+extern const uint8_t kNetworkFlags;
+extern const uint32_t kDisconnectedModeScanIntervalMs;
+extern const uint64_t kSubscriptionDurationMs;
+extern const uint64_t kScanDurationMs[2];
+extern const uint32_t kNumChannelsScanned[2];
+extern const uint8_t kDefaultNumTimesAChannelsIsScanned;
+extern const uint8_t kChannelNotScanned;
+extern const uint32_t kDefaultNumScansRequestedByWifi;
+extern const uint32_t kDefaultNumScansServicedByWifi;
+extern const uint64_t kScanDurationTotalMs;
+extern const uint32_t kNumChannelsTotalScanned;
+
+}  // namespace offload_hal_test_constants
+}  // namespace wificond
+}  // namespace android
+
+#endif  // WIFICOND_OFFLOAD_HAL_TEST_CONSTANTS_H_
index cfccbc4..53f423f 100644 (file)
 #include <gtest/gtest.h>
 #include <android/hardware/wifi/offload/1.0/IOffload.h>
 
+#include "wificond/tests/offload_hal_test_constants.h"
+#include "wificond/tests/offload_test_utils.h"
 #include "wificond/tests/mock_offload.h"
 #include "wificond/tests/mock_offload_service_utils.h"
-#include "wificond/tests/offload_test_utils.h"
 
 #include "wificond/scanning/scan_result.h"
 #include "wificond/scanning/offload/offload_callback.h"
 
 using android::hardware::wifi::offload::V1_0::ScanResult;
 using android::hardware::wifi::offload::V1_0::OffloadStatus;
+using android::hardware::wifi::offload::V1_0::ScanParam;
+using android::hardware::wifi::offload::V1_0::ScanFilter;
 using com::android::server::wifi::wificond::NativeScanResult;
+using com::android::server::wifi::wificond::NativeScanStats;
 using testing::NiceMock;
 using testing::_;
 using testing::Invoke;
@@ -43,6 +47,7 @@ using std::vector;
 using std::bind;
 
 using namespace std::placeholders;
+using namespace android::wificond::offload_hal_test_constants;
 
 namespace android {
 namespace wificond {
@@ -72,6 +77,10 @@ class OffloadScanManagerTest: public ::testing::Test {
     unique_ptr<NiceMock<MockOffloadServiceUtils>> mock_offload_service_utils_{
         new NiceMock<MockOffloadServiceUtils>()};
     unique_ptr<OffloadScanManager> offload_scan_manager_;
+    vector<vector<uint8_t>> scan_ssids { kSsid1, kSsid2};
+    vector<vector<uint8_t>> match_ssids { kSsid1, kSsid2 };
+    vector<uint8_t> security_flags { kNetworkFlags, kNetworkFlags };
+    vector<uint32_t> frequencies { kFrequency1, kFrequency2 };
 };
 
 /**
@@ -79,7 +88,8 @@ class OffloadScanManagerTest: public ::testing::Test {
  */
 TEST_F(OffloadScanManagerTest, ServiceUtilsNotAvailableTest) {
   offload_scan_manager_.reset(new OffloadScanManager(nullptr, nullptr));
-  EXPECT_EQ(OffloadScanManager::kError, offload_scan_manager_->getOffloadStatus());
+  EXPECT_EQ(OffloadScanManager::kNoService,
+      offload_scan_manager_->getOffloadStatus());
 }
 
 /**
@@ -89,9 +99,11 @@ TEST_F(OffloadScanManagerTest, ServiceUtilsNotAvailableTest) {
 TEST_F(OffloadScanManagerTest, ServiceNotAvailableTest) {
   ON_CALL(*mock_offload_service_utils_, GetOffloadService())
       .WillByDefault(testing::Return(nullptr));
-  offload_scan_manager_.reset(new OffloadScanManager(mock_offload_service_utils_.get(),
-      [] (std::vector<NativeScanResult> scanResult) -> void {}));
-  EXPECT_EQ(OffloadScanManager::kNoService, offload_scan_manager_->getOffloadStatus());
+  offload_scan_manager_.reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [] (vector<NativeScanResult> scanResult) -> void {}));
+  EXPECT_EQ(OffloadScanManager::kNoService,
+      offload_scan_manager_->getOffloadStatus());
 }
 
 /**
@@ -102,9 +114,11 @@ TEST_F(OffloadScanManagerTest, ServiceAvailableTest) {
   EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
   ON_CALL(*mock_offload_service_utils_, GetOffloadService())
       .WillByDefault(testing::Return(mock_offload_));
-  offload_scan_manager_ .reset(new OffloadScanManager(mock_offload_service_utils_.get(),
-    [] (vector<NativeScanResult> scanResult) -> void {}));
-  EXPECT_EQ(OffloadScanManager::kNoError, offload_scan_manager_->getOffloadStatus());
+  offload_scan_manager_ .reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [] (vector<NativeScanResult> scanResult) -> void {}));
+  EXPECT_EQ(OffloadScanManager::kNoError,
+      offload_scan_manager_->getOffloadStatus());
 }
 
 /**
@@ -117,11 +131,13 @@ TEST_F(OffloadScanManagerTest, CallbackInvokedTest) {
   EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
   ON_CALL(*mock_offload_service_utils_, GetOffloadService())
       .WillByDefault(testing::Return(mock_offload_));
-  offload_scan_manager_.reset(new OffloadScanManager(mock_offload_service_utils_.get(),
-    [&callback_invoked] (vector<NativeScanResult> scanResult) -> void {
+  offload_scan_manager_.reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [&callback_invoked] (vector<NativeScanResult> scanResult) -> void {
         callback_invoked = true;
-    }));
-  vector<ScanResult> dummy_scan_results_ = OffloadTestUtils::createOffloadScanResults();
+      }));
+  vector<ScanResult> dummy_scan_results_ =
+      OffloadTestUtils::createOffloadScanResults();
   offload_callback_->onScanResult(dummy_scan_results_);
   EXPECT_EQ(true, callback_invoked);
 }
@@ -134,11 +150,231 @@ TEST_F(OffloadScanManagerTest, ErrorCallbackInvokedTest) {
   EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
   ON_CALL(*mock_offload_service_utils_, GetOffloadService())
       .WillByDefault(testing::Return(mock_offload_));
-  offload_scan_manager_.reset(new OffloadScanManager(mock_offload_service_utils_.get(),
-    [this] (std::vector<NativeScanResult> scanResult) -> void {}));
+  offload_scan_manager_.reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [this] (vector<NativeScanResult> scanResult) -> void {}));
   offload_callback_->onError(OffloadStatus::OFFLOAD_STATUS_ERROR);
-  EXPECT_EQ(offload_scan_manager_->getOffloadStatus(), OffloadScanManager::kError);
+  EXPECT_EQ(offload_scan_manager_->getOffloadStatus(),
+      OffloadScanManager::kError);
+}
+
+/**
+ * Testing OffloadScanManager for subscribing to the scan results from
+ * Offload HAL when service is running without errors
+ */
+TEST_F(OffloadScanManagerTest, StartScanTestWhenServiceIsOk) {
+  EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+  ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+      .WillByDefault(testing::Return(mock_offload_));
+  offload_scan_manager_ .reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [] (vector<NativeScanResult> scanResult) -> void {}));
+  EXPECT_CALL(*mock_offload_, subscribeScanResults(_));
+  EXPECT_CALL(*mock_offload_, configureScans(_, _));
+  OffloadScanManager::ReasonCode reason_code = OffloadScanManager::kNone;
+  bool result = offload_scan_manager_->startScan(
+      kDisconnectedModeScanIntervalMs,
+      kRssiThreshold,
+      scan_ssids,
+      match_ssids,
+      security_flags,
+      frequencies,
+      &reason_code);
+  EXPECT_EQ(result, true);
+}
+
+/**
+ * Testing OffloadScanManager for subscribing to the scan results from
+ * Offload HAL when service is not available
+ */
+TEST_F(OffloadScanManagerTest, StartScanTestWhenServiceIsNotAvailable) {
+  EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+  ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+      .WillByDefault(testing::Return(nullptr));
+  offload_scan_manager_ .reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [] (vector<NativeScanResult> scanResult) -> void {}));
+  OffloadScanManager::ReasonCode reason_code = OffloadScanManager::kNone;
+  bool result = offload_scan_manager_->startScan(
+      kDisconnectedModeScanIntervalMs,
+      kRssiThreshold,
+      scan_ssids,
+      match_ssids,
+      security_flags,
+      frequencies,
+      &reason_code);
+  EXPECT_EQ(result, false);
+  EXPECT_EQ(reason_code, OffloadScanManager::kNotSupported);
+}
+
+/**
+ * Testing OffloadScanManager for subscribing to the scan results from
+ * Offload HAL when service is not working correctly
+ */
+TEST_F(OffloadScanManagerTest, StartScanTestWhenServiceIsNotConnected) {
+  EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+  ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+      .WillByDefault(testing::Return(mock_offload_));
+  offload_scan_manager_ .reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [] (vector<NativeScanResult> scanResult) -> void {}));
+  offload_callback_->onError(OffloadStatus::OFFLOAD_STATUS_NO_CONNECTION);
+  OffloadScanManager::ReasonCode reason_code = OffloadScanManager::kNone;
+  bool result = offload_scan_manager_->startScan(
+      kDisconnectedModeScanIntervalMs,
+      kRssiThreshold,
+      scan_ssids,
+      match_ssids,
+      security_flags,
+      frequencies,
+      &reason_code);
+  EXPECT_EQ(result, false);
+  EXPECT_EQ(reason_code, OffloadScanManager::kNotAvailable);
+}
+
+/**
+ * Testing OffloadScanManager for subscribing to the scan results from
+ * Offload HAL twice when service is okay
+ */
+TEST_F(OffloadScanManagerTest, StartScanTwiceTestWhenServiceIsOk) {
+  EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+  ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+      .WillByDefault(testing::Return(mock_offload_));
+  offload_scan_manager_ .reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [] (vector<NativeScanResult> scanResult) -> void {}));
+  EXPECT_CALL(*mock_offload_, subscribeScanResults(_)).Times(1);
+  EXPECT_CALL(*mock_offload_, configureScans(_, _)).Times(2);
+  OffloadScanManager::ReasonCode reason_code = OffloadScanManager::kNone;
+  bool result = offload_scan_manager_->startScan(
+      kDisconnectedModeScanIntervalMs,
+      kRssiThreshold,
+      scan_ssids,
+      match_ssids,
+      security_flags,
+      frequencies,
+      &reason_code);
+  EXPECT_EQ(result, true);
+  result = offload_scan_manager_->startScan(
+      kDisconnectedModeScanIntervalMs,
+      kRssiThreshold,
+      scan_ssids,
+      match_ssids,
+      security_flags,
+      frequencies,
+      &reason_code);
+  EXPECT_EQ(result, true);
+}
+
+/**
+ * Testing OffloadScanManager for unsubscribing to the scan results from
+ * Offload HAL when service is ok
+ */
+TEST_F(OffloadScanManagerTest, StopScanTestWhenServiceIsOk) {
+  EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+  ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+      .WillByDefault(testing::Return(mock_offload_));
+  offload_scan_manager_ .reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [] (vector<NativeScanResult> scanResult) -> void {}));
+  EXPECT_CALL(*mock_offload_, subscribeScanResults(_));
+  EXPECT_CALL(*mock_offload_, configureScans(_, _));
+  EXPECT_CALL(*mock_offload_, unsubscribeScanResults());
+  OffloadScanManager::ReasonCode reason_code = OffloadScanManager::kNone;
+  bool result = offload_scan_manager_->startScan(
+      kDisconnectedModeScanIntervalMs,
+      kRssiThreshold,
+      scan_ssids,
+      match_ssids,
+      security_flags,
+      frequencies,
+      &reason_code);
+  EXPECT_EQ(result, true);
+  result = offload_scan_manager_->stopScan(&reason_code);
+  EXPECT_EQ(result, true);
+}
+
+/**
+ * Testing OffloadScanManager for unsubscribing to the scan results from
+ * Offload HAL without first subscribing
+ */
+TEST_F(OffloadScanManagerTest, StopScanTestWithoutStartWhenServiceIsOk) {
+  EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+  ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+      .WillByDefault(testing::Return(mock_offload_));
+  offload_scan_manager_ .reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [] (vector<NativeScanResult> scanResult) -> void {}));
+  OffloadScanManager::ReasonCode reason_code = OffloadScanManager::kNone;
+  bool result = offload_scan_manager_->stopScan(&reason_code);
+  EXPECT_EQ(result, false);
+  EXPECT_EQ(reason_code, OffloadScanManager::kNotSubscribed);
+}
+
+/**
+ * Testing OffloadScanManager for unsubscribing to the scan results from
+ * Offload HAL without first subscribing when service is not working correctly
+ */
+TEST_F(OffloadScanManagerTest, StopScanTestWhenServiceIsNotConnectedAnymore) {
+  EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+  ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+      .WillByDefault(testing::Return(mock_offload_));
+  offload_scan_manager_ .reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [] (vector<NativeScanResult> scanResult) -> void {}));
+  EXPECT_CALL(*mock_offload_, subscribeScanResults(_));
+  EXPECT_CALL(*mock_offload_, configureScans(_, _));
+  EXPECT_CALL(*mock_offload_, unsubscribeScanResults());
+  OffloadScanManager::ReasonCode reason_code = OffloadScanManager::kNone;
+  bool result = offload_scan_manager_->startScan(
+      kDisconnectedModeScanIntervalMs,
+      kRssiThreshold,
+      scan_ssids,
+      match_ssids,
+      security_flags,
+      frequencies,
+      &reason_code);
+  EXPECT_EQ(result, true);
+  offload_callback_->onError(OffloadStatus::OFFLOAD_STATUS_NO_CONNECTION);
+  result = offload_scan_manager_->stopScan(&reason_code);
+  EXPECT_EQ(result, true);
+}
+
+/**
+ * Testing OffloadScanManager for getting scan statistics when the
+ * Offload HAL service is running without errors
+ */
+TEST_F(OffloadScanManagerTest, getScanStatsTestWhenServiceIsOk) {
+  EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+  ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+      .WillByDefault(testing::Return(mock_offload_));
+  offload_scan_manager_ .reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [] (vector<NativeScanResult> scanResult) -> void {}));
+  EXPECT_CALL(*mock_offload_, getScanStats(_));
+  NativeScanStats stats;
+  bool result = offload_scan_manager_->getScanStats(&stats);
+  EXPECT_EQ(result, true);
+}
+
+/**
+ * Testing OffloadScanManager for getting scan statistics when the
+ * Offload HAL service is not connected
+ */
+TEST_F(OffloadScanManagerTest, getScanStatsTestWhenServiceIsNotOk) {
+  EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+  ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+      .WillByDefault(testing::Return(mock_offload_));
+  offload_scan_manager_ .reset(new OffloadScanManager(
+      mock_offload_service_utils_.get(),
+      [] (vector<NativeScanResult> scanResult) -> void {}));
+  offload_callback_->onError(OffloadStatus::OFFLOAD_STATUS_NO_CONNECTION);
+  EXPECT_CALL(*mock_offload_, getScanStats(_)).Times(0);
+  NativeScanStats stats;
+  bool result = offload_scan_manager_->getScanStats(&stats);
+  EXPECT_EQ(result, false);
 }
 
 } // namespace wificond
 } // namespace android
+
index d7463ce..e01a298 100644 (file)
 
 #include <gtest/gtest.h>
 #include "wificond/tests/offload_test_utils.h"
-
+#include <android-base/logging.h>
 #include "wificond/scanning/scan_result.h"
 #include "wificond/scanning/offload/offload_scan_utils.h"
+#include "wificond/tests/offload_hal_test_constants.h"
 
 using android::hardware::wifi::offload::V1_0::ScanResult;
+using android::hardware::wifi::offload::V1_0::ScanParam;
+using android::hardware::wifi::offload::V1_0::ScanFilter;
+using android::hardware::wifi::offload::V1_0::NetworkInfo;
+using android::hardware::wifi::offload::V1_0::ScanRecord;
+using android::hardware::wifi::offload::V1_0::ScanStats;
 using ::com::android::server::wifi::wificond::NativeScanResult;
+using ::com::android::server::wifi::wificond::NativeScanStats;
+using std::vector;
+
+using namespace android::wificond::offload_hal_test_constants;
 
 namespace android {
 namespace wificond {
@@ -38,22 +48,69 @@ class OffloadScanUtilsTest : public ::testing::Test {
     dummy_scan_results_.clear();
   }
 
-  std::vector<ScanResult> dummy_scan_results_;
+  vector<ScanResult> dummy_scan_results_;
 };
 
 TEST_F(OffloadScanUtilsTest, verifyConversion) {
-  std::vector<NativeScanResult> native_scan_results =
+  vector<NativeScanResult> native_scan_results =
       OffloadScanUtils::convertToNativeScanResults(dummy_scan_results_);
   EXPECT_EQ(native_scan_results.size(), dummy_scan_results_.size());
   for (size_t i = 0; i < native_scan_results.size(); i++) {
     EXPECT_EQ(native_scan_results[i].frequency, dummy_scan_results_[i].frequency);
     EXPECT_EQ(native_scan_results[i].tsf, dummy_scan_results_[i].tsf);
     EXPECT_EQ(native_scan_results[i].signal_mbm, dummy_scan_results_[i].rssi);
-    EXPECT_EQ(native_scan_results[i].ssid.size(), dummy_scan_results_[i].networkInfo.ssid.size());
-    EXPECT_EQ(native_scan_results[i].bssid.size(), dummy_scan_results_[i].bssid.elementCount());
+    EXPECT_EQ(native_scan_results[i].ssid.size(),
+        dummy_scan_results_[i].networkInfo.ssid.size());
+    EXPECT_EQ(native_scan_results[i].bssid.size(),
+        dummy_scan_results_[i].bssid.elementCount());
     EXPECT_EQ(native_scan_results[i].capability, dummy_scan_results_[i].capability);
   }
 }
 
+TEST_F(OffloadScanUtilsTest, verifyScanParam) {
+  vector<vector<uint8_t>> scan_ssids { kSsid1, kSsid2};
+  vector<uint32_t> frequencies { kFrequency1, kFrequency2 };
+  ScanParam scanParam = OffloadScanUtils::createScanParam(scan_ssids, frequencies,
+      kDisconnectedModeScanIntervalMs);
+  EXPECT_EQ(scanParam.disconnectedModeScanIntervalMs,
+      kDisconnectedModeScanIntervalMs);
+  for (size_t i = 0; i < frequencies.size(); i++) {
+    EXPECT_EQ(scanParam.frequencyList[i], frequencies[i]);
+  }
+  for (size_t j = 0; j < scan_ssids.size(); j++) {
+    vector<uint8_t> ssid_result = scanParam.ssidList[j];
+    vector<uint8_t> ssid_input = scan_ssids[j];
+    for (size_t k = 0; k < ssid_result.size(); k++) {
+      EXPECT_EQ(ssid_result[k], ssid_input[k]);
+    }
+  }
+}
+
+TEST_F(OffloadScanUtilsTest, verifyScanFilter) {
+  vector<vector<uint8_t>> match_ssids { kSsid1, kSsid2 };
+  vector<uint8_t> security_flags { kNetworkFlags, kNetworkFlags };
+  ScanFilter scanFilter = OffloadScanUtils::createScanFilter(match_ssids,
+      security_flags, kRssiThreshold);
+  EXPECT_EQ(kRssiThreshold, scanFilter.rssiThreshold);
+  EXPECT_FALSE(scanFilter.preferredNetworkInfoList.size() == 0);
+  for (size_t i = 0; i < security_flags.size(); ++i) {
+    NetworkInfo nwInfo = scanFilter.preferredNetworkInfoList[i];
+    vector<uint8_t> ssid = nwInfo.ssid;
+    vector<uint8_t> match_ssid = match_ssids[i];
+    EXPECT_EQ(nwInfo.flags, security_flags[i]);
+    for (size_t j = 0; j < ssid.size(); j++) {
+      EXPECT_EQ(ssid[j], match_ssid[j]);
+    }
+  }
+}
+
+TEST_F(OffloadScanUtilsTest, verifyScanStats) {
+  NativeScanStats stats_expected;
+  ScanStats offload_scan_stats = OffloadTestUtils::createScanStats(&stats_expected);
+  NativeScanStats stats_returned = OffloadScanUtils::convertToNativeScanStats(
+    offload_scan_stats);
+  EXPECT_TRUE(stats_expected == stats_returned);
+}
+
 } // namespace wificond
 } // namespace android
index 4309006..6302f24 100644 (file)
 #include <vector>
 
 #include "wificond/tests/offload_test_utils.h"
+#include "wificond/tests/offload_hal_test_constants.h"
 
 using android::hardware::wifi::offload::V1_0::ScanResult;
+using android::hardware::wifi::offload::V1_0::ScanStats;
+using android::hardware::wifi::offload::V1_0::ScanRecord;
+using namespace android::wificond::offload_hal_test_constants;
 
 namespace android {
 namespace wificond {
 
-namespace {
-  const uint8_t kSsid[] = { 'G', 'o', 'o', 'g', 'l', 'e' };
-  const uint8_t kBssid [6] = { 0x12, 0xef, 0xa1, 0x2c, 0x97, 0x8b };
-  const int16_t kRssi = -60;
-  const uint32_t kFrequency = 2412;
-  const uint8_t kBssidSize = 6;
-  const uint64_t kTsf = 0;
-  const uint16_t kCapability = 0;
-  const uint8_t kNetworkFlags = 0;
-} // namespace
-
 std::vector<ScanResult> OffloadTestUtils::createOffloadScanResults() {
   std::vector<ScanResult> scanResults;
   ScanResult scanResult;
-  std::vector<uint8_t> ssid(kSsid, kSsid + sizeof(kSsid));
+  std::vector<uint8_t> ssid(kSsid1, kSsid1 + kSsid1_size);
   scanResult.tsf = kTsf;
   scanResult.rssi = kRssi;
-  scanResult.frequency = kFrequency;
+  scanResult.frequency = kFrequency1;
   scanResult.capability = kCapability;
   memcpy(&scanResult.bssid[0], &kBssid[0], kBssidSize);
   scanResult.networkInfo.ssid = ssid;
@@ -49,5 +42,46 @@ std::vector<ScanResult> OffloadTestUtils::createOffloadScanResults() {
   return scanResults;
 }
 
+ScanStats OffloadTestUtils::createScanStats(NativeScanStats* nativeScanStats) {
+  std::vector<ScanRecord> scan_records;
+  std::vector<uint8_t> histogram_channels;
+  uint32_t scan_duration_ms = 0;
+  uint32_t num_channels_scanned = 0;
+  ScanStats scan_stats;
+  int numEntriesInScanRecord =
+      sizeof(kNumChannelsScanned)/sizeof(kNumChannelsScanned[0]);
+  for (int i = 0; i < numEntriesInScanRecord; i++) {
+    ScanRecord scan_record;
+    scan_record.durationMs = kScanDurationMs[i];
+    scan_duration_ms += kScanDurationMs[i];
+    scan_record.numChannelsScanned = kNumChannelsScanned[i];
+    num_channels_scanned += kNumChannelsScanned[i];
+    scan_record.numEntriesAggregated = 1;
+    scan_records.push_back(scan_record);
+  }
+  scan_stats.scanRecord = scan_records;
+  scan_stats.numScansRequestedByWifi = kDefaultNumScansRequestedByWifi;
+  scan_stats.numScansServicedByWifi = kDefaultNumScansServicedByWifi;
+  scan_stats.subscriptionDurationMs = kSubscriptionDurationMs;
+  uint32_t skip_tmp = 256/num_channels_scanned;
+  for(size_t i = 0; i < 256; i++) {
+    if (i % skip_tmp == 0) {
+      scan_stats.histogramChannelsScanned[i] = kDefaultNumTimesAChannelsIsScanned;
+      histogram_channels.push_back(kDefaultNumTimesAChannelsIsScanned);
+    } else {
+      scan_stats.histogramChannelsScanned[i] = kChannelNotScanned;
+      histogram_channels.push_back(kChannelNotScanned);
+    }
+  }
+  NativeScanStats native_scan_stats(kDefaultNumScansRequestedByWifi,
+      kDefaultNumScansServicedByWifi,
+      kSubscriptionDurationMs,
+      scan_duration_ms,
+      num_channels_scanned,
+      histogram_channels);
+  *nativeScanStats = native_scan_stats;
+  return scan_stats;
+}
+
 } // namespace wificond
 } // namespace android
index 621f297..e624ec1 100644 (file)
 
 #include <android/hardware/wifi/offload/1.0/IOffload.h>
 #include <vector>
+
+#include "wificond/scanning/offload/scan_stats.h"
+
 using android::hardware::wifi::offload::V1_0::ScanResult;
+using android::hardware::wifi::offload::V1_0::ScanStats;
+using ::com::android::server::wifi::wificond::NativeScanStats;
+
 namespace android {
 namespace wificond {
 
 class OffloadTestUtils {
  public:
   static std::vector<ScanResult> createOffloadScanResults();
+  static ScanStats createScanStats(NativeScanStats* /* nativeScanStats */);
 };
 
 } // namespace wificond
diff --git a/tests/scan_stats_unittest.cpp b/tests/scan_stats_unittest.cpp
new file mode 100644 (file)
index 0000000..a867378
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017, 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 <vector>
+
+#include <gtest/gtest.h>
+
+#include "wificond/scanning/offload/scan_stats.h"
+#include "wificond/tests/offload_hal_test_constants.h"
+
+using ::com::android::server::wifi::wificond::NativeScanStats;
+using namespace android::wificond::offload_hal_test_constants;
+
+namespace android {
+namespace wificond {
+
+class ScanStatsTest : public ::testing::Test {
+};
+
+TEST_F(ScanStatsTest, ParcelableTest) {
+  std::vector<uint8_t> histogram_channels;
+  for(size_t i = 0; i < 256; i++) {
+    histogram_channels.push_back(255 - i);
+  }
+  NativeScanStats  scan_stats_in(kDefaultNumScansRequestedByWifi,
+      kDefaultNumScansServicedByWifi,
+      kScanDurationTotalMs,
+      kSubscriptionDurationMs,
+      kNumChannelsTotalScanned,
+      histogram_channels);
+  Parcel parcel;
+  EXPECT_EQ(::android::OK, scan_stats_in.writeToParcel(&parcel));
+  NativeScanStats scan_stats_out;
+  parcel.setDataPosition(0);
+  EXPECT_EQ(::android::OK, scan_stats_out.readFromParcel(&parcel));
+  EXPECT_TRUE(scan_stats_in == scan_stats_out);
+}
+
+} // namespace wificond
+} // namespace android