Merge "wificond.rc: Set CAP_NET_RAW and CAP_NET_ADMIN explicitly rather then implictly via group"
am: 7a83a7b6ae
Change-Id: Ief0640e87120c4aa3c7e5b1874f307a1baf43ef4
diff --git a/Android.mk b/Android.mk
index e293246..a5dc6e0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -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)
@@ -30,12 +33,17 @@
LOCAL_SRC_FILES := \
main.cpp
LOCAL_SHARED_LIBRARIES := \
+ android.hardware.wifi.offload@1.0 \
libbinder \
libbase \
libcutils \
+ libhidlbase \
+ libhwbinder \
+ libhidltransport \
libminijail \
libutils \
- libwifi-system
+ libwifi-system \
+ libwifi-system-iface
LOCAL_STATIC_LIBRARIES := \
libwificond
include $(BUILD_EXECUTABLE)
@@ -61,14 +69,24 @@
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 \
+ scanning/offload/offload_scan_manager.cpp \
+ scanning/offload/offload_callback.cpp \
+ scanning/offload/offload_service_utils.cpp \
+ scanning/offload/offload_scan_utils.cpp \
server.cpp
LOCAL_SHARED_LIBRARIES := \
+ android.hardware.wifi.offload@1.0 \
libbase \
libutils \
- libwifi-system
+ libhidlbase \
+ libhwbinder \
+ libhidltransport \
+ libwifi-system \
+ libwifi-system-iface
LOCAL_WHOLE_STATIC_LIBRARIES := \
libwificond_ipc \
libwificond_nl
@@ -152,29 +170,46 @@
tests/client_interface_impl_unittest.cpp \
tests/looper_backed_event_loop_unittest.cpp \
tests/main.cpp \
+ tests/mock_client_interface_impl.cpp \
tests/mock_netlink_manager.cpp \
tests/mock_netlink_utils.cpp \
+ tests/mock_offload.cpp \
+ tests/mock_offload_callback_handlers.cpp \
+ tests/mock_offload_service_utils.cpp \
tests/mock_scan_utils.cpp \
tests/netlink_manager_unittest.cpp \
tests/netlink_utils_unittest.cpp \
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/scanner_unittest.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 := \
libgmock \
libgtest \
libwifi-system-test \
+ libwifi-system-iface-test \
libwificond \
libwificond_nl
LOCAL_SHARED_LIBRARIES := \
+ android.hardware.wifi.offload@1.0 \
libbase \
libbinder \
+ libhidltransport \
+ libhidlbase \
+ libhwbinder \
liblog \
libutils \
- libwifi-system
+ libwifi-system \
+ libwifi-system-iface
include $(BUILD_NATIVE_TEST)
###
@@ -197,7 +232,8 @@
libbinder \
libcutils \
libutils \
- libwifi-system
+ libwifi-system \
+ libwifi-system-iface
LOCAL_STATIC_LIBRARIES := \
libgmock \
libwificond_ipc \
diff --git a/client_interface_impl.cpp b/client_interface_impl.cpp
index 405d1fd..974ff17 100644
--- a/client_interface_impl.cpp
+++ b/client_interface_impl.cpp
@@ -24,6 +24,7 @@
#include "wificond/client_interface_binder.h"
#include "wificond/net/mlme_event.h"
#include "wificond/net/netlink_utils.h"
+#include "wificond/scanning/offload/offload_service_utils.h"
#include "wificond/scanning/scan_result.h"
#include "wificond/scanning/scan_utils.h"
#include "wificond/scanning/scanner_impl.h"
@@ -116,6 +117,7 @@
supplicant_manager_(supplicant_manager),
netlink_utils_(netlink_utils),
scan_utils_(scan_utils),
+ offload_service_utils_(new OffloadServiceUtils()),
mlme_event_handler_(new MlmeEventHandlerImpl(this)),
binder_(new ClientInterfaceBinder(this)),
is_associated_(false) {
@@ -136,7 +138,8 @@
wiphy_features_,
this,
netlink_utils_,
- scan_utils_);
+ scan_utils_,
+ offload_service_utils_);
}
ClientInterfaceImpl::~ClientInterfaceImpl() {
@@ -161,6 +164,12 @@
<< static_cast<int>(scan_capabilities_.max_num_sched_scan_ssids) << endl;
*ss << "Max number of match sets for scheduled scan: "
<< static_cast<int>(scan_capabilities_.max_match_sets) << endl;
+ *ss << "Maximum number of scan plans: "
+ << scan_capabilities_.max_num_scan_plans << endl;
+ *ss << "Max scan plan interval in seconds: "
+ << scan_capabilities_.max_scan_plan_interval << endl;
+ *ss << "Max scan plan iterations: "
+ << scan_capabilities_.max_scan_plan_iterations << endl;
*ss << "Device supports random MAC for single shot scan: "
<< wiphy_features_.supports_random_mac_oneshot_scan << endl;
*ss << "Device supports random MAC for scheduled scan: "
diff --git a/client_interface_impl.h b/client_interface_impl.h
index 41f6a09..6ce0547 100644
--- a/client_interface_impl.h
+++ b/client_interface_impl.h
@@ -27,6 +27,7 @@
#include "android/net/wifi/IClientInterface.h"
#include "wificond/net/mlme_event_handler.h"
#include "wificond/net/netlink_utils.h"
+#include "wificond/scanning/offload/offload_service_utils.h"
#include "wificond/scanning/scanner_impl.h"
namespace android {
@@ -67,7 +68,7 @@
android::wifi_system::SupplicantManager* supplicant_manager,
NetlinkUtils* netlink_utils,
ScanUtils* scan_utils);
- ~ClientInterfaceImpl();
+ virtual ~ClientInterfaceImpl();
// Get a pointer to the binder representing this ClientInterfaceImpl.
android::sp<android::net::wifi::IClientInterface> GetBinder() const;
@@ -82,7 +83,7 @@
bool requestANQP(
const ::std::vector<uint8_t>& bssid,
const ::android::sp<::android::net::wifi::IANQPDoneCallback>& callback);
- bool IsAssociated() const;
+ virtual bool IsAssociated() const;
void Dump(std::stringstream* ss) const;
private:
@@ -96,6 +97,7 @@
android::wifi_system::SupplicantManager* const supplicant_manager_;
NetlinkUtils* const netlink_utils_;
ScanUtils* const scan_utils_;
+ const std::shared_ptr<OffloadServiceUtils> offload_service_utils_;
const std::unique_ptr<MlmeEventHandlerImpl> mlme_event_handler_;
const android::sp<ClientInterfaceBinder> binder_;
android::sp<ScannerImpl> scanner_;
diff --git a/main.cpp b/main.cpp
index 6e3f1d7..d2a9ba4 100644
--- a/main.cpp
+++ b/main.cpp
@@ -26,6 +26,8 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <cutils/properties.h>
+#include <hwbinder/IPCThreadState.h>
+#include <hwbinder/ProcessState.h>
#include <libminijail.h>
#include <utils/String16.h>
#include <wifi_system/interface_tool.h>
@@ -89,6 +91,16 @@
return binder_fd;
}
+// Setup our interface to the hw Binder driver or die trying.
+int SetupHwBinderOrCrash() {
+ int binder_fd = -1;
+ android::hardware::ProcessState::self()->setThreadPoolConfiguration(1, true);
+ int err = android::hardware::IPCThreadState::self()->setupPolling(&binder_fd);
+ CHECK_EQ(err, 0) << "Error setting up hw binder polling: " << strerror(-err);
+ CHECK_GE(binder_fd, 0) << "Invalid hw binder FD: " << binder_fd;
+ return binder_fd;
+}
+
void RegisterServiceOrCrash(const android::sp<android::IBinder>& service) {
android::sp<android::IServiceManager> sm = android::defaultServiceManager();
CHECK_EQ(sm != NULL, true) << "Could not obtain IServiceManager";
@@ -103,6 +115,10 @@
android::IPCThreadState::self()->handlePolledCommands();
}
+void OnHwBinderReadReady(int fd) {
+ android::hardware::IPCThreadState::self()->handlePolledCommands();
+}
+
int main(int argc, char** argv) {
android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
LOG(INFO) << "wificond is starting up...";
@@ -117,6 +133,11 @@
android::wificond::EventLoop::kModeInput,
&OnBinderReadReady)) << "Failed to watch binder FD";
+ int hw_binder_fd = SetupHwBinderOrCrash();
+ CHECK(event_dispatcher->WatchFileDescriptor(
+ hw_binder_fd, android::wificond::EventLoop::kModeInput,
+ &OnHwBinderReadReady)) << "Failed to watch Hw Binder FD";
+
android::wificond::NetlinkManager netlink_manager(event_dispatcher.get());
CHECK(netlink_manager.Start()) << "Failed to start netlink manager";
android::wificond::NetlinkUtils netlink_utils(&netlink_manager);
diff --git a/net/netlink_utils.cpp b/net/netlink_utils.cpp
index 0fa0116..18246f7 100644
--- a/net/netlink_utils.cpp
+++ b/net/netlink_utils.cpp
@@ -246,6 +246,17 @@
return false;
}
+ // Use default value 0 for scan plan capabilities if attributes are missing.
+ uint32_t max_num_scan_plans = 0;
+ packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
+ &max_num_scan_plans);
+ uint32_t max_scan_plan_interval = 0;
+ packet->GetAttributeValue(NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
+ &max_scan_plan_interval);
+ uint32_t max_scan_plan_iterations = 0;
+ packet->GetAttributeValue(NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
+ &max_scan_plan_iterations);
+
uint8_t max_match_sets;
if (!packet->GetAttributeValue(NL80211_ATTR_MAX_MATCH_SETS,
&max_match_sets)) {
@@ -255,7 +266,10 @@
}
*out_scan_capabilities = ScanCapabilities(max_num_scan_ssids,
max_num_sched_scan_ssids,
- max_match_sets);
+ max_match_sets,
+ max_num_scan_plans,
+ max_scan_plan_interval,
+ max_scan_plan_iterations);
return true;
}
diff --git a/net/netlink_utils.h b/net/netlink_utils.h
index f8b9c0e..f1e43b5 100644
--- a/net/netlink_utils.h
+++ b/net/netlink_utils.h
@@ -65,16 +65,30 @@
ScanCapabilities() = default;
ScanCapabilities(uint8_t max_num_scan_ssids_,
uint8_t max_num_sched_scan_ssids_,
- uint8_t max_match_sets_)
+ uint8_t max_match_sets_,
+ uint32_t max_num_scan_plans_,
+ uint32_t max_scan_plan_interval_,
+ uint32_t max_scan_plan_iterations_)
: max_num_scan_ssids(max_num_scan_ssids_),
max_num_sched_scan_ssids(max_num_sched_scan_ssids_),
- max_match_sets(max_match_sets_) {}
+ max_match_sets(max_match_sets_),
+ max_num_scan_plans(max_num_scan_plans_),
+ max_scan_plan_interval(max_scan_plan_interval_),
+ max_scan_plan_iterations(max_scan_plan_iterations_) {}
// Number of SSIDs you can scan with a single scan request.
uint8_t max_num_scan_ssids;
// Number of SSIDs you can scan with a single scheduled scan request.
uint8_t max_num_sched_scan_ssids;
// Maximum number of sets that can be used with NL80211_ATTR_SCHED_SCAN_MATCH.
uint8_t max_match_sets;
+ // Maximum number of scan plans that can be specified.
+ uint32_t max_num_scan_plans;
+ // Maximum interval in seconds for a particular scan plan that can be
+ // specified.
+ uint32_t max_scan_plan_interval;
+ // Maximum number of iterations for a particular scan plan that can be
+ // specified.
+ uint32_t max_scan_plan_iterations;
};
struct WiphyFeatures {
diff --git a/scanning/offload/hidl_call_util.h b/scanning/offload/hidl_call_util.h
new file mode 100644
index 0000000..6303f1a
--- /dev/null
+++ b/scanning/offload/hidl_call_util.h
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+// This file is modified from
+// hardware/interfaces/wifi/1.0/vts/functional/wifi_hidl_call_util.h
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <functional>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+namespace {
+namespace detail {
+template <typename>
+struct functionArgSaver;
+
+// Provides a std::function that takes one argument, and a buffer
+// wherein the function will store its argument. The buffer has
+// the same type as the argument, but with const and reference
+// modifiers removed.
+template <typename ArgT>
+struct functionArgSaver<std::function<void(ArgT)>> final {
+ using StorageT = typename std::remove_const<
+ typename std::remove_reference<ArgT>::type>::type;
+
+ std::function<void(ArgT)> saveArgs = [this](ArgT arg) {
+ this->saved_values = arg;
+ };
+
+ StorageT saved_values;
+};
+
+// Provides a std::function that takes two arguments, and a buffer
+// wherein the function will store its arguments. The buffer is a
+// std::pair, whose elements have the same types as the arguments
+// (but with const and reference modifiers removed).
+template <typename Arg1T, typename Arg2T>
+struct functionArgSaver<std::function<void(Arg1T, Arg2T)>> final {
+ using StorageT =
+ std::pair<typename std::remove_const<
+ typename std::remove_reference<Arg1T>::type>::type,
+ typename std::remove_const<
+ typename std::remove_reference<Arg2T>::type>::type>;
+
+ std::function<void(Arg1T, Arg2T)> saveArgs = [this](Arg1T arg1, Arg2T arg2) {
+ this->saved_values = {arg1, arg2};
+ };
+
+ StorageT saved_values;
+};
+
+// Provides a std::function that takes three or more arguments, and a
+// buffer wherein the function will store its arguments. The buffer is a
+// std::tuple whose elements have the same types as the arguments (but
+// with const and reference modifiers removed).
+template <typename... ArgT>
+struct functionArgSaver<std::function<void(ArgT...)>> final {
+ using StorageT = std::tuple<typename std::remove_const<
+ typename std::remove_reference<ArgT>::type>::type...>;
+
+ std::function<void(ArgT...)> saveArgs = [this](ArgT... arg) {
+ this->saved_values = {arg...};
+ };
+
+ StorageT saved_values;
+};
+
+// Invokes |method| on |object|, providing |method| a CallbackT as the
+// final argument. Returns a copy of the parameters that |method| provided
+// to CallbackT. (The parameters are returned by value.)
+template <typename CallbackT, typename MethodT, typename ObjectT,
+ typename... ArgT>
+std::pair<typename functionArgSaver<CallbackT>::StorageT, bool> invokeMethod(
+ MethodT method, ObjectT object, ArgT&&... methodArg) {
+ functionArgSaver<CallbackT> result_buffer;
+ const auto& res = ((*object).*method)(std::forward<ArgT>(methodArg)...,
+ result_buffer.saveArgs);
+ bool transportStatus = true;
+ if (!res.isOk()) {
+ LOG(ERROR) << " Transport failed " << res.description();
+ transportStatus = false;
+ }
+ return std::make_pair(result_buffer.saved_values, transportStatus);
+}
+} // namespace detail
+} // namespace
+
+// Invokes |method| on |strong_pointer|, passing provided arguments through to
+// |method|.
+//
+// Returns either:
+// - A copy of the result callback parameter (for callbacks with a single
+// parameter), OR
+// - A pair containing a copy of the result callback parameters (for callbacks
+// with two parameters), OR
+// - A tuple containing a copy of the result callback paramters (for callbacks
+// with three or more parameters).
+//
+// Example usage:
+// EXPECT_EQ(WifiStatusCode::SUCCESS,
+// HIDL_INVOKE(strong_pointer, methodReturningWifiStatus).code);
+// EXPECT_EQ(WifiStatusCode::SUCCESS,
+// HIDL_INVOKE(strong_pointer, methodReturningWifiStatusAndOneMore)
+// .first.code);
+// EXPECT_EQ(WifiStatusCode::SUCCESS, std::get<0>(
+// HIDL_INVOKE(strong_pointer, methodReturningWifiStatusAndTwoMore))
+// .code);
+#define HIDL_INVOKE(strong_pointer, method, ...) \
+ (detail::invokeMethod< \
+ std::remove_reference<decltype(*strong_pointer)>::type::method##_cb>( \
+ &std::remove_reference<decltype(*strong_pointer)>::type::method, \
+ strong_pointer, ##__VA_ARGS__))
diff --git a/scanning/offload/offload_callback.cpp b/scanning/offload/offload_callback.cpp
new file mode 100644
index 0000000..b92a1ed
--- /dev/null
+++ b/scanning/offload/offload_callback.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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 <memory>
+#include <vector>
+
+#include <android-base/logging.h>
+
+#include "wificond/scanning/offload/offload_callback.h"
+#include "wificond/scanning/offload/offload_scan_manager.h"
+#include "wificond/scanning/scan_result.h"
+
+using ::android::hardware::wifi::offload::V1_0::ScanResult;
+using ::android::hardware::wifi::offload::V1_0::OffloadStatus;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+namespace android {
+namespace wificond {
+
+OffloadCallback::OffloadCallback(OffloadCallbackHandlers* handlers)
+ : handlers_(handlers) {}
+
+// Methods from ::android::hardware::wifi::offload::V1_0::IOffloadCallback
+// follow.
+Return<void> OffloadCallback::onScanResult(
+ const hidl_vec<ScanResult>& scan_result) {
+ if (handlers_ != nullptr) {
+ handlers_->OnScanResultHandler(std::vector<ScanResult>(scan_result));
+ } else {
+ LOG(WARNING) << "No handler available for Offload scan results";
+ }
+ return Void();
+}
+
+Return<void> OffloadCallback::onError(const OffloadStatus& status) {
+ if (handlers_ != nullptr) {
+ handlers_->OnErrorHandler(status);
+ } else {
+ LOG(WARNING) << "No error handler for Offload";
+ }
+ return Void();
+}
+
+OffloadCallback::~OffloadCallback() {}
+
+} // namespace wificond
+} // namespace android
diff --git a/scanning/offload/offload_callback.h b/scanning/offload/offload_callback.h
new file mode 100644
index 0000000..ae0b2f4
--- /dev/null
+++ b/scanning/offload/offload_callback.h
@@ -0,0 +1,51 @@
+/*
+ * 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 ANDROID_HARDWARE_WIFI_OFFLOAD_V1_0_OFFLOADCALLBACK_H
+#define ANDROID_HARDWARE_WIFI_OFFLOAD_V1_0_OFFLOADCALLBACK_H
+
+#include <android/hardware/wifi/offload/1.0/IOffloadCallback.h>
+#include <hidl/Status.h>
+#include <vector>
+#include "wificond/scanning/offload/offload_callback_handlers.h"
+
+namespace android {
+namespace wificond {
+
+class OffloadCallback
+ : public ::android::hardware::wifi::offload::V1_0::IOffloadCallback {
+ public:
+ explicit OffloadCallback(OffloadCallbackHandlers* handlers);
+ virtual ~OffloadCallback();
+
+ // Methods from ::android::hardware::wifi::offload::V1_0::IOffloadCallback
+ // follow.
+ ::android::hardware::Return<void> onScanResult(
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::wifi::offload::V1_0::ScanResult>& scanResult)
+ override;
+ ::android::hardware::Return<void> onError(
+ const ::android::hardware::wifi::offload::V1_0::OffloadStatus& status)
+ override;
+ // Methods from ::android::hidl::base::V1_0::IBase follow.
+
+ private:
+ OffloadCallbackHandlers* handlers_;
+};
+
+} // namespace wificond
+} // namespace android
+
+#endif // ANDROID_HARDWARE_WIFI_OFFLOAD_V1_0_OFFLOADCALLBACK_H
diff --git a/scanning/offload/offload_callback_handlers.h b/scanning/offload/offload_callback_handlers.h
new file mode 100644
index 0000000..a202cda
--- /dev/null
+++ b/scanning/offload/offload_callback_handlers.h
@@ -0,0 +1,40 @@
+/*
+ * 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 ANDROID_HARDWARE_WIFI_OFFLOAD_V1_0_OFFLOADCALLBACK_HANDLERS_H
+#define ANDROID_HARDWARE_WIFI_OFFLOAD_V1_0_OFFLOADCALLBACK_HANDLERS_H
+
+#include <android/hardware/wifi/offload/1.0/IOffload.h>
+#include <vector>
+
+namespace android {
+namespace wificond {
+
+class OffloadCallbackHandlers {
+ public:
+ virtual ~OffloadCallbackHandlers() {}
+
+ virtual void OnScanResultHandler(
+ const std::vector<::android::hardware::wifi::offload::V1_0::ScanResult>&
+ scanResult) = 0;
+ virtual void OnErrorHandler(
+ const ::android::hardware::wifi::offload::V1_0::OffloadStatus&
+ status) = 0;
+};
+
+} // namespace wificond
+} // namespace android
+
+#endif // ANDROID_HARDWARE_WIFI_OFFLOAD_V1_0_OFFLOADCALLBACK_HANDLERS_H
diff --git a/scanning/offload/offload_scan_manager.cpp b/scanning/offload/offload_scan_manager.cpp
new file mode 100644
index 0000000..5e3d90d
--- /dev/null
+++ b/scanning/offload/offload_scan_manager.cpp
@@ -0,0 +1,275 @@
+/*
+ * 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/offload_scan_manager.h"
+
+#include <vector>
+
+#include <android-base/logging.h>
+
+#include "wificond/scanning/offload/hidl_call_util.h"
+#include "wificond/scanning/offload/offload_scan_utils.h"
+#include "wificond/scanning/offload/offload_service_utils.h"
+#include "wificond/scanning/offload/scan_stats.h"
+#include "wificond/scanning/scan_result.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::hardware::wifi::offload::V1_0::OffloadStatusCode;
+
+using android::wificond::OffloadCallback;
+using android::wificond::OnNativeScanResultsReadyHandler;
+using ::com::android::server::wifi::wificond::NativeScanResult;
+using ::com::android::server::wifi::wificond::NativeScanStats;
+using std::vector;
+using std::weak_ptr;
+
+using namespace std::placeholders;
+
+namespace {
+const uint32_t kSubscriptionDelayMs = 5000;
+}
+
+namespace android {
+namespace wificond {
+
+OffloadCallbackHandlersImpl::OffloadCallbackHandlersImpl(
+ OffloadScanManager* offload_scan_manager)
+ : offload_scan_manager_(offload_scan_manager) {}
+
+OffloadCallbackHandlersImpl::~OffloadCallbackHandlersImpl() {}
+
+void OffloadCallbackHandlersImpl::OnScanResultHandler(
+ const vector<ScanResult>& scanResult) {
+ if (offload_scan_manager_ != nullptr) {
+ offload_scan_manager_->ReportScanResults(scanResult);
+ }
+}
+
+void OffloadCallbackHandlersImpl::OnErrorHandler(const OffloadStatus& status) {
+ if (offload_scan_manager_ != nullptr) {
+ offload_scan_manager_->ReportError(status);
+ }
+}
+
+OffloadScanManager::OffloadScanManager(weak_ptr<OffloadServiceUtils> utils,
+ OnNativeScanResultsReadyHandler handler)
+ : wifi_offload_hal_(nullptr),
+ wifi_offload_callback_(nullptr),
+ offload_status_(OffloadScanManager::kError),
+ subscription_enabled_(false),
+ offload_callback_handlers_(new OffloadCallbackHandlersImpl(this)),
+ scan_result_handler_(handler) {
+ auto offload_scan_utils = utils.lock();
+ if (scan_result_handler_ == nullptr) {
+ LOG(ERROR) << "Invalid Offload scan result handler";
+ return;
+ }
+ wifi_offload_hal_ = offload_scan_utils->GetOffloadService();
+ if (wifi_offload_hal_ == nullptr) {
+ LOG(ERROR) << "No Offload Service available";
+ return;
+ }
+
+ death_recipient_ = offload_scan_utils->GetOffloadDeathRecipient(
+ std::bind(&OffloadScanManager::OnObjectDeath, this, _1));
+ uint64_t cookie = reinterpret_cast<uint64_t>(wifi_offload_hal_.get());
+ auto link_to_death_status =
+ wifi_offload_hal_->linkToDeath(death_recipient_, cookie);
+ if (!link_to_death_status.isOk()) {
+ LOG(ERROR) << "Unable to register death handler "
+ << link_to_death_status.description();
+ return;
+ }
+
+ wifi_offload_callback_ =
+ offload_scan_utils->GetOffloadCallback(offload_callback_handlers_.get());
+ if (wifi_offload_callback_ == nullptr) {
+ LOG(ERROR) << "Invalid Offload callback object";
+ return;
+ }
+ wifi_offload_hal_->setEventCallback(wifi_offload_callback_);
+ 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 (wifi_offload_hal_ != nullptr) {
+ wifi_offload_hal_->unsubscribeScanResults();
+ subscription_enabled_ = false;
+ }
+ *reason_code = OffloadScanManager::kNone;
+ return true;
+}
+
+bool OffloadScanManager::GetScanStats(NativeScanStats* native_scan_stats) {
+ const auto& result = HIDL_INVOKE(wifi_offload_hal_, getScanStats);
+ const auto& offload_status_and_scan_stats = result.first;
+ bool transport_status = result.second;
+ if (!transport_status) {
+ return false;
+ }
+ OffloadStatus offload_status = offload_status_and_scan_stats.first;
+ ScanStats scan_stats = offload_status_and_scan_stats.second;
+ if (offload_status.code != OffloadStatusCode::OK) {
+ LOG(WARNING) << offload_status.description;
+ return false;
+ }
+ *native_scan_stats = OffloadScanUtils::convertToNativeScanStats(scan_stats);
+ return true;
+}
+
+bool OffloadScanManager::VerifyAndConvertHIDLStatus(
+ std::pair<OffloadStatus, bool> result,
+ OffloadScanManager::ReasonCode* reason_code) {
+ const auto& offload_status = result.first;
+ bool transport_status = result.second;
+ if (!transport_status) {
+ *reason_code = OffloadScanManager::kTransactionFailed;
+ return false;
+ }
+ if (offload_status.code != OffloadStatusCode::OK) {
+ LOG(WARNING) << offload_status.description;
+ *reason_code = OffloadScanManager::kOperationFailed;
+ return false;
+ }
+ 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 (getOffloadStatus() != OffloadScanManager::kNoError) {
+ *reason_code = OffloadScanManager::kNotAvailable;
+ LOG(WARNING) << "Offload HAL scans are not available";
+ return false;
+ }
+ ScanParam param =
+ OffloadScanUtils::createScanParam(scan_ssids, freqs, interval_ms);
+ ScanFilter filter = OffloadScanUtils::createScanFilter(
+ match_ssids, match_security, rssi_threshold);
+
+ if (!ConfigureScans(param, filter, reason_code)) {
+ return false;
+ }
+
+ if (!subscription_enabled_ && !SubscribeScanResults(reason_code)) {
+ return false;
+ }
+
+ subscription_enabled_ = true;
+ *reason_code = OffloadScanManager::kNone;
+ return true;
+}
+
+bool OffloadScanManager::ConfigureScans(
+ ScanParam param, ScanFilter filter,
+ OffloadScanManager::ReasonCode* reason_code) {
+ const auto& result =
+ HIDL_INVOKE(wifi_offload_hal_, configureScans, param, filter);
+ if (!VerifyAndConvertHIDLStatus(result, reason_code)) {
+ return false;
+ }
+ return true;
+}
+
+bool OffloadScanManager::SubscribeScanResults(
+ OffloadScanManager::ReasonCode* reason_code) {
+ const auto& result = HIDL_INVOKE(wifi_offload_hal_, subscribeScanResults,
+ kSubscriptionDelayMs);
+ if (!VerifyAndConvertHIDLStatus(result, reason_code)) {
+ return false;
+ }
+ return true;
+}
+
+OffloadScanManager::StatusCode OffloadScanManager::getOffloadStatus() const {
+ if (wifi_offload_hal_ == nullptr) {
+ return OffloadScanManager::kNoService;
+ }
+ return offload_status_;
+}
+
+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;
+ }
+ return GetScanStats(native_scan_stats);
+}
+
+OffloadScanManager::~OffloadScanManager() {
+ if (wifi_offload_hal_ != nullptr) {
+ wifi_offload_hal_->unlinkToDeath(death_recipient_);
+ }
+}
+
+void OffloadScanManager::ReportScanResults(
+ const vector<ScanResult>& scanResult) {
+ if (scan_result_handler_ != nullptr) {
+ scan_result_handler_(
+ OffloadScanUtils::convertToNativeScanResults(scanResult));
+ } else {
+ LOG(ERROR) << "No scan result handler for Offload ScanManager";
+ }
+}
+
+void OffloadScanManager::ReportError(const OffloadStatus& status) {
+ OffloadStatusCode status_code = status.code;
+ OffloadScanManager::StatusCode status_result = OffloadScanManager::kNoError;
+ switch (status_code) {
+ case OffloadStatusCode::OK:
+ status_result = OffloadScanManager::kNoError;
+ break;
+ case OffloadStatusCode::TIMEOUT:
+ status_result = OffloadScanManager::kTimeOut;
+ break;
+ case OffloadStatusCode::NO_CONNECTION:
+ status_result = OffloadScanManager::kNotConnected;
+ break;
+ case OffloadStatusCode::ERROR:
+ status_result = OffloadScanManager::kError;
+ break;
+ default:
+ LOG(WARNING) << "Invalid Offload Error reported";
+ return;
+ }
+ if (status_result != OffloadScanManager::kNoError) {
+ LOG(WARNING) << "Offload Error reported " << status.description;
+ }
+ offload_status_ = status_result;
+}
+
+void OffloadScanManager::OnObjectDeath(uint64_t cookie) {
+ if (wifi_offload_hal_ == reinterpret_cast<IOffload*>(cookie)) {
+ wifi_offload_hal_.clear();
+ LOG(ERROR) << "Death Notification for Wifi Offload HAL";
+ }
+}
+
+} // namespace wificond
+} // namespace android
diff --git a/scanning/offload/offload_scan_manager.h b/scanning/offload/offload_scan_manager.h
new file mode 100644
index 0000000..e2c2b0c
--- /dev/null
+++ b/scanning/offload/offload_scan_manager.h
@@ -0,0 +1,157 @@
+/*
+ * 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_OFFLOAD_SCAN_MANAGER_H_
+#define WIFICOND_OFFLOAD_SCAN_MANAGER_H_
+
+#include <android/hardware/wifi/offload/1.0/IOffload.h>
+#include "wificond/scanning/offload/offload_callback.h"
+#include "wificond/scanning/offload/offload_callback_handlers.h"
+#include "wificond/scanning/offload/offload_service_utils.h"
+
+#include <vector>
+
+namespace com {
+namespace android {
+namespace server {
+namespace wifi {
+namespace wificond {
+
+class NativeScanResult;
+class NativeScanStats;
+
+} // namespace wificond
+} // namespace wifi
+} // namespace server
+} // namespace android
+} // namespace com
+
+namespace android {
+namespace wificond {
+
+class OffloadScanManager;
+
+typedef std::function<void(
+ const std::vector<::com::android::server::wifi::wificond::NativeScanResult>
+ scanResult)>
+ OnNativeScanResultsReadyHandler;
+
+// Provides callback interface implementation from Offload HAL
+class OffloadCallbackHandlersImpl : public OffloadCallbackHandlers {
+ public:
+ OffloadCallbackHandlersImpl(OffloadScanManager* parent);
+ ~OffloadCallbackHandlersImpl() override;
+
+ void OnScanResultHandler(
+ const std::vector<android::hardware::wifi::offload::V1_0::ScanResult>&
+ scanResult) override;
+ void OnErrorHandler(
+ const android::hardware::wifi::offload::V1_0::OffloadStatus& status)
+ override;
+
+ private:
+ OffloadScanManager* offload_scan_manager_;
+};
+
+// Provides methods to interact with Offload HAL
+class OffloadScanManager {
+ public:
+ enum StatusCode {
+ /* Corresponds to OffloadStatusCode::OK */
+ kNoError,
+ /* Offload HAL service not avaialble */
+ kNoService,
+ /* Corresponds to OffloadStatusCode::NO_CONNECTION */
+ kNotConnected,
+ /* Corresponds to OffloadStatusCode::TIMEOUT */
+ kTimeOut,
+ /* Corresponds to OffloadStatusCode::ERROR */
+ kError
+ };
+
+ enum ReasonCode {
+ /* Default value */
+ kNone,
+ /* Offload HAL scans is not available */
+ kNotAvailable,
+ /* Offload HAL service is not subscribed to */
+ kNotSubscribed,
+ /* Offload HAL requested operation failure */
+ kOperationFailed,
+ /* Binder failed to deliver message to Offload HAL*/
+ kTransactionFailed,
+ };
+
+ explicit OffloadScanManager(std::weak_ptr<OffloadServiceUtils> utils,
+ OnNativeScanResultsReadyHandler handler);
+ virtual ~OffloadScanManager();
+ /* 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;
+
+ private:
+ void ReportScanResults(
+ const std::vector<android::hardware::wifi::offload::V1_0::ScanResult>&
+ scanResult);
+ void ReportError(
+ const android::hardware::wifi::offload::V1_0::OffloadStatus& status);
+ bool VerifyAndConvertHIDLStatus(
+ std::pair<android::hardware::wifi::offload::V1_0::OffloadStatus, bool>
+ result,
+ OffloadScanManager::ReasonCode* reason_code);
+ bool GetScanStats(
+ ::com::android::server::wifi::wificond::NativeScanStats* stats);
+ bool SubscribeScanResults(OffloadScanManager::ReasonCode* reason_code);
+ bool ConfigureScans(android::hardware::wifi::offload::V1_0::ScanParam,
+ android::hardware::wifi::offload::V1_0::ScanFilter,
+ OffloadScanManager::ReasonCode* reason_code);
+ /* Handle binder death */
+ void OnObjectDeath(uint64_t /* cookie */);
+
+ android::sp<android::hardware::wifi::offload::V1_0::IOffload>
+ wifi_offload_hal_;
+ android::sp<OffloadCallback> wifi_offload_callback_;
+ android::sp<OffloadDeathRecipient> death_recipient_;
+ StatusCode offload_status_;
+ bool subscription_enabled_;
+
+ const std::unique_ptr<OffloadCallbackHandlersImpl> offload_callback_handlers_;
+ OnNativeScanResultsReadyHandler scan_result_handler_;
+
+ friend class OffloadCallbackHandlersImpl;
+};
+
+} // namespace wificond
+} // namespace android
+
+#endif // WIFICOND_OFFLOAD_SCAN_MANAGER_H_
diff --git a/scanning/offload/offload_scan_utils.cpp b/scanning/offload/offload_scan_utils.cpp
new file mode 100644
index 0000000..9127632
--- /dev/null
+++ b/scanning/offload/offload_scan_utils.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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/offload_scan_utils.h"
+
+#include <android-base/logging.h>
+
+#include "wificond/scanning/offload/scan_stats.h"
+#include "wificond/scanning/scan_result.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 {
+
+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);
+ }
+ 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;
+}
+
+} // namespace wificond
+} // namespace android
diff --git a/scanning/offload/offload_scan_utils.h b/scanning/offload/offload_scan_utils.h
new file mode 100644
index 0000000..ce4afa7
--- /dev/null
+++ b/scanning/offload/offload_scan_utils.h
@@ -0,0 +1,68 @@
+/*
+ * 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_OFFLOAD_SCAN_UTILS_H_
+#define WIFICOND_OFFLOAD_SCAN_UTILS_H_
+
+#include <android/hardware/wifi/offload/1.0/IOffload.h>
+#include "wificond/scanning/offload/offload_callback.h"
+
+#include <vector>
+
+namespace com {
+namespace android {
+namespace server {
+namespace wifi {
+namespace wificond {
+
+class NativeScanResult;
+class NativeScanStats;
+
+} // namespace wificond
+} // namespace wifi
+} // namespace server
+} // namespace android
+} // namespace com
+
+namespace android {
+namespace wificond {
+
+// Provides utility methods for Offload Scan Manager
+class OffloadScanUtils {
+ public:
+ static std::vector<::com::android::server::wifi::wificond::NativeScanResult>
+ convertToNativeScanResults(
+ const std::vector<android::hardware::wifi::offload::V1_0::ScanResult>&);
+ static android::hardware::wifi::offload::V1_0::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 android::hardware::wifi::offload::V1_0::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 android::hardware::wifi::offload::V1_0::ScanStats& /* scanStats */);
+};
+
+} // namespace wificond
+} // namespace android
+
+#endif // WIFICOND_OFFLOAD_SCAN_UTILS_H_
diff --git a/scanning/offload/offload_service_utils.cpp b/scanning/offload/offload_service_utils.cpp
new file mode 100644
index 0000000..2a14a32
--- /dev/null
+++ b/scanning/offload/offload_service_utils.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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/offload_service_utils.h"
+#include "wificond/scanning/offload/offload_scan_manager.h"
+
+using ::android::hardware::wifi::offload::V1_0::IOffload;
+
+namespace android {
+namespace wificond {
+
+android::sp<IOffload> OffloadServiceUtils::GetOffloadService() {
+ return IOffload::getService();
+}
+
+android::sp<OffloadCallback> OffloadServiceUtils::GetOffloadCallback(
+ OffloadCallbackHandlers* handlers) {
+ return new OffloadCallback(handlers);
+}
+
+OffloadDeathRecipient* OffloadServiceUtils::GetOffloadDeathRecipient(
+ OffloadDeathRecipientHandler handler) {
+ return new OffloadDeathRecipient(handler);
+}
+
+bool OffloadServiceUtils::IsOffloadScanSupported() const {
+ bool result = false;
+#ifdef WIFI_OFFLOAD_SCANS
+ LOG(VERBOSE) << "Offload HAL supported";
+ result = true;
+#endif
+ return result;
+}
+
+OffloadDeathRecipient::OffloadDeathRecipient(
+ OffloadDeathRecipientHandler handler)
+ : handler_(handler) {}
+
+} // namespace wificond
+} // namespace android
diff --git a/scanning/offload/offload_service_utils.h b/scanning/offload/offload_service_utils.h
new file mode 100644
index 0000000..cff5575
--- /dev/null
+++ b/scanning/offload/offload_service_utils.h
@@ -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_OFFLOAD_SERVICE_UTILS_H_
+#define WIFICOND_OFFLOAD_SERVICE_UTILS_H_
+
+#include <android/hardware/wifi/offload/1.0/IOffload.h>
+#include "wificond/scanning/offload/offload_callback.h"
+#include "wificond/scanning/offload/offload_callback_handlers.h"
+
+namespace android {
+namespace wificond {
+
+typedef std::function<void(uint64_t)> OffloadDeathRecipientHandler;
+
+class OffloadDeathRecipient : public android::hardware::hidl_death_recipient {
+ public:
+ OffloadDeathRecipient(OffloadDeathRecipientHandler handler);
+
+ void serviceDied(
+ uint64_t cookie,
+ const android::wp<android::hidl::base::V1_0::IBase>& who) override {
+ this->handler_(cookie);
+ }
+
+ private:
+ OffloadDeathRecipientHandler handler_;
+};
+
+// Provides methods to get Offload HAL service and create callback
+class OffloadServiceUtils {
+ public:
+ OffloadServiceUtils() = default;
+ virtual ~OffloadServiceUtils() = default;
+ virtual android::sp<android::hardware::wifi::offload::V1_0::IOffload>
+ GetOffloadService();
+ // Check if Offload scan is supported on this device.
+ virtual bool IsOffloadScanSupported() const;
+ virtual android::sp<OffloadCallback> GetOffloadCallback(
+ OffloadCallbackHandlers* handlers);
+ virtual OffloadDeathRecipient* GetOffloadDeathRecipient(
+ OffloadDeathRecipientHandler handler);
+};
+
+} // namespace wificond
+} // namespace android
+
+#endif // WIFICOND_OFFLOAD_SERVICE_UTILS_H
diff --git a/scanning/offload/scan_stats.cpp b/scanning/offload/scan_stats.cpp
new file mode 100644
index 0000000..4a963cb
--- /dev/null
+++ b/scanning/offload/scan_stats.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 {
+ 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_)) {
+ return 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]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+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
index 0000000..eb1d16a
--- /dev/null
+++ b/scanning/offload/scan_stats.h
@@ -0,0 +1,58 @@
+/*
+ * 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
diff --git a/scanning/pno_settings.cpp b/scanning/pno_settings.cpp
index c8b5ff6..be051dd 100644
--- a/scanning/pno_settings.cpp
+++ b/scanning/pno_settings.cpp
@@ -28,6 +28,9 @@
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_));
diff --git a/scanning/pno_settings.h b/scanning/pno_settings.h
index e236ec8..a606b0f 100644
--- a/scanning/pno_settings.h
+++ b/scanning/pno_settings.h
@@ -32,6 +32,9 @@
class PnoSettings : public ::android::Parcelable {
public:
+ static const uint32_t kFastScanIterations;
+ static const uint32_t kSlowScanIntervalMultiplier;
+
PnoSettings()
: interval_ms_(0),
min_2g_rssi_(0),
diff --git a/scanning/scan_utils.cpp b/scanning/scan_utils.cpp
index 5199e2b..dfd051c 100644
--- a/scanning/scan_utils.cpp
+++ b/scanning/scan_utils.cpp
@@ -36,6 +36,7 @@
namespace {
constexpr uint8_t kElemIdSsid = 0;
+constexpr unsigned int kMsecPerSec = 1000;
} // namespace
@@ -151,17 +152,11 @@
// These scan results are considered as malformed.
return false;
}
- uint64_t tsf;
- if (!bss.GetAttributeValue(NL80211_BSS_TSF, &tsf)) {
- LOG(ERROR) << "Failed to get TSF from scan result packet";
+ uint64_t last_seen_since_boot_microseconds;
+ if (!GetBssTimestamp(bss, &last_seen_since_boot_microseconds)) {
+ // Logging is done inside |GetBssTimestamp|.
return false;
}
- uint64_t beacon_tsf;
- if (bss.GetAttributeValue(NL80211_BSS_BEACON_TSF, &beacon_tsf)) {
- if (beacon_tsf > tsf) {
- tsf = beacon_tsf;
- }
- }
int32_t signal;
if (!bss.GetAttributeValue(NL80211_BSS_SIGNAL_MBM, &signal)) {
LOG(ERROR) << "Failed to get Signal Strength from scan result packet";
@@ -181,7 +176,37 @@
}
*scan_result =
- NativeScanResult(ssid, bssid, ie, freq, signal, tsf, capability, associated);
+ NativeScanResult(ssid, bssid, ie, freq, signal,
+ last_seen_since_boot_microseconds,
+ capability, associated);
+ }
+ return true;
+}
+
+bool ScanUtils::GetBssTimestampForTesting(
+ const NL80211NestedAttr& bss,
+ uint64_t* last_seen_since_boot_microseconds){
+ return GetBssTimestamp(bss, last_seen_since_boot_microseconds);
+}
+
+bool ScanUtils::GetBssTimestamp(const NL80211NestedAttr& bss,
+ uint64_t* last_seen_since_boot_microseconds){
+ uint64_t last_seen_since_boot_nanoseconds;
+ if (bss.GetAttributeValue(NL80211_BSS_LAST_SEEN_BOOTTIME,
+ &last_seen_since_boot_nanoseconds)) {
+ *last_seen_since_boot_microseconds = last_seen_since_boot_nanoseconds / 1000;
+ } else {
+ // Fall back to use TSF if we can't find NL80211_BSS_LAST_SEEN_BOOTTIME
+ // attribute.
+ if (!bss.GetAttributeValue(NL80211_BSS_TSF, last_seen_since_boot_microseconds)) {
+ LOG(ERROR) << "Failed to get TSF from scan result packet";
+ return false;
+ }
+ uint64_t beacon_tsf_microseconds;
+ if (bss.GetAttributeValue(NL80211_BSS_BEACON_TSF, &beacon_tsf_microseconds)) {
+ *last_seen_since_boot_microseconds = std::max(*last_seen_since_boot_microseconds,
+ beacon_tsf_microseconds);
+ }
}
return true;
}
@@ -220,7 +245,8 @@
bool ScanUtils::Scan(uint32_t interface_index,
bool request_random_mac,
const vector<vector<uint8_t>>& ssids,
- const vector<uint32_t>& freqs) {
+ const vector<uint32_t>& freqs,
+ int* error_code) {
NL80211Packet trigger_scan(
netlink_manager_->GetFamilyId(),
NL80211_CMD_TRIGGER_SCAN,
@@ -261,8 +287,13 @@
// scan results here, so it is OK to expect a timely response because
// kernel is supposed to send the ERROR/ACK back before the scan starts.
vector<unique_ptr<const NL80211Packet>> response;
- if (!netlink_manager_->SendMessageAndGetAck(trigger_scan)) {
- LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN failed";
+ if (!netlink_manager_->SendMessageAndGetAckOrError(trigger_scan,
+ error_code)) {
+ // Logging is done inside |SendMessageAndGetAckOrError|.
+ return false;
+ }
+ if (*error_code != 0) {
+ LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN failed: " << strerror(*error_code);
return false;
}
return true;
@@ -318,12 +349,13 @@
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,
const std::vector<std::vector<uint8_t>>& match_ssids,
- const std::vector<uint32_t>& freqs) {
+ const std::vector<uint32_t>& freqs,
+ int* error_code) {
NL80211Packet start_sched_scan(
netlink_manager_->GetFamilyId(),
NL80211_CMD_START_SCHED_SCAN,
@@ -354,6 +386,7 @@
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(
@@ -364,9 +397,31 @@
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,
@@ -374,8 +429,13 @@
}
vector<unique_ptr<const NL80211Packet>> response;
- if (!netlink_manager_->SendMessageAndGetAck(start_sched_scan)) {
- LOG(ERROR) << "NL80211_CMD_START_SCHED_SCAN failed";
+ if (!netlink_manager_->SendMessageAndGetAckOrError(start_sched_scan,
+ error_code)) {
+ // Logging is done inside |SendMessageAndGetAckOrError|.
+ return false;
+ }
+ if (*error_code != 0) {
+ LOG(ERROR) << "NL80211_CMD_START_SCHED_SCAN failed: " << strerror(*error_code);
return false;
}
diff --git a/scanning/scan_utils.h b/scanning/scan_utils.h
index 84baeec..87df13a 100644
--- a/scanning/scan_utils.h
+++ b/scanning/scan_utils.h
@@ -41,8 +41,20 @@
namespace android {
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:
@@ -69,11 +81,13 @@
// If |ssids| contains an empty string, it will a scan for all ssids.
// |freqs| is a vector of frequencies we request to scan.
// If |freqs| is an empty vector, it will scan all supported frequencies.
+ // |error_code| contains the errno kernel replied when this returns false.
// Returns true on success.
virtual bool Scan(uint32_t interface_index,
bool request_random_mac,
const std::vector<std::vector<uint8_t>>& ssids,
- const std::vector<uint32_t>& freqs);
+ const std::vector<uint32_t>& freqs,
+ int* error_code);
// Send scan request to kernel for interface with index |interface_index|.
// |inteval_ms| is the expected scan interval in milliseconds.
@@ -91,15 +105,17 @@
// If |freqs| is an empty vector, it will scan all supported frequencies.
// Only BSSs match the |match_ssids| and |rssi_threshold| will be returned as
// scan results.
+ // |error_code| contains the errno kernel replied when this returns false.
// 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,
const std::vector<std::vector<uint8_t>>& match_ssids,
- const std::vector<uint32_t>& freqs);
+ const std::vector<uint32_t>& freqs,
+ int* error_code);
// Stop existing scheduled scan on interface with index |interface_index|.
// Returns true on success.
@@ -110,6 +126,14 @@
// Returns true on success.
virtual bool AbortScan(uint32_t interface_index);
+ // Visible for testing.
+ // Get a timestamp for the scan result |bss| represents.
+ // This timestamp records the time passed since boot when last time the
+ // AP was seen.
+ virtual bool GetBssTimestampForTesting(
+ const NL80211NestedAttr& bss,
+ uint64_t* last_seen_since_boot_microseconds);
+
// 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
@@ -137,6 +161,8 @@
virtual void UnsubscribeSchedScanResultNotification(uint32_t interface_index);
private:
+ bool GetBssTimestamp(const NL80211NestedAttr& bss,
+ uint64_t* last_seen_since_boot_microseconds);
bool GetSSIDFromInfoElement(const std::vector<uint8_t>& ie,
std::vector<uint8_t>* ssid);
// Converts a NL80211_CMD_NEW_SCAN_RESULTS packet to a ScanResult object.
diff --git a/scanning/scanner_impl.cpp b/scanning/scanner_impl.cpp
index 2c1b1d0..9bf13b3 100644
--- a/scanning/scanner_impl.cpp
+++ b/scanning/scanner_impl.cpp
@@ -23,17 +23,22 @@
#include "wificond/client_interface_impl.h"
#include "wificond/scanning/scan_utils.h"
+#include "wificond/scanning/offload/offload_service_utils.h"
+#include "wificond/scanning/offload/offload_scan_manager.h"
using android::binder::Status;
using android::net::wifi::IPnoScanEvent;
using android::net::wifi::IScanEvent;
+using android::hardware::wifi::offload::V1_0::IOffload;
using android::sp;
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;
using namespace std::placeholders;
@@ -46,10 +51,12 @@
const WiphyFeatures& wiphy_features,
ClientInterfaceImpl* client_interface,
NetlinkUtils* netlink_utils,
- ScanUtils* scan_utils)
+ ScanUtils* scan_utils,
+ weak_ptr<OffloadServiceUtils> offload_service_utils)
: 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),
@@ -72,6 +79,12 @@
std::bind(&ScannerImpl::OnSchedScanResultsReady,
this,
_1, _2));
+ offload_scan_manager_.reset(
+ new OffloadScanManager(
+ offload_service_utils,
+ std::bind(&ScannerImpl::OnOffloadScanResult,
+ this, _1)));
+ offload_scan_supported_ = offload_service_utils.lock()->IsOffloadScanSupported();
}
ScannerImpl::~ScannerImpl() {
@@ -195,7 +208,10 @@
freqs.push_back(channel.frequency_);
}
- if (!scan_utils_->Scan(interface_index_, request_random_mac, ssids, freqs)) {
+ int error_code = 0;
+ if (!scan_utils_->Scan(interface_index_, request_random_mac, ssids, freqs,
+ &error_code)) {
+ CHECK(error_code != ENODEV) << "Driver is in a bad state, restarting wificond";
*out_success = false;
return Status::ok();
}
@@ -206,9 +222,72 @@
Status ScannerImpl::startPnoScan(const PnoSettings& pno_settings,
bool* out_success) {
+ if (!offload_scan_supported_ || !StartPnoScanOffload(pno_settings)) {
+ *out_success = StartPnoScanDefault(pno_settings);
+ } else {
+ // scanning over offload succeeded
+ *out_success = true;
+ }
+ 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_) {
+ // 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_);
+ }
+
+ 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_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()) {
- *out_success = false;
- return Status::ok();
+ return false;
}
if (pno_scan_started_) {
LOG(WARNING) << "Pno scan already started";
@@ -216,70 +295,63 @@
// 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;
- 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) {
- skipped_scan_ssids.emplace_back(network.ssid_);
- continue;
- }
- scan_ssids.push_back(network.ssid_);
- }
-
- if (match_ssids.size() + 1 > scan_capabilities_.max_match_sets) {
- skipped_match_ssids.emplace_back(network.ssid_);
- continue;
- }
- match_ssids.push_back(network.ssid_);
- }
-
- LogSsidList(skipped_scan_ssids, "Skip scan ssid for pno scan");
- LogSsidList(skipped_match_ssids, "Skip match ssid for pno scan");
-
+ 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();
+ 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,
scan_ssids,
match_ssids,
- freqs)) {
- *out_success = false;
+ freqs,
+ &error_code)) {
LOG(ERROR) << "Failed to start pno scan";
- return Status::ok();
+ CHECK(error_code != ENODEV) << "Driver is in a bad state, restarting wificond";
+ 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 Status::ok();
+ return true;
}
Status ScannerImpl::abortScan() {
@@ -376,6 +448,34 @@
}
}
+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()) {
@@ -391,5 +491,15 @@
LOG(WARNING) << prefix << ": " << ssid_list_string;
}
+void ScannerImpl::OnOffloadScanResult(
+ std::vector<NativeScanResult> scanResult) {
+ 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";
+ }
+}
+
} // namespace wificond
} // namespace android
diff --git a/scanning/scanner_impl.h b/scanning/scanner_impl.h
index 61a7b96..2bb9262 100644
--- a/scanning/scanner_impl.h
+++ b/scanning/scanner_impl.h
@@ -24,12 +24,14 @@
#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 ScanUtils;
+class OffloadServiceUtils;
class ScannerImpl : public android::net::wifi::BnWifiScannerImpl {
public:
@@ -39,7 +41,8 @@
const WiphyFeatures& wiphy_features,
ClientInterfaceImpl* client_interface,
NetlinkUtils* netlink_utils,
- ScanUtils* scan_utils);
+ ScanUtils* scan_utils,
+ std::weak_ptr<OffloadServiceUtils> offload_service_utils);
~ScannerImpl();
// Returns a vector of available frequencies for 2.4GHz channels.
::android::binder::Status getAvailable2gChannels(
@@ -74,6 +77,8 @@
private:
bool CheckIsValid();
+ void OnOffloadScanResult(
+ std::vector<::com::android::server::wifi::wificond::NativeScanResult>);
void OnScanResultsReady(
uint32_t interface_index,
bool aborted,
@@ -82,11 +87,26 @@
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);
+ SchedScanIntervalSetting GenerateIntervalSetting(
+ const ::com::android::server::wifi::wificond::PnoSettings& pno_settings) const;
// 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_;
@@ -100,6 +120,7 @@
ScanUtils* const scan_utils_;
::android::sp<::android::net::wifi::IPnoScanEvent> pno_scan_event_handler_;
::android::sp<::android::net::wifi::IScanEvent> scan_event_handler_;
+ std::unique_ptr<OffloadScanManager> offload_scan_manager_;
DISALLOW_COPY_AND_ASSIGN(ScannerImpl);
};
diff --git a/server.cpp b/server.cpp
index 595fd8a..be57e89 100644
--- a/server.cpp
+++ b/server.cpp
@@ -20,6 +20,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include <binder/IPCThreadState.h>
#include <binder/PermissionCache.h>
@@ -268,7 +269,10 @@
// Some kernel/driver uses station type for p2p interface.
// In that case we can only rely on hard-coded name to exclude
// p2p interface from station interfaces.
- if (iface.name != "p2p0") {
+ // Currently NAN interfaces also use station type.
+ // We should blacklist NAN interfaces as well.
+ if (iface.name != "p2p0" &&
+ !android::base::StartsWith(iface.name, "aware_data")) {
*interface = iface;
return true;
}
diff --git a/tests/mock_client_interface_impl.cpp b/tests/mock_client_interface_impl.cpp
new file mode 100644
index 0000000..775eb1c
--- /dev/null
+++ b/tests/mock_client_interface_impl.cpp
@@ -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 "wificond/tests/mock_client_interface_impl.h"
+
+#include <vector>
+
+#include <wifi_system/interface_tool.h>
+#include <wifi_system/supplicant_manager.h>
+
+#include "wificond/net/netlink_utils.h"
+#include "wificond/scanning/scan_utils.h"
+
+namespace android {
+namespace wificond {
+
+const char kTestInterfaceName[] = "testwifi0";
+const uint8_t kTestInterfaceMacAddress[] = {0x10, 0x20, 0xfe, 0xae, 0x2d, 0xc2};
+const uint32_t kTestInterfaceIndex = 42;
+const uint32_t kTestWiphyIndex = 2;
+
+MockClientInterfaceImpl::MockClientInterfaceImpl(
+ android::wifi_system::InterfaceTool* interface_tool,
+ android::wifi_system::SupplicantManager* supplicant_manager,
+ NetlinkUtils* netlink_utils,
+ ScanUtils* scan_utils)
+ : ClientInterfaceImpl(
+ kTestWiphyIndex,
+ kTestInterfaceName,
+ kTestInterfaceIndex,
+ std::vector<uint8_t>(
+ kTestInterfaceMacAddress,
+ kTestInterfaceMacAddress + arraysize(kTestInterfaceMacAddress)),
+ interface_tool,
+ supplicant_manager,
+ netlink_utils,
+ scan_utils) {}
+
+} // namespace wificond
+} // namespace android
diff --git a/tests/mock_client_interface_impl.h b/tests/mock_client_interface_impl.h
new file mode 100644
index 0000000..05cf686
--- /dev/null
+++ b/tests/mock_client_interface_impl.h
@@ -0,0 +1,44 @@
+/*
+ * 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_TEST_MOCK_CLIENT_INTERFACE_IMPL_H_
+#define WIFICOND_TEST_MOCK_CLIENT_INTERFACE_IMPL_H_
+
+#include <gmock/gmock.h>
+
+#include "wificond/client_interface_impl.h"
+
+namespace android {
+
+namespace wificond {
+
+class MockClientInterfaceImpl : public ClientInterfaceImpl {
+ public:
+ MockClientInterfaceImpl(
+ android::wifi_system::InterfaceTool*,
+ android::wifi_system::SupplicantManager*,
+ NetlinkUtils*,
+ ScanUtils*);
+ ~MockClientInterfaceImpl() override = default;
+
+ MOCK_CONST_METHOD0(IsAssociated, bool());
+
+}; // class MockClientInterfaceImpl
+
+} // namespace wificond
+} // namespace android
+
+#endif // WIFICOND_TEST_MOCK_CLIENT_INTERFACE_IMPL_H_
diff --git a/tests/mock_offload.cpp b/tests/mock_offload.cpp
new file mode 100644
index 0000000..02ad00d
--- /dev/null
+++ b/tests/mock_offload.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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/tests/mock_offload.h"
+
+namespace android {
+namespace wificond {
+
+MockOffload::MockOffload() {}
+
+} // namespace wificond
+} // namespace android
diff --git a/tests/mock_offload.h b/tests/mock_offload.h
new file mode 100644
index 0000000..399639c
--- /dev/null
+++ b/tests/mock_offload.h
@@ -0,0 +1,62 @@
+/*
+ * 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_TEST_MOCK_OFFLOAD_H
+#define WIFICOND_TEST_MOCK_OFFLOAD_H
+
+#include <gmock/gmock.h>
+
+#include <android/hardware/wifi/offload/1.0/IOffload.h>
+
+namespace android {
+namespace wificond {
+
+typedef std::function<void(
+ const android::hardware::wifi::offload::V1_0::OffloadStatus& status,
+ const android::hardware::wifi::offload::V1_0::ScanStats& scanStats)>
+ OnScanStatsCallback;
+typedef std::function<void(
+ const android::hardware::wifi::offload::V1_0::OffloadStatus& status)>
+ StatusCallback;
+
+class MockOffload : public android::hardware::wifi::offload::V1_0::IOffload {
+ public:
+ MockOffload();
+ ~MockOffload() override = default;
+
+ MOCK_METHOD3(
+ configureScans,
+ android::hardware::Return<void>(
+ const android::hardware::wifi::offload::V1_0::ScanParam& param,
+ const android::hardware::wifi::offload::V1_0::ScanFilter& filter,
+ StatusCallback _hidl_cb));
+ MOCK_METHOD1(getScanStats,
+ android::hardware::Return<void>(OnScanStatsCallback cb));
+ MOCK_METHOD2(subscribeScanResults,
+ android::hardware::Return<void>(uint32_t delayMs,
+ StatusCallback _hidl_cb));
+ MOCK_METHOD0(unsubscribeScanResults, android::hardware::Return<void>());
+ MOCK_METHOD1(
+ setEventCallback,
+ android::hardware::Return<void>(
+ const android::sp<
+ android::hardware::wifi::offload::V1_0::IOffloadCallback>& cb));
+};
+
+} // namespace wificond
+} // namespace android
+
+#endif // WIFICOND_TEST_MOCK_OFFLOAD_H
diff --git a/tests/mock_offload_callback_handlers.cpp b/tests/mock_offload_callback_handlers.cpp
new file mode 100644
index 0000000..e4e5d48
--- /dev/null
+++ b/tests/mock_offload_callback_handlers.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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 "wificond/tests/mock_offload_callback_handlers.h"
+
+namespace android {
+namespace wificond {
+
+MockOffloadCallbackHandlers::MockOffloadCallbackHandlers() {}
+
+} // namespace wificond
+} // namespace android
diff --git a/tests/mock_offload_callback_handlers.h b/tests/mock_offload_callback_handlers.h
new file mode 100644
index 0000000..e9b6285
--- /dev/null
+++ b/tests/mock_offload_callback_handlers.h
@@ -0,0 +1,46 @@
+/*
+ * 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_TESTS_MOCK_OFFLOAD_CALLBACK_HANDLERS_H_
+#define WIFICOND_TESTS_MOCK_OFFLOAD_CALLBACK_HANDLERS_H_
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <android/hardware/wifi/offload/1.0/IOffload.h>
+#include "wificond/scanning/offload/offload_callback_handlers.h"
+
+namespace android {
+namespace wificond {
+
+class MockOffloadCallbackHandlers : public OffloadCallbackHandlers {
+ public:
+ MockOffloadCallbackHandlers();
+ ~MockOffloadCallbackHandlers() override = default;
+
+ MOCK_METHOD1(
+ OnScanResultHandler,
+ void(const std::vector<
+ android::hardware::wifi::offload::V1_0::ScanResult>& scanResult));
+ MOCK_METHOD1(OnErrorHandler,
+ void(const android::hardware::wifi::offload::V1_0::OffloadStatus&
+ status));
+};
+
+} // namespace wificond
+} // namespace android
+
+#endif // WIFICOND_TESTS_MOCK_OFFLOAD_CALLBACK_HANDLERS_H_
diff --git a/tests/mock_offload_service_utils.cpp b/tests/mock_offload_service_utils.cpp
new file mode 100644
index 0000000..c58be31
--- /dev/null
+++ b/tests/mock_offload_service_utils.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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/tests/mock_offload_service_utils.h"
+
+namespace android {
+namespace wificond {
+
+MockOffloadServiceUtils::MockOffloadServiceUtils() {}
+
+} // namespace wificond
+} // namespace android
diff --git a/tests/mock_offload_service_utils.h b/tests/mock_offload_service_utils.h
new file mode 100644
index 0000000..fd9fd34
--- /dev/null
+++ b/tests/mock_offload_service_utils.h
@@ -0,0 +1,48 @@
+/*
+ * 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_TEST_MOCK_OFFLOAD_SERVICE_UTILS_H_
+#define WIFICOND_TEST_MOCK_OFFLOAD_SERVICE_UTILS_H_
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <android/hardware/wifi/offload/1.0/IOffload.h>
+#include "wificond/scanning/offload/offload_callback.h"
+#include "wificond/scanning/offload/offload_callback_handlers.h"
+#include "wificond/scanning/offload/offload_service_utils.h"
+
+namespace android {
+namespace wificond {
+
+class MockOffloadServiceUtils : public OffloadServiceUtils {
+ public:
+ MockOffloadServiceUtils();
+ ~MockOffloadServiceUtils() override = default;
+ MOCK_CONST_METHOD0(IsOffloadScanSupported, bool());
+ MOCK_METHOD0(GetOffloadService,
+ sp<android::hardware::wifi::offload::V1_0::IOffload>());
+ MOCK_METHOD1(GetOffloadCallback,
+ sp<OffloadCallback>(OffloadCallbackHandlers* handlers));
+ MOCK_METHOD1(GetOffloadDeathRecipient,
+ android::wificond::OffloadDeathRecipient*(
+ OffloadDeathRecipientHandler handler));
+};
+
+} // namespace wificond
+} // namespace android
+
+#endif // WIFICOND_TEST_MOCK_OFFLOAD_SERVICE_UTILS_H_
diff --git a/tests/mock_scan_utils.h b/tests/mock_scan_utils.h
index 4f9e461..3e5cc7f 100644
--- a/tests/mock_scan_utils.h
+++ b/tests/mock_scan_utils.h
@@ -29,22 +29,34 @@
MockScanUtils(NetlinkManager* netlink_manager);
~MockScanUtils() override = default;
- MOCK_METHOD2(GetScanResult, bool(
- uint32_t interface_index,
- std::vector<::com::android::server::wifi::wificond::NativeScanResult>* out_scan_results));
-
- MOCK_METHOD4(Scan, bool(
- uint32_t interface_index,
- bool random_mac,
- const std::vector<std::vector<uint8_t>>& ssids,
- const std::vector<uint32_t>& freqs));
+ MOCK_METHOD1(UnsubscribeScanResultNotification,
+ void(uint32_t interface_index));
+ MOCK_METHOD1(AbortScan, bool(uint32_t interface_index));
+ MOCK_METHOD1(StopScheduledScan, bool(uint32_t interface_index));
MOCK_METHOD2(SubscribeScanResultNotification,void(
uint32_t interface_index,
OnScanResultsReadyHandler handler));
+ MOCK_METHOD2(GetScanResult, bool(
+ uint32_t interface_index,
+ std::vector<::com::android::server::wifi::wificond::NativeScanResult>* out_scan_results));
- MOCK_METHOD1(UnsubscribeScanResultNotification,
- void(uint32_t interface_index));
+ MOCK_METHOD5(Scan, bool(
+ uint32_t interface_index,
+ bool random_mac,
+ const std::vector<std::vector<uint8_t>>& ssids,
+ const std::vector<uint32_t>& freqs,
+ int* error_code));
+
+ MOCK_METHOD8(StartScheduledScan, bool(
+ 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));
}; // class MockScanUtils
diff --git a/tests/netlink_utils_unittest.cpp b/tests/netlink_utils_unittest.cpp
index b1a7939..646d4a9 100644
--- a/tests/netlink_utils_unittest.cpp
+++ b/tests/netlink_utils_unittest.cpp
@@ -42,6 +42,9 @@
constexpr uint8_t kFakeMaxNumScanSSIDs = 10;
constexpr uint8_t kFakeMaxNumSchedScanSSIDs = 16;
constexpr uint8_t kFakeMaxMatchSets = 18;
+constexpr uint8_t kFakeMaxNumScanPlans = 8;
+constexpr uint8_t kFakeMaxScanPlanIntervals = 80;
+constexpr uint8_t kFakeMaxScanPlanIterations = 10;
constexpr uint16_t kFakeFamilyId = 14;
constexpr uint32_t kFakeFrequency1 = 2412;
constexpr uint32_t kFakeFrequency2 = 2437;
@@ -80,6 +83,116 @@
return CreateControlMessageError(0);
}
+void AppendScanCapabilitiesAttributes(NL80211Packet* packet,
+ bool supports_scan_plan) {
+ packet->AddAttribute(NL80211Attr<uint8_t>(NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+ kFakeMaxNumScanSSIDs));
+ packet->AddAttribute(NL80211Attr<uint8_t>(
+ NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+ kFakeMaxNumSchedScanSSIDs));
+ packet->AddAttribute(NL80211Attr<uint8_t>(NL80211_ATTR_MAX_MATCH_SETS,
+ kFakeMaxMatchSets));
+ if (supports_scan_plan) {
+ packet->AddAttribute(NL80211Attr<uint32_t>(
+ NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
+ kFakeMaxNumScanPlans));
+ packet->AddAttribute(NL80211Attr<uint32_t>(
+ NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
+ kFakeMaxScanPlanIntervals));
+ packet->AddAttribute(NL80211Attr<uint32_t>(
+ NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
+ kFakeMaxScanPlanIterations));
+ }
+}
+
+void AppendBandInfoAttributes(NL80211Packet* packet) {
+ NL80211NestedAttr freq_2g_1(1);
+ NL80211NestedAttr freq_2g_2(2);
+ NL80211NestedAttr freq_2g_3(3);
+ NL80211NestedAttr freq_5g_1(4);
+ NL80211NestedAttr freq_5g_2(5);
+ NL80211NestedAttr freq_dfs_1(6);
+ freq_2g_1.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
+ kFakeFrequency1));
+ freq_2g_2.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
+ kFakeFrequency2));
+ freq_2g_3.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
+ kFakeFrequency3));
+ freq_5g_1.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
+ kFakeFrequency4));
+ freq_5g_2.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
+ kFakeFrequency5));
+ // DFS frequency.
+ freq_dfs_1.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
+ kFakeFrequency6));
+ freq_dfs_1.AddAttribute(NL80211Attr<uint32_t>(
+ NL80211_FREQUENCY_ATTR_DFS_STATE,
+ NL80211_DFS_USABLE));
+
+ NL80211NestedAttr band_2g_freqs(NL80211_BAND_ATTR_FREQS);
+ NL80211NestedAttr band_5g_freqs(NL80211_BAND_ATTR_FREQS);
+ band_2g_freqs.AddAttribute(freq_2g_1);
+ band_2g_freqs.AddAttribute(freq_2g_2);
+ band_2g_freqs.AddAttribute(freq_2g_3);
+ band_5g_freqs.AddAttribute(freq_5g_1);
+ band_5g_freqs.AddAttribute(freq_5g_2);
+ band_5g_freqs.AddAttribute(freq_dfs_1);
+
+ NL80211NestedAttr band_2g_attr(1);
+ NL80211NestedAttr band_5g_attr(2);
+ band_2g_attr.AddAttribute(band_2g_freqs);
+ band_5g_attr.AddAttribute(band_5g_freqs);
+
+ NL80211NestedAttr band_attr(NL80211_ATTR_WIPHY_BANDS);
+ band_attr.AddAttribute(band_2g_attr);
+ band_attr.AddAttribute(band_5g_attr);
+
+ packet->AddAttribute(band_attr);
+}
+
+void AppendWiphyFeaturesAttributes(NL80211Packet* packet) {
+ packet->AddAttribute(NL80211Attr<uint32_t>(
+ NL80211_ATTR_FEATURE_FLAGS,
+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR));
+}
+
+void VerifyScanCapabilities(const ScanCapabilities& scan_capabilities,
+ bool supports_scan_plan) {
+ EXPECT_EQ(scan_capabilities.max_num_scan_ssids,
+ kFakeMaxNumScanSSIDs);
+ EXPECT_EQ(scan_capabilities.max_num_sched_scan_ssids,
+ kFakeMaxNumSchedScanSSIDs);
+ EXPECT_EQ(scan_capabilities.max_match_sets,
+ kFakeMaxMatchSets);
+ if (supports_scan_plan) {
+ EXPECT_EQ(scan_capabilities.max_num_scan_plans,
+ kFakeMaxNumScanPlans);
+ EXPECT_EQ(scan_capabilities.max_scan_plan_interval,
+ kFakeMaxScanPlanIntervals);
+ EXPECT_EQ(scan_capabilities.max_scan_plan_iterations,
+ kFakeMaxScanPlanIterations);
+ } else {
+ EXPECT_EQ(scan_capabilities.max_num_scan_plans, (unsigned int) 0);
+ EXPECT_EQ(scan_capabilities.max_scan_plan_interval, (unsigned int) 0);
+ EXPECT_EQ(scan_capabilities.max_scan_plan_iterations, (unsigned int) 0);
+ }
+}
+
+void VerifyBandInfo(const BandInfo& band_info) {
+ vector<uint32_t> band_2g_expected = {kFakeFrequency1,
+ kFakeFrequency2, kFakeFrequency3};
+ vector<uint32_t> band_5g_expected = {kFakeFrequency4, kFakeFrequency5};
+ vector<uint32_t> band_dfs_expected = {kFakeFrequency6};
+ EXPECT_EQ(band_info.band_2g, band_2g_expected);
+ EXPECT_EQ(band_info.band_5g, band_5g_expected);
+ EXPECT_EQ(band_info.band_dfs, band_dfs_expected);
+}
+
+void VerifyWiphyFeatures(const WiphyFeatures& wiphy_features) {
+ EXPECT_TRUE(wiphy_features.supports_random_mac_oneshot_scan);
+ EXPECT_FALSE(wiphy_features.supports_random_mac_sched_scan);
+}
+
} // namespace
class NetlinkUtilsTest : public ::testing::Test {
@@ -314,64 +427,9 @@
new_wiphy.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY,
kFakeWiphyIndex));
- // Insert band information to mock netlink response.
-
- NL80211NestedAttr freq_2g_1(1);
- NL80211NestedAttr freq_2g_2(2);
- NL80211NestedAttr freq_2g_3(3);
- NL80211NestedAttr freq_5g_1(4);
- NL80211NestedAttr freq_5g_2(5);
- NL80211NestedAttr freq_dfs_1(6);
- freq_2g_1.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
- kFakeFrequency1));
- freq_2g_2.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
- kFakeFrequency2));
- freq_2g_3.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
- kFakeFrequency3));
- freq_5g_1.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
- kFakeFrequency4));
- freq_5g_2.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
- kFakeFrequency5));
- // DFS frequency.
- freq_dfs_1.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
- kFakeFrequency6));
- freq_dfs_1.AddAttribute(NL80211Attr<uint32_t>(
- NL80211_FREQUENCY_ATTR_DFS_STATE,
- NL80211_DFS_USABLE));
-
- NL80211NestedAttr band_2g_freqs(NL80211_BAND_ATTR_FREQS);
- NL80211NestedAttr band_5g_freqs(NL80211_BAND_ATTR_FREQS);
- band_2g_freqs.AddAttribute(freq_2g_1);
- band_2g_freqs.AddAttribute(freq_2g_2);
- band_2g_freqs.AddAttribute(freq_2g_3);
- band_5g_freqs.AddAttribute(freq_5g_1);
- band_5g_freqs.AddAttribute(freq_5g_2);
- band_5g_freqs.AddAttribute(freq_dfs_1);
-
- NL80211NestedAttr band_2g_attr(1);
- NL80211NestedAttr band_5g_attr(2);
- band_2g_attr.AddAttribute(band_2g_freqs);
- band_5g_attr.AddAttribute(band_5g_freqs);
-
- NL80211NestedAttr band_attr(NL80211_ATTR_WIPHY_BANDS);
- band_attr.AddAttribute(band_2g_attr);
- band_attr.AddAttribute(band_5g_attr);
-
- new_wiphy.AddAttribute(band_attr);
-
- // Insert scan capabilities to mock netlink response.
- new_wiphy.AddAttribute(NL80211Attr<uint8_t>(NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
- kFakeMaxNumScanSSIDs));
- new_wiphy.AddAttribute(NL80211Attr<uint8_t>(
- NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
- kFakeMaxNumSchedScanSSIDs));
- new_wiphy.AddAttribute(NL80211Attr<uint8_t>(NL80211_ATTR_MAX_MATCH_SETS,
- kFakeMaxMatchSets));
-
- // Insert wiphy features to mock netlink response.
- new_wiphy.AddAttribute(NL80211Attr<uint32_t>(
- NL80211_ATTR_FEATURE_FLAGS,
- NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR));
+ AppendBandInfoAttributes(&new_wiphy);
+ AppendScanCapabilitiesAttributes(&new_wiphy, true);
+ AppendWiphyFeaturesAttributes(&new_wiphy);
vector<NL80211Packet> response = {new_wiphy};
@@ -385,29 +443,42 @@
&band_info,
&scan_capabilities,
&wiphy_features));
-
- // Verify band information.
- vector<uint32_t> band_2g_expected = {kFakeFrequency1,
- kFakeFrequency2, kFakeFrequency3};
- vector<uint32_t> band_5g_expected = {kFakeFrequency4, kFakeFrequency5};
- vector<uint32_t> band_dfs_expected = {kFakeFrequency6};
- EXPECT_EQ(band_info.band_2g, band_2g_expected);
- EXPECT_EQ(band_info.band_5g, band_5g_expected);
- EXPECT_EQ(band_info.band_dfs, band_dfs_expected);
-
- // Verify scan capabilities.
- EXPECT_EQ(scan_capabilities.max_num_scan_ssids,
- kFakeMaxNumScanSSIDs);
- EXPECT_EQ(scan_capabilities.max_num_sched_scan_ssids,
- kFakeMaxNumSchedScanSSIDs);
- EXPECT_EQ(scan_capabilities.max_match_sets,
- kFakeMaxMatchSets);
-
- // Verify wiphy features.
- EXPECT_TRUE(wiphy_features.supports_random_mac_oneshot_scan);
- EXPECT_FALSE(wiphy_features.supports_random_mac_sched_scan);
+ VerifyBandInfo(band_info);
+ VerifyScanCapabilities(scan_capabilities, true);
+ VerifyWiphyFeatures(wiphy_features);
}
+TEST_F(NetlinkUtilsTest, CanGetWiphyInfoScanPlanNotSupported) {
+ NL80211Packet new_wiphy(
+ netlink_manager_->GetFamilyId(),
+ NL80211_CMD_NEW_WIPHY,
+ netlink_manager_->GetSequenceNumber(),
+ getpid());
+ new_wiphy.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY,
+ kFakeWiphyIndex));
+
+ AppendBandInfoAttributes(&new_wiphy);
+ AppendScanCapabilitiesAttributes(&new_wiphy, false);
+ AppendWiphyFeaturesAttributes(&new_wiphy);
+
+ vector<NL80211Packet> response = {new_wiphy};
+
+ EXPECT_CALL(*netlink_manager_, SendMessageAndGetResponses(_, _)).
+ WillOnce(DoAll(MakeupResponse(response), Return(true)));
+
+ BandInfo band_info;
+ ScanCapabilities scan_capabilities;
+ WiphyFeatures wiphy_features;
+ EXPECT_TRUE(netlink_utils_->GetWiphyInfo(kFakeWiphyIndex,
+ &band_info,
+ &scan_capabilities,
+ &wiphy_features));
+ VerifyBandInfo(band_info);
+ VerifyScanCapabilities(scan_capabilities, false);
+ VerifyWiphyFeatures(wiphy_features);
+}
+
+
TEST_F(NetlinkUtilsTest, CanHandleGetWiphyInfoError) {
// Mock an error response from kernel.
vector<NL80211Packet> response = {CreateControlMessageError(kFakeErrorCode)};
diff --git a/tests/offload_callback_test.cpp b/tests/offload_callback_test.cpp
new file mode 100644
index 0000000..f55d281
--- /dev/null
+++ b/tests/offload_callback_test.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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 <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "wificond/scanning/offload/offload_callback.h"
+#include "wificond/scanning/scan_result.h"
+#include "wificond/tests/mock_offload_callback_handlers.h"
+#include "wificond/tests/offload_test_utils.h"
+
+using android::hardware::wifi::offload::V1_0::ScanResult;
+using android::hardware::wifi::offload::V1_0::OffloadStatus;
+using android::hardware::wifi::offload::V1_0::OffloadStatusCode;
+using android::hardware::hidl_vec;
+using testing::NiceMock;
+
+namespace android {
+namespace wificond {
+
+class OffloadCallbackTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ dummy_scan_results_ = OffloadTestUtils::createOffloadScanResults();
+ }
+
+ void TearDown() override { dummy_scan_results_.clear(); }
+
+ std::vector<ScanResult> dummy_scan_results_;
+ std::unique_ptr<OffloadCallback> offload_callback_;
+ std::unique_ptr<NiceMock<MockOffloadCallbackHandlers>> handlers_;
+};
+
+/**
+ * Testing OffloadCallback to invoke the registered callback handler
+ * with the scan results when they are available
+ */
+TEST_F(OffloadCallbackTest, checkScanResultSize) {
+ std::vector<ScanResult> scan_result;
+ handlers_.reset(new NiceMock<MockOffloadCallbackHandlers>());
+ ON_CALL(*handlers_, OnScanResultHandler(testing::_))
+ .WillByDefault(testing::Invoke(
+ [&scan_result](std::vector<ScanResult> scanResult) -> void {
+ scan_result = scanResult;
+ }));
+ offload_callback_.reset(new OffloadCallback(handlers_.get()));
+ hidl_vec<ScanResult> offloadScanResult(dummy_scan_results_);
+ offload_callback_->onScanResult(offloadScanResult);
+ EXPECT_EQ(dummy_scan_results_.size(), scan_result.size());
+}
+
+/**
+ * Testing OffloadCallback to invoke the registered error handler
+ */
+TEST_F(OffloadCallbackTest, checkErrorStatus) {
+ OffloadStatus status_;
+ handlers_.reset(new NiceMock<MockOffloadCallbackHandlers>());
+ ON_CALL(*handlers_, OnErrorHandler(testing::_))
+ .WillByDefault(testing::Invoke(
+ [&status_](OffloadStatus status) -> void { status_ = status; }));
+ offload_callback_.reset(new OffloadCallback(handlers_.get()));
+ OffloadStatus status =
+ OffloadTestUtils::createOffloadStatus(OffloadStatusCode::ERROR);
+ offload_callback_->onError(status);
+ EXPECT_EQ(status_.code, OffloadStatusCode::ERROR);
+}
+
+} // namespace wificond
+} // namespace android
diff --git a/tests/offload_hal_test_constants.cpp b/tests/offload_hal_test_constants.cpp
new file mode 100644
index 0000000..79705fe
--- /dev/null
+++ b/tests/offload_hal_test_constants.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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;
+const uint32_t kNumChannelsInHistogram = 256;
+const uint64_t kDeathCode = 0xBEEF;
+
+} // 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
index 0000000..efc589f
--- /dev/null
+++ b/tests/offload_hal_test_constants.h
@@ -0,0 +1,56 @@
+/*
+ * 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;
+extern const uint32_t kNumChannelsInHistogram;
+extern const uint64_t kDeathCode;
+
+} // namespace offload_hal_test_constants
+} // namespace wificond
+} // namespace android
+
+#endif // WIFICOND_OFFLOAD_HAL_TEST_CONSTANTS_H_
diff --git a/tests/offload_scan_manager_test.cpp b/tests/offload_scan_manager_test.cpp
new file mode 100644
index 0000000..2dbf953
--- /dev/null
+++ b/tests/offload_scan_manager_test.cpp
@@ -0,0 +1,480 @@
+/*
+ * 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 <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android/hardware/wifi/offload/1.0/IOffload.h>
+#include <gtest/gtest.h>
+
+#include "wificond/tests/mock_offload.h"
+#include "wificond/tests/mock_offload_service_utils.h"
+#include "wificond/tests/offload_hal_test_constants.h"
+#include "wificond/tests/offload_test_utils.h"
+
+#include "wificond/scanning/offload/offload_callback.h"
+#include "wificond/scanning/offload/offload_callback_handlers.h"
+#include "wificond/scanning/offload/offload_scan_manager.h"
+#include "wificond/scanning/scan_result.h"
+
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::wifi::offload::V1_0::IOffload;
+using android::hardware::wifi::offload::V1_0::ScanResult;
+using android::hardware::wifi::offload::V1_0::OffloadStatus;
+using android::hardware::wifi::offload::V1_0::OffloadStatusCode;
+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::sp;
+using com::android::server::wifi::wificond::NativeScanResult;
+using com::android::server::wifi::wificond::NativeScanStats;
+using testing::NiceMock;
+using testing::_;
+using testing::Invoke;
+using std::shared_ptr;
+using std::unique_ptr;
+using std::vector;
+using std::bind;
+
+using namespace std::placeholders;
+using namespace android::wificond::offload_hal_test_constants;
+
+namespace android {
+namespace wificond {
+
+sp<OffloadCallback> CaptureCallback(OffloadCallbackHandlers* handler,
+ sp<OffloadCallback>* offload_callback) {
+ *offload_callback = sp<OffloadCallback>(new OffloadCallback(handler));
+ return *offload_callback;
+}
+
+OffloadDeathRecipient* CaptureDeathRecipient(
+ OffloadDeathRecipientHandler handler,
+ sp<OffloadDeathRecipient>* death_recipient_) {
+ OffloadDeathRecipient* death_recipient = new OffloadDeathRecipient(handler);
+ *death_recipient_ = sp<OffloadDeathRecipient>(death_recipient);
+ return death_recipient;
+}
+
+Return<void> HidlStatusReturn(android::wificond::StatusCallback cb,
+ OffloadStatus* status) {
+ cb(*status);
+ return Void();
+}
+
+Return<void> ScanStatusReturn(android::wificond::OnScanStatsCallback cb,
+ OffloadStatus* status) {
+ ScanStats stats;
+ cb(*status, stats);
+ return Void();
+}
+
+class OffloadScanManagerTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ ON_CALL(*mock_offload_service_utils_, GetOffloadCallback(_))
+ .WillByDefault(Invoke(bind(CaptureCallback, _1, &offload_callback_)));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_))
+ .WillByDefault(
+ Invoke(bind(CaptureDeathRecipient, _1, &death_recipient_)));
+ status = OffloadTestUtils::createOffloadStatus(OffloadStatusCode::OK);
+ ON_CALL(*mock_offload_, configureScans(_, _, _))
+ .WillByDefault(Invoke(bind(HidlStatusReturn, _3, &status)));
+ ON_CALL(*mock_offload_, subscribeScanResults(_, _))
+ .WillByDefault(Invoke(bind(HidlStatusReturn, _2, &status)));
+ ON_CALL(*mock_offload_, getScanStats(_))
+ .WillByDefault(Invoke(bind(ScanStatusReturn, _1, &status)));
+ }
+
+ void TearDown() override {
+ offload_callback_.clear();
+ death_recipient_.clear();
+ }
+
+ sp<NiceMock<MockOffload>> mock_offload_{new NiceMock<MockOffload>()};
+ sp<OffloadCallback> offload_callback_;
+ sp<OffloadDeathRecipient> death_recipient_;
+ shared_ptr<NiceMock<MockOffloadServiceUtils>> mock_offload_service_utils_{
+ new NiceMock<MockOffloadServiceUtils>()};
+ unique_ptr<OffloadScanManager> offload_scan_manager_;
+ OffloadStatus status;
+ 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};
+ uint64_t cookie_ = reinterpret_cast<uint64_t>(mock_offload_.get());
+};
+
+/**
+ * Testing OffloadScanManager for binder death with registered cookie
+ */
+TEST_F(OffloadScanManagerTest, BinderDeathRegisteredCookieAndService) {
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](vector<NativeScanResult> scanResult) -> void {}));
+ death_recipient_->serviceDied(cookie_, mock_offload_);
+ EXPECT_EQ(OffloadScanManager::kNoService,
+ offload_scan_manager_->getOffloadStatus());
+}
+
+/**
+ * Testing OffloadScanManager for binder death with invalid cookie
+ */
+TEST_F(OffloadScanManagerTest, BinderDeathUnregisteredCookie) {
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](vector<NativeScanResult> scanResult) -> void {}));
+ death_recipient_->serviceDied(kDeathCode, mock_offload_);
+ EXPECT_FALSE(OffloadScanManager::kNoService ==
+ offload_scan_manager_->getOffloadStatus());
+}
+
+/**
+ * Testing OffloadScanManager with no handle on Offloal HAL service
+ * and no registered handler for Offload Scan results
+ */
+TEST_F(OffloadScanManagerTest, ServiceNotAvailableTest) {
+ 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_,
+ [](vector<NativeScanResult> scanResult) -> void {}));
+ EXPECT_EQ(OffloadScanManager::kNoService,
+ offload_scan_manager_->getOffloadStatus());
+}
+
+/**
+ * Testing OffloadScanManager when service is available and valid handler
+ * registered for Offload Scan results
+ */
+TEST_F(OffloadScanManagerTest, ServiceAvailableTest) {
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](vector<NativeScanResult> scanResult) -> void {}));
+ EXPECT_EQ(OffloadScanManager::kNoError,
+ offload_scan_manager_->getOffloadStatus());
+}
+
+/**
+ * Testing OffloadScanManager when service is available and valid handler
+ * is registered, test to ensure that registered handler is invoked when
+ * scan results are available
+ */
+TEST_F(OffloadScanManagerTest, CallbackInvokedTest) {
+ bool callback_invoked = false;
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [&callback_invoked](vector<NativeScanResult> scanResult) -> void {
+ callback_invoked = true;
+ }));
+ vector<ScanResult> dummy_scan_results_ =
+ OffloadTestUtils::createOffloadScanResults();
+ offload_callback_->onScanResult(dummy_scan_results_);
+ EXPECT_EQ(true, callback_invoked);
+}
+
+/**
+ * Testing OffloadScanManager when service is available and valid handler
+ * is registered, ensure that error callback is invoked
+ */
+TEST_F(OffloadScanManagerTest, ErrorCallbackInvokedTest) {
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](vector<NativeScanResult> scanResult) -> void {}));
+ OffloadStatus status =
+ OffloadTestUtils::createOffloadStatus(OffloadStatusCode::ERROR);
+ offload_callback_->onError(status);
+ 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());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](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_,
+ [](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::kNotAvailable);
+}
+
+/**
+ * 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());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](vector<NativeScanResult> scanResult) -> void {}));
+ OffloadStatus status =
+ OffloadTestUtils::createOffloadStatus(OffloadStatusCode::NO_CONNECTION);
+ offload_callback_->onError(status);
+ 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());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](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());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](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());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](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());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](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);
+ OffloadStatus status =
+ OffloadTestUtils::createOffloadStatus(OffloadStatusCode::NO_CONNECTION);
+ offload_callback_->onError(status);
+ 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());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](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());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](vector<NativeScanResult> scanResult) -> void {}));
+ OffloadStatus status =
+ OffloadTestUtils::createOffloadStatus(OffloadStatusCode::NO_CONNECTION);
+ offload_callback_->onError(status);
+ EXPECT_CALL(*mock_offload_, getScanStats(_)).Times(0);
+ NativeScanStats stats;
+ bool result = offload_scan_manager_->getScanStats(&stats);
+ EXPECT_EQ(result, false);
+}
+
+/**
+ * Testing OffloadScanManager for subscribing to the scan results from
+ * Offload HAL when service is running without errors, operation failure
+ */
+TEST_F(OffloadScanManagerTest, StartScanFailedTest) {
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](vector<NativeScanResult> scanResult) -> void {}));
+ EXPECT_CALL(*mock_offload_, subscribeScanResults(_, _)).Times(0);
+ EXPECT_CALL(*mock_offload_, configureScans(_, _, _)).Times(1);
+ status = OffloadTestUtils::createOffloadStatus(OffloadStatusCode::ERROR);
+ 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::kOperationFailed);
+}
+
+/**
+ * Testing OffloadScanManager for getting scan statistics when the
+ * Offload HAL service is running without errors, getting scan stats failure
+ */
+TEST_F(OffloadScanManagerTest, getScanStatsFailedTest) {
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadService());
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadCallback(_));
+ EXPECT_CALL(*mock_offload_service_utils_, GetOffloadDeathRecipient(_));
+ ON_CALL(*mock_offload_service_utils_, GetOffloadService())
+ .WillByDefault(testing::Return(mock_offload_));
+ offload_scan_manager_.reset(new OffloadScanManager(
+ mock_offload_service_utils_,
+ [](vector<NativeScanResult> scanResult) -> void {}));
+ status = OffloadTestUtils::createOffloadStatus(OffloadStatusCode::TIMEOUT);
+ EXPECT_CALL(*mock_offload_, getScanStats(_));
+ NativeScanStats stats;
+ bool result = offload_scan_manager_->getScanStats(&stats);
+ EXPECT_EQ(result, false);
+}
+
+} // namespace wificond
+} // namespace android
diff --git a/tests/offload_scan_utils_test.cpp b/tests/offload_scan_utils_test.cpp
new file mode 100644
index 0000000..d75143a
--- /dev/null
+++ b/tests/offload_scan_utils_test.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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 <vector>
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include "wificond/scanning/offload/offload_scan_utils.h"
+#include "wificond/scanning/scan_result.h"
+#include "wificond/tests/offload_hal_test_constants.h"
+#include "wificond/tests/offload_test_utils.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 {
+
+class OffloadScanUtilsTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ dummy_scan_results_ = OffloadTestUtils::createOffloadScanResults();
+ }
+
+ void TearDown() override { dummy_scan_results_.clear(); }
+
+ vector<ScanResult> dummy_scan_results_;
+};
+
+TEST_F(OffloadScanUtilsTest, verifyConversion) {
+ 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].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
diff --git a/tests/offload_test_utils.cpp b/tests/offload_test_utils.cpp
new file mode 100644
index 0000000..2b2acd8
--- /dev/null
+++ b/tests/offload_test_utils.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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 <vector>
+
+#include "wificond/tests/offload_hal_test_constants.h"
+#include "wificond/tests/offload_test_utils.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 android::hardware::wifi::offload::V1_0::OffloadStatus;
+using android::hardware::wifi::offload::V1_0::OffloadStatusCode;
+
+using ::com::android::server::wifi::wificond::NativeScanResult;
+using ::com::android::server::wifi::wificond::NativeScanStats;
+
+using namespace android::wificond::offload_hal_test_constants;
+
+namespace android {
+namespace wificond {
+
+std::vector<ScanResult> OffloadTestUtils::createOffloadScanResults() {
+ std::vector<ScanResult> scanResults;
+ ScanResult scanResult;
+ std::vector<uint8_t> ssid(kSsid1, kSsid1 + kSsid1_size);
+ scanResult.tsf = kTsf;
+ scanResult.rssi = kRssi;
+ scanResult.frequency = kFrequency1;
+ scanResult.capability = kCapability;
+ memcpy(&scanResult.bssid[0], &kBssid[0], kBssidSize);
+ scanResult.networkInfo.ssid = ssid;
+ scanResult.networkInfo.flags = kNetworkFlags;
+ scanResults.push_back(scanResult);
+ 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;
+}
+
+OffloadStatus OffloadTestUtils::createOffloadStatus(OffloadStatusCode code) {
+ return createOffloadStatus(code, "");
+}
+
+OffloadStatus OffloadTestUtils::createOffloadStatus(OffloadStatusCode code,
+ const std::string& desc) {
+ return {code, desc};
+}
+
+} // namespace wificond
+} // namespace android
diff --git a/tests/offload_test_utils.h b/tests/offload_test_utils.h
new file mode 100644
index 0000000..f2370e2
--- /dev/null
+++ b/tests/offload_test_utils.h
@@ -0,0 +1,48 @@
+/*
+ * 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_OFFLOAD_TEST_UTILS_H_
+#define WIFICOND_OFFLOAD_TEST_UTILS_H_
+
+#include <android/hardware/wifi/offload/1.0/IOffload.h>
+#include <vector>
+
+#include "wificond/scanning/offload/scan_stats.h"
+#include "wificond/scanning/scan_result.h"
+
+namespace android {
+namespace wificond {
+
+class OffloadTestUtils {
+ public:
+ static std::vector<android::hardware::wifi::offload::V1_0::ScanResult>
+ createOffloadScanResults();
+ static android::hardware::wifi::offload::V1_0::ScanStats createScanStats(
+ ::com::android::server::wifi::wificond::
+ NativeScanStats* /* nativeScanStats */);
+ static android::hardware::wifi::offload::V1_0::OffloadStatus
+ createOffloadStatus(
+ android::hardware::wifi::offload::V1_0::OffloadStatusCode code);
+ static android::hardware::wifi::offload::V1_0::OffloadStatus
+ createOffloadStatus(
+ android::hardware::wifi::offload::V1_0::OffloadStatusCode code,
+ const std::string& desc);
+};
+
+} // namespace wificond
+} // namespace android
+
+#endif // WIFICOND_OFFLOAD_TEST_UTILS_H
diff --git a/tests/scan_stats_unittest.cpp b/tests/scan_stats_unittest.cpp
new file mode 100644
index 0000000..6eb72d6
--- /dev/null
+++ b/tests/scan_stats_unittest.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 < kNumChannelsInHistogram; i++) {
+ histogram_channels.push_back(kNumChannelsInHistogram - 1 - 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
diff --git a/tests/scan_utils_unittest.cpp b/tests/scan_utils_unittest.cpp
index 3dbfe21..28ea283 100644
--- a/tests/scan_utils_unittest.cpp
+++ b/tests/scan_utils_unittest.cpp
@@ -32,8 +32,10 @@
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 @@
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(
@@ -130,7 +137,9 @@
WillOnce(Invoke(bind(
AppendMessageAndReturn, response, true, _1, _2)));
- EXPECT_TRUE(scan_utils_.Scan(kFakeInterfaceIndex, kFakeUseRandomMAC, {}, {}));
+ int errno_ignored;
+ EXPECT_TRUE(scan_utils_.Scan(kFakeInterfaceIndex, kFakeUseRandomMAC, {}, {},
+ &errno_ignored));
// TODO(b/34231420): Add validation of requested scan ssids, threshold,
// and frequencies.
}
@@ -143,7 +152,10 @@
DoesNL80211PacketMatchCommand(NL80211_CMD_TRIGGER_SCAN), _)).
WillOnce(Invoke(bind(
AppendMessageAndReturn, response, true, _1, _2)));
- EXPECT_FALSE(scan_utils_.Scan(kFakeInterfaceIndex, kFakeUseRandomMAC, {}, {}));
+ int error_code;
+ EXPECT_FALSE(scan_utils_.Scan(kFakeInterfaceIndex, kFakeUseRandomMAC, {}, {},
+ &error_code));
+ EXPECT_EQ(kFakeErrorCode, error_code);
}
TEST_F(ScanUtilsTest, CanSendSchedScanRequest) {
@@ -154,10 +166,11 @@
DoesNL80211PacketMatchCommand(NL80211_CMD_START_SCHED_SCAN), _)).
WillOnce(Invoke(bind(
AppendMessageAndReturn, response, true, _1, _2)));
+ int errno_ignored;
EXPECT_TRUE(scan_utils_.StartScheduledScan(
kFakeInterfaceIndex,
- kFakeScheduledScanIntervalMs,
- kFakeRssiThreshold, kFakeUseRandomMAC, {}, {}, {}));
+ SchedScanIntervalSetting(),
+ kFakeRssiThreshold, kFakeUseRandomMAC, {}, {}, {}, &errno_ignored));
// TODO(b/34231420): Add validation of requested scan ssids, threshold,
// and frequencies.
}
@@ -170,10 +183,112 @@
DoesNL80211PacketMatchCommand(NL80211_CMD_START_SCHED_SCAN), _)).
WillOnce(Invoke(bind(
AppendMessageAndReturn, response, true, _1, _2)));
+ int error_code;
EXPECT_FALSE(scan_utils_.StartScheduledScan(
kFakeInterfaceIndex,
- kFakeScheduledScanIntervalMs,
- kFakeRssiThreshold, kFakeUseRandomMAC, {}, {}, {}));
+ 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;
+ NL80211NestedAttr bss(NL80211_ATTR_BSS);
+ bss.AddAttribute(
+ NL80211Attr<uint64_t>(NL80211_BSS_LAST_SEEN_BOOTTIME,
+ kLastSeenTimestampNanoSeconds));
+ bss.AddAttribute(
+ NL80211Attr<uint64_t>(NL80211_BSS_TSF, kBssTsfTimestampMicroSeconds));
+ uint64_t timestamp_microseconds;
+ EXPECT_TRUE(scan_utils_.GetBssTimestampForTesting(
+ bss, ×tamp_microseconds));
+ EXPECT_EQ(kLastSeenTimestampNanoSeconds/1000, timestamp_microseconds);
+}
+
+TEST_F(ScanUtilsTest, CanHandleMissingLastSeenSinceBootNetlinkAttribute) {
+ constexpr uint64_t kBssTsfTimestampMicroSeconds = 654321;
+ NL80211NestedAttr bss(NL80211_ATTR_BSS);
+ bss.AddAttribute(
+ NL80211Attr<uint64_t>(NL80211_BSS_TSF, kBssTsfTimestampMicroSeconds));
+ uint64_t timestamp_microseconds;
+ EXPECT_TRUE(scan_utils_.GetBssTimestampForTesting(
+ bss, ×tamp_microseconds));
+ EXPECT_EQ(kBssTsfTimestampMicroSeconds, timestamp_microseconds);
+}
+
+// Probe TSF is newer.
+TEST_F(ScanUtilsTest, CanPickMostRecentTimestampBetweenBetweenProbeAndBeacon1) {
+ constexpr uint64_t kBssBeaconTsfTimestampMicroSeconds = 654321;
+ constexpr uint64_t kBssTsfTimestampMicroSeconds =
+ kBssBeaconTsfTimestampMicroSeconds + 2000;
+ NL80211NestedAttr bss(NL80211_ATTR_BSS);
+ bss.AddAttribute(
+ NL80211Attr<uint64_t>(NL80211_BSS_BEACON_TSF,
+ kBssBeaconTsfTimestampMicroSeconds));
+ bss.AddAttribute(
+ NL80211Attr<uint64_t>(NL80211_BSS_TSF, kBssTsfTimestampMicroSeconds));
+ uint64_t timestamp_microseconds;
+ EXPECT_TRUE(scan_utils_.GetBssTimestampForTesting(
+ bss, ×tamp_microseconds));
+ EXPECT_EQ(kBssTsfTimestampMicroSeconds, timestamp_microseconds);
+}
+
+// Beacon TSF is newer.
+TEST_F(ScanUtilsTest, CanPickMostRecentTimestampBetweenBetweenProbeAndBeacon2) {
+ constexpr uint64_t kBssTsfTimestampMicroSeconds = 654321;
+ constexpr uint64_t kBssBeaconTsfTimestampMicroSeconds =
+ kBssTsfTimestampMicroSeconds + 2000;
+ NL80211NestedAttr bss(NL80211_ATTR_BSS);
+ bss.AddAttribute(
+ NL80211Attr<uint64_t>(NL80211_BSS_BEACON_TSF,
+ kBssBeaconTsfTimestampMicroSeconds));
+ bss.AddAttribute(
+ NL80211Attr<uint64_t>(NL80211_BSS_TSF, kBssTsfTimestampMicroSeconds));
+ uint64_t timestamp_microseconds;
+ EXPECT_TRUE(scan_utils_.GetBssTimestampForTesting(
+ bss, ×tamp_microseconds));
+ EXPECT_EQ(kBssBeaconTsfTimestampMicroSeconds, timestamp_microseconds);
}
} // namespace wificond
diff --git a/tests/scanner_unittest.cpp b/tests/scanner_unittest.cpp
new file mode 100644
index 0000000..bbaeffd
--- /dev/null
+++ b/tests/scanner_unittest.cpp
@@ -0,0 +1,253 @@
+/*
+ * 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <wifi_system_test/mock_interface_tool.h>
+#include <wifi_system_test/mock_supplicant_manager.h>
+
+#include "wificond/scanning/scanner_impl.h"
+#include "wificond/tests/mock_client_interface_impl.h"
+#include "wificond/tests/mock_netlink_manager.h"
+#include "wificond/tests/mock_netlink_utils.h"
+#include "wificond/tests/mock_offload_service_utils.h"
+#include "wificond/tests/mock_scan_utils.h"
+
+using ::android::binder::Status;
+using ::android::wifi_system::MockInterfaceTool;
+using ::android::wifi_system::MockSupplicantManager;
+using ::com::android::server::wifi::wificond::SingleScanSettings;
+using ::com::android::server::wifi::wificond::PnoSettings;
+using ::com::android::server::wifi::wificond::NativeScanResult;
+using ::testing::Invoke;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::_;
+using std::shared_ptr;
+using std::unique_ptr;
+using std::vector;
+
+using namespace std::placeholders;
+
+namespace android {
+namespace wificond {
+
+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.
+// |interface_index_ignored|, |request_random_mac_ignored|, |ssids_ignored|,
+// |freqs_ignored|, |error_code| are mapped to existing parameters of ScanUtils::Scan().
+// |mock_error_code| is a additional parameter used for specifying expected error code.
+bool ReturnErrorCodeForScanRequest(
+ int mock_error_code,
+ uint32_t interface_index_ignored,
+ bool request_random_mac_ignored,
+ const std::vector<std::vector<uint8_t>>& ssids_ignored,
+ const std::vector<uint32_t>& freqs_ignored,
+ int* error_code) {
+ *error_code = mock_error_code;
+ // Returing false because this helper function is used for failure case.
+ 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 {
+ protected:
+ void SetUp() override {
+ ON_CALL(*offload_service_utils_, IsOffloadScanSupported()).WillByDefault(
+ Return(false));
+ netlink_scanner_.reset(new ScannerImpl(
+ kFakeWiphyIndex, kFakeInterfaceIndex,
+ scan_capabilities_, wiphy_features_,
+ &client_interface_impl_,
+ &netlink_utils_, &scan_utils_, offload_service_utils_));
+ }
+
+ unique_ptr<ScannerImpl> netlink_scanner_;
+ NiceMock<MockNetlinkManager> netlink_manager_;
+ NiceMock<MockNetlinkUtils> netlink_utils_{&netlink_manager_};
+ NiceMock<MockScanUtils> scan_utils_{&netlink_manager_};
+ NiceMock<MockInterfaceTool> if_tool_;
+ NiceMock<MockSupplicantManager> supplicant_manager_;
+ NiceMock<MockClientInterfaceImpl> client_interface_impl_{
+ &if_tool_, &supplicant_manager_, &netlink_utils_, &scan_utils_};
+ shared_ptr<NiceMock<MockOffloadServiceUtils>> offload_service_utils_{
+ new NiceMock<MockOffloadServiceUtils>()};
+ ScanCapabilities scan_capabilities_;
+ WiphyFeatures wiphy_features_;
+};
+
+TEST_F(ScannerTest, TestSingleScan) {
+ EXPECT_CALL(scan_utils_, Scan(_, _, _, _, _)).WillOnce(Return(true));
+ bool success = false;
+ EXPECT_TRUE(netlink_scanner_->scan(SingleScanSettings(), &success).isOk());
+ EXPECT_TRUE(success);
+}
+
+TEST_F(ScannerTest, TestSingleScanFailure) {
+ EXPECT_CALL(
+ scan_utils_,
+ Scan(_, _, _, _, _)).
+ WillOnce(Invoke(bind(
+ ReturnErrorCodeForScanRequest, EBUSY, _1, _2, _3, _4, _5)));
+
+ bool success = false;
+ EXPECT_TRUE(netlink_scanner_->scan(SingleScanSettings(), &success).isOk());
+ EXPECT_FALSE(success);
+}
+
+TEST_F(ScannerTest, TestProcessAbortsOnScanReturningNoDeviceError) {
+ ON_CALL(
+ scan_utils_,
+ Scan(_, _, _, _, _)).
+ WillByDefault(Invoke(bind(
+ ReturnErrorCodeForScanRequest, ENODEV, _1, _2, _3, _4, _5)));
+
+ bool success_ignored;
+ EXPECT_DEATH(
+ netlink_scanner_->scan(SingleScanSettings(), &success_ignored),
+ "Driver is in a bad state*");
+}
+
+TEST_F(ScannerTest, TestAbortScan) {
+ bool single_scan_success = false;
+ EXPECT_CALL(scan_utils_, Scan(_, _, _, _, _)).WillOnce(Return(true));
+ EXPECT_TRUE(netlink_scanner_->scan(SingleScanSettings(),
+ &single_scan_success).isOk());
+ EXPECT_TRUE(single_scan_success);
+
+ EXPECT_CALL(scan_utils_, AbortScan(_));
+ EXPECT_TRUE(netlink_scanner_->abortScan().isOk());
+}
+
+TEST_F(ScannerTest, TestAbortScanNotIssuedIfNoOngoingScan) {
+ EXPECT_CALL(scan_utils_, AbortScan(_)).Times(0);
+ EXPECT_TRUE(netlink_scanner_->abortScan().isOk());
+}
+
+TEST_F(ScannerTest, TestGetScanResults) {
+ vector<NativeScanResult> scan_results;
+ EXPECT_CALL(scan_utils_, GetScanResult(_, _)).WillOnce(Return(true));
+ EXPECT_TRUE(netlink_scanner_->getScanResults(&scan_results).isOk());
+}
+
+TEST_F(ScannerTest, TestStartPnoScanViaNetlink) {
+ bool success = false;
+ EXPECT_CALL(scan_utils_, StartScheduledScan(_, _, _, _, _, _, _, _)).
+ WillOnce(Return(true));
+ EXPECT_TRUE(netlink_scanner_->startPnoScan(PnoSettings(), &success).isOk());
+ EXPECT_TRUE(success);
+}
+
+TEST_F(ScannerTest, TestStopPnoScanViaNetlink) {
+ bool success = false;
+ // StopScheduledScan() will be called no matter if there is an ongoing
+ // scheduled scan or not. This is for making the system more robust.
+ EXPECT_CALL(scan_utils_, StopScheduledScan(_)).WillOnce(Return(true));
+ EXPECT_TRUE(netlink_scanner_->stopPnoScan(&success).isOk());
+ 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