From 675609baa6d2d8ec0a08a8b24d3173f4768459e2 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Tue, 31 Oct 2017 14:24:58 -0700 Subject: [PATCH 1/6] wifi(implementation): Support multiple ifaces of same type Making all of the iface object fields in WifiChip to vectors to support multiple ifaces of the same type. Bug: 65671875 Test: Device boots up and connects to wifi networks. Change-Id: I4c0c927c0269e54210cc1f81203c1797d72e969c --- wifi/1.2/default/wifi_ap_iface.cpp | 2 + wifi/1.2/default/wifi_ap_iface.h | 1 + wifi/1.2/default/wifi_chip.cpp | 132 ++++++++++++++++++---------- wifi/1.2/default/wifi_chip.h | 8 +- wifi/1.2/default/wifi_nan_iface.cpp | 2 + wifi/1.2/default/wifi_nan_iface.h | 1 + wifi/1.2/default/wifi_p2p_iface.cpp | 2 + wifi/1.2/default/wifi_p2p_iface.h | 1 + wifi/1.2/default/wifi_sta_iface.cpp | 2 + wifi/1.2/default/wifi_sta_iface.h | 1 + 10 files changed, 102 insertions(+), 50 deletions(-) diff --git a/wifi/1.2/default/wifi_ap_iface.cpp b/wifi/1.2/default/wifi_ap_iface.cpp index 284f9b9774..92b7b48d98 100644 --- a/wifi/1.2/default/wifi_ap_iface.cpp +++ b/wifi/1.2/default/wifi_ap_iface.cpp @@ -40,6 +40,8 @@ void WifiApIface::invalidate() { bool WifiApIface::isValid() { return is_valid_; } +std::string WifiApIface::getName() { return ifname_; } + Return WifiApIface::getName(getName_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, &WifiApIface::getNameInternal, hidl_status_cb); diff --git a/wifi/1.2/default/wifi_ap_iface.h b/wifi/1.2/default/wifi_ap_iface.h index 6375121c80..5363ec2586 100644 --- a/wifi/1.2/default/wifi_ap_iface.h +++ b/wifi/1.2/default/wifi_ap_iface.h @@ -39,6 +39,7 @@ class WifiApIface : public V1_0::IWifiApIface { // Refer to |WifiChip::invalidate()|. void invalidate(); bool isValid(); + std::string getName(); // HIDL methods exposed. Return getName(getName_cb hidl_status_cb) override; diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp index 4e2191d10b..49cf8882b1 100644 --- a/wifi/1.2/default/wifi_chip.cpp +++ b/wifi/1.2/default/wifi_chip.cpp @@ -27,8 +27,8 @@ namespace { using android::hardware::hidl_string; using android::hardware::hidl_vec; using android::hardware::wifi::V1_0::ChipModeId; -using android::hardware::wifi::V1_0::IWifiChip; using android::hardware::wifi::V1_0::IfaceType; +using android::hardware::wifi::V1_0::IWifiChip; using android::sp; constexpr ChipModeId kStaChipModeId = 0; @@ -36,11 +36,39 @@ constexpr ChipModeId kApChipModeId = 1; constexpr ChipModeId kInvalidModeId = UINT32_MAX; template -void invalidateAndClear(sp& iface) { - if (iface.get()) { +void invalidateAndClear(std::vector>& ifaces, sp iface) { + iface->invalidate(); + ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface), + ifaces.end()); +} + +template +void invalidateAndClearAll(std::vector>& ifaces) { + for (const auto& iface : ifaces) { iface->invalidate(); - iface.clear(); } + ifaces.clear(); +} + +template +std::vector getNames(std::vector>& ifaces) { + std::vector names; + for (const auto& iface : ifaces) { + names.emplace_back(iface->getName()); + } + return names; +} + +template +sp findUsingName(std::vector>& ifaces, + const std::string& name) { + std::vector names; + for (const auto& iface : ifaces) { + if (name == iface->getName()) { + return iface; + } + } + return nullptr; } std::string getWlan0IfaceName() { @@ -317,10 +345,10 @@ Return WifiChip::resetTxPowerScenario( } void WifiChip::invalidateAndRemoveAllIfaces() { - invalidateAndClear(ap_iface_); - invalidateAndClear(nan_iface_); - invalidateAndClear(p2p_iface_); - invalidateAndClear(sta_iface_); + invalidateAndClearAll(ap_ifaces_); + invalidateAndClearAll(nan_ifaces_); + invalidateAndClearAll(p2p_ifaces_); + invalidateAndClearAll(sta_ifaces_); // Since all the ifaces are invalid now, all RTT controller objects // using those ifaces also need to be invalidated. for (const auto& rtt : rtt_controllers_) { @@ -497,40 +525,43 @@ WifiChip::requestFirmwareDebugDumpInternal() { } std::pair> WifiChip::createApIfaceInternal() { - if (current_mode_id_ != kApChipModeId || ap_iface_.get()) { + if (current_mode_id_ != kApChipModeId || !ap_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } std::string ifname = getWlan0IfaceName(); - ap_iface_ = new WifiApIface(ifname, legacy_hal_); + sp iface = new WifiApIface(ifname, legacy_hal_); + ap_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; } } - return {createWifiStatus(WifiStatusCode::SUCCESS), ap_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } std::pair> WifiChip::getApIfaceNamesInternal() { - if (!ap_iface_.get()) { + if (ap_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::SUCCESS), {}}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), {getWlan0IfaceName()}}; + return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(ap_ifaces_)}; } std::pair> WifiChip::getApIfaceInternal( const std::string& ifname) { - if (!ap_iface_.get() || (ifname != getWlan0IfaceName())) { + const auto iface = findUsingName(ap_ifaces_, ifname); + if (!iface.get()) { return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), ap_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) { - if (!ap_iface_.get() || (ifname != getWlan0IfaceName())) { + const auto iface = findUsingName(ap_ifaces_, ifname); + if (!iface.get()) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } - invalidateAndClear(ap_iface_); + invalidateAndClear(ap_ifaces_, iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceRemoved callback"; @@ -542,18 +573,19 @@ WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) { std::pair> WifiChip::createNanIfaceInternal() { // Only 1 of NAN or P2P iface can be active at a time. if (WifiFeatureFlags::wifiHidlFeatureAware) { - if (current_mode_id_ != kStaChipModeId || nan_iface_.get() || - p2p_iface_.get()) { + if (current_mode_id_ != kStaChipModeId || !nan_ifaces_.empty() || + !p2p_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } std::string ifname = getWlan0IfaceName(); - nan_iface_ = new WifiNanIface(ifname, legacy_hal_); + sp iface = new WifiNanIface(ifname, legacy_hal_); + nan_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; } } - return {createWifiStatus(WifiStatusCode::SUCCESS), nan_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } else { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } @@ -561,25 +593,27 @@ std::pair> WifiChip::createNanIfaceInternal() { std::pair> WifiChip::getNanIfaceNamesInternal() { - if (!nan_iface_.get()) { + if (nan_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::SUCCESS), {}}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), {getWlan0IfaceName()}}; + return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)}; } std::pair> WifiChip::getNanIfaceInternal( const std::string& ifname) { - if (!nan_iface_.get() || (ifname != getWlan0IfaceName())) { + const auto iface = findUsingName(nan_ifaces_, ifname); + if (!iface.get()) { return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), nan_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) { - if (!nan_iface_.get() || (ifname != getWlan0IfaceName())) { + const auto iface = findUsingName(nan_ifaces_, ifname); + if (!iface.get()) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } - invalidateAndClear(nan_iface_); + invalidateAndClear(nan_ifaces_, iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceRemoved(IfaceType::NAN, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; @@ -590,41 +624,44 @@ WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) { std::pair> WifiChip::createP2pIfaceInternal() { // Only 1 of NAN or P2P iface can be active at a time. - if (current_mode_id_ != kStaChipModeId || p2p_iface_.get() || - nan_iface_.get()) { + if (current_mode_id_ != kStaChipModeId || !p2p_ifaces_.empty() || + !nan_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } std::string ifname = getP2pIfaceName(); - p2p_iface_ = new WifiP2pIface(ifname, legacy_hal_); + sp iface = new WifiP2pIface(ifname, legacy_hal_); + p2p_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; } } - return {createWifiStatus(WifiStatusCode::SUCCESS), p2p_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } std::pair> WifiChip::getP2pIfaceNamesInternal() { - if (!p2p_iface_.get()) { + if (p2p_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::SUCCESS), {}}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), {getP2pIfaceName()}}; + return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(p2p_ifaces_)}; } std::pair> WifiChip::getP2pIfaceInternal( const std::string& ifname) { - if (!p2p_iface_.get() || (ifname != getP2pIfaceName())) { + const auto iface = findUsingName(p2p_ifaces_, ifname); + if (!iface.get()) { return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), p2p_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) { - if (!p2p_iface_.get() || (ifname != getP2pIfaceName())) { + const auto iface = findUsingName(p2p_ifaces_, ifname); + if (!iface.get()) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } - invalidateAndClear(p2p_iface_); + invalidateAndClear(p2p_ifaces_, iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceRemoved callback"; @@ -634,40 +671,43 @@ WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) { } std::pair> WifiChip::createStaIfaceInternal() { - if (current_mode_id_ != kStaChipModeId || sta_iface_.get()) { + if (current_mode_id_ != kStaChipModeId || !sta_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } std::string ifname = getWlan0IfaceName(); - sta_iface_ = new WifiStaIface(ifname, legacy_hal_); + sp iface = new WifiStaIface(ifname, legacy_hal_); + sta_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; } } - return {createWifiStatus(WifiStatusCode::SUCCESS), sta_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } std::pair> WifiChip::getStaIfaceNamesInternal() { - if (!sta_iface_.get()) { + if (sta_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::SUCCESS), {}}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), {getWlan0IfaceName()}}; + return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)}; } std::pair> WifiChip::getStaIfaceInternal( const std::string& ifname) { - if (!sta_iface_.get() || (ifname != getWlan0IfaceName())) { + const auto iface = findUsingName(sta_ifaces_, ifname); + if (!iface.get()) { return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), sta_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) { - if (!sta_iface_.get() || (ifname != getWlan0IfaceName())) { + const auto iface = findUsingName(sta_ifaces_, ifname); + if (!iface.get()) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } - invalidateAndClear(sta_iface_); + invalidateAndClear(sta_ifaces_, iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceRemoved callback"; diff --git a/wifi/1.2/default/wifi_chip.h b/wifi/1.2/default/wifi_chip.h index ac59d59102..4830af9f72 100644 --- a/wifi/1.2/default/wifi_chip.h +++ b/wifi/1.2/default/wifi_chip.h @@ -193,10 +193,10 @@ class WifiChip : public V1_1::IWifiChip { ChipId chip_id_; std::weak_ptr legacy_hal_; std::weak_ptr mode_controller_; - sp ap_iface_; - sp nan_iface_; - sp p2p_iface_; - sp sta_iface_; + std::vector> ap_ifaces_; + std::vector> nan_ifaces_; + std::vector> p2p_ifaces_; + std::vector> sta_ifaces_; std::vector> rtt_controllers_; bool is_valid_; uint32_t current_mode_id_; diff --git a/wifi/1.2/default/wifi_nan_iface.cpp b/wifi/1.2/default/wifi_nan_iface.cpp index 1d786e3b28..7a597ae247 100644 --- a/wifi/1.2/default/wifi_nan_iface.cpp +++ b/wifi/1.2/default/wifi_nan_iface.cpp @@ -489,6 +489,8 @@ void WifiNanIface::invalidate() { bool WifiNanIface::isValid() { return is_valid_; } +std::string WifiNanIface::getName() { return ifname_; } + std::set> WifiNanIface::getEventCallbacks() { return event_cb_handler_.getCallbacks(); } diff --git a/wifi/1.2/default/wifi_nan_iface.h b/wifi/1.2/default/wifi_nan_iface.h index 2ca2e45a7d..6fa7b0c1e9 100644 --- a/wifi/1.2/default/wifi_nan_iface.h +++ b/wifi/1.2/default/wifi_nan_iface.h @@ -41,6 +41,7 @@ class WifiNanIface : public V1_0::IWifiNanIface { // Refer to |WifiChip::invalidate()|. void invalidate(); bool isValid(); + std::string getName(); // HIDL methods exposed. Return getName(getName_cb hidl_status_cb) override; diff --git a/wifi/1.2/default/wifi_p2p_iface.cpp b/wifi/1.2/default/wifi_p2p_iface.cpp index f1fbf2c9bc..92bbaee388 100644 --- a/wifi/1.2/default/wifi_p2p_iface.cpp +++ b/wifi/1.2/default/wifi_p2p_iface.cpp @@ -39,6 +39,8 @@ void WifiP2pIface::invalidate() { bool WifiP2pIface::isValid() { return is_valid_; } +std::string WifiP2pIface::getName() { return ifname_; } + Return WifiP2pIface::getName(getName_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, &WifiP2pIface::getNameInternal, hidl_status_cb); diff --git a/wifi/1.2/default/wifi_p2p_iface.h b/wifi/1.2/default/wifi_p2p_iface.h index 839d3c35b6..76120b1574 100644 --- a/wifi/1.2/default/wifi_p2p_iface.h +++ b/wifi/1.2/default/wifi_p2p_iface.h @@ -39,6 +39,7 @@ class WifiP2pIface : public V1_0::IWifiP2pIface { // Refer to |WifiChip::invalidate()|. void invalidate(); bool isValid(); + std::string getName(); // HIDL methods exposed. Return getName(getName_cb hidl_status_cb) override; diff --git a/wifi/1.2/default/wifi_sta_iface.cpp b/wifi/1.2/default/wifi_sta_iface.cpp index c8605eedaa..6faf009379 100644 --- a/wifi/1.2/default/wifi_sta_iface.cpp +++ b/wifi/1.2/default/wifi_sta_iface.cpp @@ -49,6 +49,8 @@ void WifiStaIface::invalidate() { bool WifiStaIface::isValid() { return is_valid_; } +std::string WifiStaIface::getName() { return ifname_; } + std::set> WifiStaIface::getEventCallbacks() { return event_cb_handler_.getCallbacks(); } diff --git a/wifi/1.2/default/wifi_sta_iface.h b/wifi/1.2/default/wifi_sta_iface.h index 6731864dec..423365cfbd 100644 --- a/wifi/1.2/default/wifi_sta_iface.h +++ b/wifi/1.2/default/wifi_sta_iface.h @@ -42,6 +42,7 @@ class WifiStaIface : public V1_0::IWifiStaIface { void invalidate(); bool isValid(); std::set> getEventCallbacks(); + std::string getName(); // HIDL methods exposed. Return getName(getName_cb hidl_status_cb) override; From 200a17db77a00685712d762d138c292ca82cdc9a Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 1 Nov 2017 13:03:35 -0700 Subject: [PATCH 2/6] wifi(implementation): Add unit test framework We're going to add some non-trivial logic in wifi chip to handle multiple chip configurations (to support devices with different capabilities). So, adding a unit test framework in preparation for testing those changes. The mocks only mock legacy HAL methods which are in use during chip configuration & interface creation/deletion. Bug: 68775880 Test: Compiles Change-Id: I8575df02f54656f77077d14ac9535ccc974bdff3 --- wifi/1.2/default/Android.mk | 65 ++++++++++++++++- wifi/1.2/default/service.cpp | 13 +++- wifi/1.2/default/tests/main.cpp | 28 +++++++ .../default/tests/mock_wifi_feature_flags.cpp | 35 +++++++++ .../default/tests/mock_wifi_feature_flags.h | 45 ++++++++++++ .../default/tests/mock_wifi_legacy_hal.cpp | 37 ++++++++++ wifi/1.2/default/tests/mock_wifi_legacy_hal.h | 54 ++++++++++++++ .../tests/mock_wifi_mode_controller.cpp | 37 ++++++++++ .../default/tests/mock_wifi_mode_controller.h | 45 ++++++++++++ wifi/1.2/default/tests/runtests.sh | 50 +++++++++++++ .../default/tests/wifi_chip_unit_tests.cpp | 73 +++++++++++++++++++ wifi/1.2/default/wifi.cpp | 13 +++- wifi/1.2/default/wifi.h | 7 +- wifi/1.2/default/wifi_chip.cpp | 9 ++- wifi/1.2/default/wifi_chip.h | 12 ++- wifi/1.2/default/wifi_feature_flags.cpp | 42 +++++++++++ wifi/1.2/default/wifi_feature_flags.h | 11 +-- wifi/1.2/default/wifi_legacy_hal.cpp | 8 +- wifi/1.2/default/wifi_legacy_hal.h | 23 +++--- wifi/1.2/default/wifi_mode_controller.h | 7 +- 20 files changed, 575 insertions(+), 39 deletions(-) create mode 100644 wifi/1.2/default/tests/main.cpp create mode 100644 wifi/1.2/default/tests/mock_wifi_feature_flags.cpp create mode 100644 wifi/1.2/default/tests/mock_wifi_feature_flags.h create mode 100644 wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp create mode 100644 wifi/1.2/default/tests/mock_wifi_legacy_hal.h create mode 100644 wifi/1.2/default/tests/mock_wifi_mode_controller.cpp create mode 100644 wifi/1.2/default/tests/mock_wifi_mode_controller.h create mode 100755 wifi/1.2/default/tests/runtests.sh create mode 100644 wifi/1.2/default/tests/wifi_chip_unit_tests.cpp create mode 100644 wifi/1.2/default/wifi_feature_flags.cpp diff --git a/wifi/1.2/default/Android.mk b/wifi/1.2/default/Android.mk index b242cfc4e0..2205e4e0f0 100644 --- a/wifi/1.2/default/Android.mk +++ b/wifi/1.2/default/Android.mk @@ -13,8 +13,11 @@ # limitations under the License. LOCAL_PATH := $(call my-dir) +### +### android.hardware.wifi static library +### include $(CLEAR_VARS) -LOCAL_MODULE := android.hardware.wifi@1.0-service +LOCAL_MODULE := android.hardware.wifi@1.0-service-lib LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_PROPRIETARY_MODULE := true LOCAL_CPPFLAGS := -Wall -Werror -Wextra @@ -24,10 +27,10 @@ endif LOCAL_SRC_FILES := \ hidl_struct_util.cpp \ hidl_sync_util.cpp \ - service.cpp \ wifi.cpp \ wifi_ap_iface.cpp \ wifi_chip.cpp \ + wifi_feature_flags.cpp \ wifi_legacy_hal.cpp \ wifi_legacy_hal_stubs.cpp \ wifi_mode_controller.cpp \ @@ -49,5 +52,63 @@ LOCAL_SHARED_LIBRARIES := \ android.hardware.wifi@1.0 \ android.hardware.wifi@1.1 \ android.hardware.wifi@1.2 +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) +include $(BUILD_STATIC_LIBRARY) + +### +### android.hardware.wifi daemon +### +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.wifi@1.0-service +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_CPPFLAGS := -Wall -Werror -Wextra +LOCAL_SRC_FILES := \ + service.cpp +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libcutils \ + libhidlbase \ + libhidltransport \ + liblog \ + libnl \ + libutils \ + libwifi-hal \ + libwifi-system-iface \ + android.hardware.wifi@1.0 \ + android.hardware.wifi@1.1 \ + android.hardware.wifi@1.2 +LOCAL_STATIC_LIBRARIES := \ + android.hardware.wifi@1.0-service-lib LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc include $(BUILD_EXECUTABLE) + +### +### android.hardware.wifi unit tests. +### +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.wifi@1.0-service-tests +LOCAL_SRC_FILES := \ + tests/main.cpp \ + tests/mock_wifi_feature_flags.cpp \ + tests/mock_wifi_legacy_hal.cpp \ + tests/mock_wifi_mode_controller.cpp \ + tests/wifi_chip_unit_tests.cpp +LOCAL_STATIC_LIBRARIES := \ + libgmock \ + libgtest \ + android.hardware.wifi@1.0-service-lib +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libcutils \ + libhidlbase \ + libhidltransport \ + liblog \ + libnl \ + libutils \ + libwifi-hal \ + libwifi-system-iface \ + android.hardware.wifi@1.0 \ + android.hardware.wifi@1.1 \ + android.hardware.wifi@1.2 +include $(BUILD_NATIVE_TEST) diff --git a/wifi/1.2/default/service.cpp b/wifi/1.2/default/service.cpp index 6297cf2158..01d22bd881 100644 --- a/wifi/1.2/default/service.cpp +++ b/wifi/1.2/default/service.cpp @@ -20,9 +20,17 @@ #include #include "wifi.h" +#include "wifi_feature_flags.h" +#include "wifi_legacy_hal.h" +#include "wifi_mode_controller.h" using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; +using android::hardware::wifi::V1_2::implementation::feature_flags:: + WifiFeatureFlags; +using android::hardware::wifi::V1_2::implementation::legacy_hal::WifiLegacyHal; +using android::hardware::wifi::V1_2::implementation::mode_controller:: + WifiModeController; int main(int /*argc*/, char** argv) { android::base::InitLogging( @@ -33,7 +41,10 @@ int main(int /*argc*/, char** argv) { // Setup hwbinder service android::sp service = - new android::hardware::wifi::V1_2::implementation::Wifi(); + new android::hardware::wifi::V1_2::implementation::Wifi( + std::make_shared(), + std::make_shared(), + std::make_shared()); CHECK_EQ(service->registerAsService(), android::NO_ERROR) << "Failed to register wifi HAL"; diff --git a/wifi/1.2/default/tests/main.cpp b/wifi/1.2/default/tests/main.cpp new file mode 100644 index 0000000000..9aac837242 --- /dev/null +++ b/wifi/1.2/default/tests/main.cpp @@ -0,0 +1,28 @@ +/* + * 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 +#include + +#include + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + ::testing::InitGoogleMock(&argc, argv); + // Force ourselves to always log to stderr + android::base::InitLogging(argv, android::base::StderrLogger); + return RUN_ALL_TESTS(); +} diff --git a/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp new file mode 100644 index 0000000000..8d0b1921c2 --- /dev/null +++ b/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp @@ -0,0 +1,35 @@ +/* + * 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 + +#include "mock_wifi_feature_flags.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace feature_flags { + +MockWifiFeatureFlags::MockWifiFeatureFlags() {} + +} // namespace feature_flags +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.2/default/tests/mock_wifi_feature_flags.h b/wifi/1.2/default/tests/mock_wifi_feature_flags.h new file mode 100644 index 0000000000..85927f96f2 --- /dev/null +++ b/wifi/1.2/default/tests/mock_wifi_feature_flags.h @@ -0,0 +1,45 @@ +/* + * 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 MOCK_WIFI_FEATURE_FLAGS_H_ +#define MOCK_WIFI_FEATURE_FLAGS_H_ + +#include + +#include "wifi_feature_flags.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace feature_flags { + +class MockWifiFeatureFlags : public WifiFeatureFlags { + public: + MockWifiFeatureFlags(); + + MOCK_METHOD0(isAwareSupported, bool()); +}; + +} // namespace feature_flags +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android + +#endif // MOCK_WIFI_FEATURE_FLAGS_H_ diff --git a/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp new file mode 100644 index 0000000000..8381ddef4e --- /dev/null +++ b/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp @@ -0,0 +1,37 @@ +/* + * 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 +#include +#include + +#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38 +#include "mock_wifi_legacy_hal.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace legacy_hal { + +MockWifiLegacyHal::MockWifiLegacyHal() : WifiLegacyHal() {} +} // namespace legacy_hal +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.2/default/tests/mock_wifi_legacy_hal.h b/wifi/1.2/default/tests/mock_wifi_legacy_hal.h new file mode 100644 index 0000000000..8e1696e10c --- /dev/null +++ b/wifi/1.2/default/tests/mock_wifi_legacy_hal.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MOCK_WIFI_LEGACY_HAL_H_ +#define MOCK_WIFI_LEGACY_HAL_H_ + +#include + +#include "wifi_legacy_hal.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace legacy_hal { + +class MockWifiLegacyHal : public WifiLegacyHal { + public: + MockWifiLegacyHal(); + MOCK_METHOD0(initialize, wifi_error()); + MOCK_METHOD0(start, wifi_error()); + MOCK_METHOD2(stop, wifi_error(std::unique_lock*, + const std::function&)); + MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool)); + MOCK_METHOD2(nanRegisterCallbackHandlers, + wifi_error(const std::string&, const NanCallbackHandlers&)); + MOCK_METHOD2(nanDisableRequest, + wifi_error(const std::string&, transaction_id)); + MOCK_METHOD3(nanDataInterfaceDelete, + wifi_error(const std::string&, transaction_id, + const std::string&)); +}; +} // namespace legacy_hal +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android + +#endif // MOCK_WIFI_LEGACY_HAL_H_ diff --git a/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp new file mode 100644 index 0000000000..461a581a22 --- /dev/null +++ b/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp @@ -0,0 +1,37 @@ +/* + * 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 +#include +#include + +#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38 +#include "mock_wifi_mode_controller.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace mode_controller { + +MockWifiModeController::MockWifiModeController() : WifiModeController() {} +} // namespace mode_controller +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.2/default/tests/mock_wifi_mode_controller.h b/wifi/1.2/default/tests/mock_wifi_mode_controller.h new file mode 100644 index 0000000000..73ff5f095c --- /dev/null +++ b/wifi/1.2/default/tests/mock_wifi_mode_controller.h @@ -0,0 +1,45 @@ +/* + * 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 MOCK_WIFI_MODE_CONTROLLER_H_ +#define MOCK_WIFI_MODE_CONTROLLER_H_ + +#include + +#include "wifi_mode_controller.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace mode_controller { + +class MockWifiModeController : public WifiModeController { + public: + MockWifiModeController(); + MOCK_METHOD1(changeFirmwareMode, bool(IfaceType)); + MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType)); + MOCK_METHOD0(deinitialize, bool()); +}; +} // namespace mode_controller +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android + +#endif // MOCK_WIFI_MODE_CONTROLLER_H_ diff --git a/wifi/1.2/default/tests/runtests.sh b/wifi/1.2/default/tests/runtests.sh new file mode 100755 index 0000000000..a1bbc936e7 --- /dev/null +++ b/wifi/1.2/default/tests/runtests.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +# 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. + +if [ -z $ANDROID_BUILD_TOP ]; then + echo "You need to source and lunch before you can use this script" + exit 1 +fi + +echo "Running tests" +set -e # fail early + +#NOTE We can't actually run these commands, since they rely on functions added by +#build / envsetup.sh to the bash shell environment. +echo "+ mmma -j32 $ANDROID_BUILD_TOP/" +make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk \ + MODULES-IN-hardware-interfaces-wifi-1.2-default + +set -x # print commands + +adb wait-for-device +adb root +adb wait-for-device + +#'disable-verity' will appear in 'adb remount' output if +#dm - verity is enabled and needs to be disabled. +if adb remount | grep 'disable-verity'; then + adb disable-verity + adb reboot + adb wait-for-device + adb root + adb wait-for-device + adb remount +fi + +adb sync + +adb shell /data/nativetest64/android.hardware.wifi@1.0-service-tests/android.hardware.wifi@1.0-service-tests diff --git a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp new file mode 100644 index 0000000000..5d217d6642 --- /dev/null +++ b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp @@ -0,0 +1,73 @@ +/* + * 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 +#include +#include + +#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38 +#include "wifi_chip.h" + +#include "mock_wifi_feature_flags.h" +#include "mock_wifi_legacy_hal.h" +#include "mock_wifi_mode_controller.h" + +using testing::NiceMock; +using testing::Return; +using testing::Test; + +namespace {} // namespace + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { + +class WifiChipTest : public Test { + protected: + void setupV1IfaceCombination() { + EXPECT_CALL(*feature_flags_, isAwareSupported()) + .WillRepeatedly(testing::Return(false)); + } + + void setupV2IfaceCombination() { + EXPECT_CALL(*feature_flags_, isAwareSupported()) + .WillRepeatedly(testing::Return(true)); + } + + sp chip_; + + ChipId chip_id_ = 5; + std::shared_ptr> legacy_hal_{ + new NiceMock}; + std::shared_ptr> + mode_controller_{new NiceMock}; + std::shared_ptr> + feature_flags_{new NiceMock}; + + public: + void SetUp() override { + chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_, + feature_flags_); + } +}; + +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.2/default/wifi.cpp b/wifi/1.2/default/wifi.cpp index a2d8f9f1ef..5a8b66ec53 100644 --- a/wifi/1.2/default/wifi.cpp +++ b/wifi/1.2/default/wifi.cpp @@ -33,9 +33,13 @@ namespace implementation { using hidl_return_util::validateAndCall; using hidl_return_util::validateAndCallWithLock; -Wifi::Wifi() - : legacy_hal_(new legacy_hal::WifiLegacyHal()), - mode_controller_(new mode_controller::WifiModeController()), +Wifi::Wifi( + const std::shared_ptr legacy_hal, + const std::shared_ptr mode_controller, + const std::shared_ptr feature_flags) + : legacy_hal_(legacy_hal), + mode_controller_(mode_controller), + feature_flags_(feature_flags), run_state_(RunState::STOPPED) {} bool Wifi::isValid() { @@ -91,7 +95,8 @@ WifiStatus Wifi::startInternal() { WifiStatus wifi_status = initializeLegacyHal(); if (wifi_status.code == WifiStatusCode::SUCCESS) { // Create the chip instance once the HAL is started. - chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_); + chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_, + feature_flags_); run_state_ = RunState::STARTED; for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onStart().isOk()) { diff --git a/wifi/1.2/default/wifi.h b/wifi/1.2/default/wifi.h index 114d7745a8..d76e9c93e0 100644 --- a/wifi/1.2/default/wifi.h +++ b/wifi/1.2/default/wifi.h @@ -25,6 +25,7 @@ #include "hidl_callback_util.h" #include "wifi_chip.h" +#include "wifi_feature_flags.h" #include "wifi_legacy_hal.h" #include "wifi_mode_controller.h" @@ -39,7 +40,10 @@ namespace implementation { */ class Wifi : public V1_2::IWifi { public: - Wifi(); + Wifi(const std::shared_ptr legacy_hal, + const std::shared_ptr + mode_controller, + const std::shared_ptr feature_flags); bool isValid(); @@ -72,6 +76,7 @@ class Wifi : public V1_2::IWifi { // and shared with all the child HIDL interface objects. std::shared_ptr legacy_hal_; std::shared_ptr mode_controller_; + std::shared_ptr feature_flags_; RunState run_state_; sp chip_; hidl_callback_util::HidlCallbackHandler diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp index 49cf8882b1..c4956e016f 100644 --- a/wifi/1.2/default/wifi_chip.cpp +++ b/wifi/1.2/default/wifi_chip.cpp @@ -20,7 +20,6 @@ #include "hidl_return_util.h" #include "hidl_struct_util.h" #include "wifi_chip.h" -#include "wifi_feature_flags.h" #include "wifi_status_util.h" namespace { @@ -103,10 +102,12 @@ using hidl_return_util::validateAndCallWithLock; WifiChip::WifiChip( ChipId chip_id, const std::weak_ptr legacy_hal, - const std::weak_ptr mode_controller) + const std::weak_ptr mode_controller, + const std::weak_ptr feature_flags) : chip_id_(chip_id), legacy_hal_(legacy_hal), mode_controller_(mode_controller), + feature_flags_(feature_flags), is_valid_(true), current_mode_id_(kInvalidModeId), debug_ring_buffer_cb_registered_(false) {} @@ -404,7 +405,7 @@ WifiChip::getAvailableModesInternal() { const IWifiChip::ChipIfaceCombinationLimit sta_chip_iface_combination_limit_1 = {{IfaceType::STA}, 1}; IWifiChip::ChipIfaceCombinationLimit sta_chip_iface_combination_limit_2; - if (WifiFeatureFlags::wifiHidlFeatureAware) { + if (feature_flags_.lock()->isAwareSupported()) { sta_chip_iface_combination_limit_2 = {{IfaceType::P2P, IfaceType::NAN}, 1}; } else { @@ -572,7 +573,7 @@ WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) { std::pair> WifiChip::createNanIfaceInternal() { // Only 1 of NAN or P2P iface can be active at a time. - if (WifiFeatureFlags::wifiHidlFeatureAware) { + if (feature_flags_.lock()->isAwareSupported()) { if (current_mode_id_ != kStaChipModeId || !nan_ifaces_.empty() || !p2p_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; diff --git a/wifi/1.2/default/wifi_chip.h b/wifi/1.2/default/wifi_chip.h index 4830af9f72..b843cf3af2 100644 --- a/wifi/1.2/default/wifi_chip.h +++ b/wifi/1.2/default/wifi_chip.h @@ -24,6 +24,7 @@ #include "hidl_callback_util.h" #include "wifi_ap_iface.h" +#include "wifi_feature_flags.h" #include "wifi_legacy_hal.h" #include "wifi_mode_controller.h" #include "wifi_nan_iface.h" @@ -45,10 +46,12 @@ using namespace android::hardware::wifi::V1_0; */ class WifiChip : public V1_1::IWifiChip { public: - WifiChip(ChipId chip_id, - const std::weak_ptr legacy_hal, - const std::weak_ptr - mode_controller); + WifiChip( + ChipId chip_id, + const std::weak_ptr legacy_hal, + const std::weak_ptr + mode_controller, + const std::weak_ptr feature_flags); // HIDL does not provide a built-in mechanism to let the server invalidate // a HIDL interface object after creation. If any client process holds onto // a reference to the object in their context, any method calls on that @@ -193,6 +196,7 @@ class WifiChip : public V1_1::IWifiChip { ChipId chip_id_; std::weak_ptr legacy_hal_; std::weak_ptr mode_controller_; + std::weak_ptr feature_flags_; std::vector> ap_ifaces_; std::vector> nan_ifaces_; std::vector> p2p_ifaces_; diff --git a/wifi/1.2/default/wifi_feature_flags.cpp b/wifi/1.2/default/wifi_feature_flags.cpp new file mode 100644 index 0000000000..aba31fb4b8 --- /dev/null +++ b/wifi/1.2/default/wifi_feature_flags.cpp @@ -0,0 +1,42 @@ +/* + * 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 "wifi_feature_flags.h" + +namespace { +#ifdef WIFI_HIDL_FEATURE_AWARE +static const bool wifiHidlFeatureAware = true; +#else +static const bool wifiHidlFeatureAware = false; +#endif // WIFI_HIDL_FEATURE_AWARE +} // namespace + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace feature_flags { + +WifiFeatureFlags::WifiFeatureFlags() {} +bool WifiFeatureFlags::isAwareSupported() { return wifiHidlFeatureAware; } + +} // namespace feature_flags +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.2/default/wifi_feature_flags.h b/wifi/1.2/default/wifi_feature_flags.h index da4ca37e9b..a31ac0f658 100644 --- a/wifi/1.2/default/wifi_feature_flags.h +++ b/wifi/1.2/default/wifi_feature_flags.h @@ -22,16 +22,17 @@ namespace hardware { namespace wifi { namespace V1_2 { namespace implementation { +namespace feature_flags { class WifiFeatureFlags { public: -#ifdef WIFI_HIDL_FEATURE_AWARE - static const bool wifiHidlFeatureAware = true; -#else - static const bool wifiHidlFeatureAware = false; -#endif // WIFI_HIDL_FEATURE_AWARE + WifiFeatureFlags(); + virtual ~WifiFeatureFlags() = default; + + virtual bool isAwareSupported(); }; +} // namespace feature_flags } // namespace implementation } // namespace V1_2 } // namespace wifi diff --git a/wifi/1.2/default/wifi_legacy_hal.cpp b/wifi/1.2/default/wifi_legacy_hal.cpp index 8289c674a8..3b056b0b43 100644 --- a/wifi/1.2/default/wifi_legacy_hal.cpp +++ b/wifi/1.2/default/wifi_legacy_hal.cpp @@ -446,7 +446,7 @@ std::pair WifiLegacyHal::getSupportedFeatureSet( const std::string& iface_name) { feature_set set; static_assert(sizeof(set) == sizeof(uint32_t), - "Some features can not be represented in output"); + "Some feature_flags can not be represented in output"); wifi_error status = global_func_table_.wifi_get_supported_feature_set( getIfaceHandle(iface_name), &set); return {status, static_cast(set)}; @@ -750,11 +750,11 @@ wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) { std::pair WifiLegacyHal::getLoggerSupportedFeatureSet( const std::string& iface_name) { - uint32_t supported_features; + uint32_t supported_feature_flags; wifi_error status = global_func_table_.wifi_get_logger_supported_feature_set( - getIfaceHandle(iface_name), &supported_features); - return {status, supported_features}; + getIfaceHandle(iface_name), &supported_feature_flags); + return {status, supported_feature_flags}; } wifi_error WifiLegacyHal::startPktFateMonitoring( diff --git a/wifi/1.2/default/wifi_legacy_hal.h b/wifi/1.2/default/wifi_legacy_hal.h index 193928b6b6..64a3f0ada1 100644 --- a/wifi/1.2/default/wifi_legacy_hal.h +++ b/wifi/1.2/default/wifi_legacy_hal.h @@ -141,15 +141,16 @@ using on_error_alert_callback = class WifiLegacyHal { public: WifiLegacyHal(); + virtual ~WifiLegacyHal() = default; // Initialize the legacy HAL function table. - wifi_error initialize(); + virtual wifi_error initialize(); // Start the legacy HAL and the event looper thread. - wifi_error start(); + virtual wifi_error start(); // Deinitialize the legacy HAL and wait for the event loop thread to exit // using a predefined timeout. - wifi_error stop(std::unique_lock* lock, - const std::function& on_complete_callback); + virtual wifi_error stop(std::unique_lock* lock, + const std::function& on_complete_callback); // Wrappers for all the functions in the legacy HAL function table. std::pair getDriverVersion( const std::string& iface_name); @@ -189,7 +190,7 @@ class WifiLegacyHal { wifi_error stopGscan(const std::string& iface_name, wifi_request_id id); std::pair> getValidFrequenciesForBand( const std::string& iface_name, wifi_band band); - wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on); + virtual wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on); // Link layer stats functions. wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug); wifi_error disableLinkLayerStats(const std::string& iface_name); @@ -275,12 +276,12 @@ class WifiLegacyHal { wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id, const wifi_lcr_information& info); // NAN functions. - wifi_error nanRegisterCallbackHandlers( + virtual wifi_error nanRegisterCallbackHandlers( const std::string& iface_name, const NanCallbackHandlers& callbacks); wifi_error nanEnableRequest(const std::string& iface_name, transaction_id id, const NanEnableRequest& msg); - wifi_error nanDisableRequest(const std::string& iface_name, - transaction_id id); + virtual wifi_error nanDisableRequest(const std::string& iface_name, + transaction_id id); wifi_error nanPublishRequest(const std::string& iface_name, transaction_id id, const NanPublishRequest& msg); @@ -311,9 +312,9 @@ class WifiLegacyHal { wifi_error nanDataInterfaceCreate(const std::string& iface_name, transaction_id id, const std::string& data_iface_name); - wifi_error nanDataInterfaceDelete(const std::string& iface_name, - transaction_id id, - const std::string& data_iface_name); + virtual wifi_error nanDataInterfaceDelete( + const std::string& iface_name, transaction_id id, + const std::string& data_iface_name); wifi_error nanDataRequestInitiator(const std::string& iface_name, transaction_id id, const NanDataPathInitiatorRequest& msg); diff --git a/wifi/1.2/default/wifi_mode_controller.h b/wifi/1.2/default/wifi_mode_controller.h index 839bf9eeaf..e54fa6e44a 100644 --- a/wifi/1.2/default/wifi_mode_controller.h +++ b/wifi/1.2/default/wifi_mode_controller.h @@ -37,15 +37,16 @@ using namespace android::hardware::wifi::V1_0; class WifiModeController { public: WifiModeController(); + virtual ~WifiModeController() = default; // Checks if a firmware mode change is necessary to support the specified // iface type operations. - bool isFirmwareModeChangeNeeded(IfaceType type); + virtual bool isFirmwareModeChangeNeeded(IfaceType type); // Change the firmware mode to support the specified iface type operations. - bool changeFirmwareMode(IfaceType type); + virtual bool changeFirmwareMode(IfaceType type); // Unload the driver. This should be invoked whenever |IWifi.stop()| is // invoked. - bool deinitialize(); + virtual bool deinitialize(); private: std::unique_ptr driver_tool_; From 3312801aa5f2f5fc01362b3a2cac4e481119d211 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 2 Nov 2017 10:58:27 -0700 Subject: [PATCH 3/6] wifi(implementation): Unit tests for V1 & V2 iface combos Unit tests for all the iface combos supported in V1 (2016 devices) & V2 (2017 devices). Bug: 68775880 Test: ./hardware/interfaces/wifi/1.2/default/tests/runtests.sh Change-Id: I1049176aabdf936d442d022b5915129010ce7387 --- wifi/1.2/default/Android.mk | 1 + wifi/1.2/default/tests/runtests.sh | 2 +- .../default/tests/wifi_chip_unit_tests.cpp | 290 +++++++++++++++++- 3 files changed, 287 insertions(+), 6 deletions(-) diff --git a/wifi/1.2/default/Android.mk b/wifi/1.2/default/Android.mk index 2205e4e0f0..120732029c 100644 --- a/wifi/1.2/default/Android.mk +++ b/wifi/1.2/default/Android.mk @@ -88,6 +88,7 @@ include $(BUILD_EXECUTABLE) ### include $(CLEAR_VARS) LOCAL_MODULE := android.hardware.wifi@1.0-service-tests +LOCAL_PROPRIETARY_MODULE := true LOCAL_SRC_FILES := \ tests/main.cpp \ tests/mock_wifi_feature_flags.cpp \ diff --git a/wifi/1.2/default/tests/runtests.sh b/wifi/1.2/default/tests/runtests.sh index a1bbc936e7..966a6a751c 100755 --- a/wifi/1.2/default/tests/runtests.sh +++ b/wifi/1.2/default/tests/runtests.sh @@ -47,4 +47,4 @@ fi adb sync -adb shell /data/nativetest64/android.hardware.wifi@1.0-service-tests/android.hardware.wifi@1.0-service-tests +adb shell /data/nativetest/vendor/android.hardware.wifi@1.0-service-tests/android.hardware.wifi@1.0-service-tests diff --git a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp index 5d217d6642..f78b852bd8 100644 --- a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp +++ b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp @@ -29,7 +29,11 @@ using testing::NiceMock; using testing::Return; using testing::Test; -namespace {} // namespace +namespace { +using android::hardware::wifi::V1_0::ChipId; + +constexpr ChipId kFakeChipId = 5; +} // namespace namespace android { namespace hardware { @@ -42,30 +46,306 @@ class WifiChipTest : public Test { void setupV1IfaceCombination() { EXPECT_CALL(*feature_flags_, isAwareSupported()) .WillRepeatedly(testing::Return(false)); + chip_->getAvailableModes( + [](const WifiStatus& status, + const std::vector& modes) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + // V1 has 2 modes of operation. + ASSERT_EQ(2u, modes.size()); + }); } void setupV2IfaceCombination() { EXPECT_CALL(*feature_flags_, isAwareSupported()) .WillRepeatedly(testing::Return(true)); + chip_->getAvailableModes( + [](const WifiStatus& status, + const std::vector& modes) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + // V2 has 2 modes of operation. + ASSERT_EQ(2u, modes.size()); + }); } - sp chip_; + void findModeAndConfigureForIfaceType(const IfaceType& type) { + // This should be aligned with kInvalidModeId in wifi_chip.cpp. + ChipModeId mode_id = UINT32_MAX; + chip_->getAvailableModes( + [&mode_id, &type](const WifiStatus& status, + const std::vector& modes) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + for (const auto& mode : modes) { + for (const auto& combination : mode.availableCombinations) { + for (const auto& limit : combination.limits) { + if (limit.types.end() != + std::find(limit.types.begin(), + limit.types.end(), type)) { + mode_id = mode.id; + } + } + } + } + }); + ASSERT_NE(UINT32_MAX, mode_id); - ChipId chip_id_ = 5; + chip_->configureChip(mode_id, [](const WifiStatus& status) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + }); + } + + // Returns an empty string on error. + std::string createIface(const IfaceType& type) { + std::string iface_name; + if (type == IfaceType::AP) { + chip_->createApIface([&iface_name](const WifiStatus& status, + const sp& iface) { + if (WifiStatusCode::SUCCESS == status.code) { + ASSERT_NE(iface.get(), nullptr); + iface->getName([&iface_name](const WifiStatus& status, + const hidl_string& name) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + iface_name = name.c_str(); + }); + } + }); + } else if (type == IfaceType::NAN) { + chip_->createNanIface( + [&iface_name](const WifiStatus& status, + const sp& iface) { + if (WifiStatusCode::SUCCESS == status.code) { + ASSERT_NE(iface.get(), nullptr); + iface->getName([&iface_name](const WifiStatus& status, + const hidl_string& name) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + iface_name = name.c_str(); + }); + } + }); + } else if (type == IfaceType::P2P) { + chip_->createP2pIface( + [&iface_name](const WifiStatus& status, + const sp& iface) { + if (WifiStatusCode::SUCCESS == status.code) { + ASSERT_NE(iface.get(), nullptr); + iface->getName([&iface_name](const WifiStatus& status, + const hidl_string& name) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + iface_name = name.c_str(); + }); + } + }); + } else if (type == IfaceType::STA) { + chip_->createStaIface( + [&iface_name](const WifiStatus& status, + const sp& iface) { + if (WifiStatusCode::SUCCESS == status.code) { + ASSERT_NE(iface.get(), nullptr); + iface->getName([&iface_name](const WifiStatus& status, + const hidl_string& name) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + iface_name = name.c_str(); + }); + } + }); + } + return iface_name; + } + + void removeIface(const IfaceType& type, const std::string& iface_name) { + if (type == IfaceType::AP) { + chip_->removeApIface(iface_name, [](const WifiStatus& status) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + }); + } else if (type == IfaceType::NAN) { + chip_->removeNanIface(iface_name, [](const WifiStatus& status) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + }); + } else if (type == IfaceType::P2P) { + chip_->removeP2pIface(iface_name, [](const WifiStatus& status) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + }); + } else if (type == IfaceType::STA) { + chip_->removeStaIface(iface_name, [](const WifiStatus& status) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + }); + } + } + + public: + void SetUp() override { + chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_, + feature_flags_); + + EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_)) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL(*legacy_hal_, start()) + .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS)); + } + + private: + sp chip_; + ChipId chip_id_ = kFakeChipId; std::shared_ptr> legacy_hal_{ new NiceMock}; std::shared_ptr> mode_controller_{new NiceMock}; std::shared_ptr> feature_flags_{new NiceMock}; +}; +////////// V1 Iface Combinations //////////// +// Mode 1 - STA + P2P +// Mode 2 - AP +class WifiChipV1IfaceCombinationTest : public WifiChipTest { public: void SetUp() override { - chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_, - feature_flags_); + WifiChipTest::SetUp(); + setupV1IfaceCombination(); } }; +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); +} + +////////// V2 Iface Combinations //////////// +// Mode 1 - STA + P2P/NAN +// Mode 2 - AP +class WifiChipV2IfaceCombinationTest : public WifiChipTest { + public: + void SetUp() override { + WifiChipTest::SetUp(); + setupV2IfaceCombination(); + } +}; + +TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateAp_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateStaNan_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateStaP2PNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2IfaceCombinationTest, + StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto p2p_iface_name = createIface(IfaceType::P2P); + ASSERT_FALSE(p2p_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); + + // After removing P2P iface, NAN iface creation should succeed. + removeIface(IfaceType::P2P, p2p_iface_name); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2IfaceCombinationTest, + StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto nan_iface_name = createIface(IfaceType::NAN); + ASSERT_FALSE(nan_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::P2P).empty()); + + // After removing NAN iface, P2P iface creation should succeed. + removeIface(IfaceType::NAN, nan_iface_name); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV2IfaceCombinationTest, ApMode_CreateSta_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2IfaceCombinationTest, ApMode_CreateNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); +} + } // namespace implementation } // namespace V1_2 } // namespace wifi From cc338202ef43a3551b1e5c96bd6756134978df32 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 2 Nov 2017 13:54:09 -0700 Subject: [PATCH 4/6] wifi(implementation): Add iface combo for 2018 Changes in the CL: a) Added iface combo for 2018 using a new feature flag. b) Added a generic algorithm to determine if an iface can be created or not based on the iface combos supported. This is needed because we now have to support 3 different combos (2016, 2017, 2018) in the HAL. The current iface creation logic is hard to adapt to these 3 varying combos. Bug: 65671875 Bug: 69863101 Test: ./hardware/interfaces/wifi/1.2/default/tests/runtests.sh Change-Id: Iff8737843abee3d03567930e9faba775eaa82e07 --- wifi/1.2/default/Android.mk | 3 + .../default/tests/mock_wifi_feature_flags.h | 1 + .../default/tests/wifi_chip_unit_tests.cpp | 232 +++++++++++++-- wifi/1.2/default/wifi_chip.cpp | 271 ++++++++++++++---- wifi/1.2/default/wifi_chip.h | 13 + wifi/1.2/default/wifi_feature_flags.cpp | 8 + wifi/1.2/default/wifi_feature_flags.h | 1 + 7 files changed, 439 insertions(+), 90 deletions(-) diff --git a/wifi/1.2/default/Android.mk b/wifi/1.2/default/Android.mk index 120732029c..95414bc743 100644 --- a/wifi/1.2/default/Android.mk +++ b/wifi/1.2/default/Android.mk @@ -24,6 +24,9 @@ LOCAL_CPPFLAGS := -Wall -Werror -Wextra ifdef WIFI_HIDL_FEATURE_AWARE LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_AWARE endif +ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE +LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DUAL_INTERFACE +endif LOCAL_SRC_FILES := \ hidl_struct_util.cpp \ hidl_sync_util.cpp \ diff --git a/wifi/1.2/default/tests/mock_wifi_feature_flags.h b/wifi/1.2/default/tests/mock_wifi_feature_flags.h index 85927f96f2..8cf1d4b258 100644 --- a/wifi/1.2/default/tests/mock_wifi_feature_flags.h +++ b/wifi/1.2/default/tests/mock_wifi_feature_flags.h @@ -33,6 +33,7 @@ class MockWifiFeatureFlags : public WifiFeatureFlags { MockWifiFeatureFlags(); MOCK_METHOD0(isAwareSupported, bool()); + MOCK_METHOD0(isDualInterfaceSupported, bool()); }; } // namespace feature_flags diff --git a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp index f78b852bd8..e3c51fa452 100644 --- a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp +++ b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp @@ -46,24 +46,31 @@ class WifiChipTest : public Test { void setupV1IfaceCombination() { EXPECT_CALL(*feature_flags_, isAwareSupported()) .WillRepeatedly(testing::Return(false)); - chip_->getAvailableModes( - [](const WifiStatus& status, - const std::vector& modes) { - ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); - // V1 has 2 modes of operation. - ASSERT_EQ(2u, modes.size()); - }); + EXPECT_CALL(*feature_flags_, isDualInterfaceSupported()) + .WillRepeatedly(testing::Return(false)); } - void setupV2IfaceCombination() { + void setupV1_AwareIfaceCombination() { EXPECT_CALL(*feature_flags_, isAwareSupported()) .WillRepeatedly(testing::Return(true)); + EXPECT_CALL(*feature_flags_, isDualInterfaceSupported()) + .WillRepeatedly(testing::Return(false)); + } + + void setupV2_AwareIfaceCombination() { + EXPECT_CALL(*feature_flags_, isAwareSupported()) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL(*feature_flags_, isDualInterfaceSupported()) + .WillRepeatedly(testing::Return(true)); + } + + void assertNumberOfModes(uint32_t num_modes) { chip_->getAvailableModes( - [](const WifiStatus& status, - const std::vector& modes) { + [num_modes](const WifiStatus& status, + const std::vector& modes) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); - // V2 has 2 modes of operation. - ASSERT_EQ(2u, modes.size()); + // V2_Aware has 1 mode of operation. + ASSERT_EQ(num_modes, modes.size()); }); } @@ -199,8 +206,10 @@ class WifiChipTest : public Test { class WifiChipV1IfaceCombinationTest : public WifiChipTest { public: void SetUp() override { - WifiChipTest::SetUp(); setupV1IfaceCombination(); + WifiChipTest::SetUp(); + // V1 has 2 modes of operation. + assertNumberOfModes(2u); } }; @@ -250,57 +259,62 @@ TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) { ASSERT_TRUE(createIface(IfaceType::NAN).empty()); } -////////// V2 Iface Combinations //////////// +////////// V1 + Aware Iface Combinations //////////// // Mode 1 - STA + P2P/NAN // Mode 2 - AP -class WifiChipV2IfaceCombinationTest : public WifiChipTest { +class WifiChipV1_AwareIfaceCombinationTest : public WifiChipTest { public: void SetUp() override { + setupV1_AwareIfaceCombination(); WifiChipTest::SetUp(); - setupV2IfaceCombination(); + // V1_Aware has 2 modes of operation. + assertNumberOfModes(2u); } }; -TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) { +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) { findModeAndConfigureForIfaceType(IfaceType::STA); ASSERT_FALSE(createIface(IfaceType::STA).empty()); } -TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) { +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) { findModeAndConfigureForIfaceType(IfaceType::STA); ASSERT_FALSE(createIface(IfaceType::P2P).empty()); } -TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) { +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) { findModeAndConfigureForIfaceType(IfaceType::STA); ASSERT_FALSE(createIface(IfaceType::NAN).empty()); } -TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateAp_ShouldFail) { +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) { findModeAndConfigureForIfaceType(IfaceType::STA); ASSERT_TRUE(createIface(IfaceType::AP).empty()); } -TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) { +TEST_F(WifiChipV1_AwareIfaceCombinationTest, + StaMode_CreateStaP2p_ShouldSucceed) { findModeAndConfigureForIfaceType(IfaceType::STA); ASSERT_FALSE(createIface(IfaceType::STA).empty()); ASSERT_FALSE(createIface(IfaceType::P2P).empty()); } -TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateStaNan_ShouldSucceed) { +TEST_F(WifiChipV1_AwareIfaceCombinationTest, + StaMode_CreateStaNan_ShouldSucceed) { findModeAndConfigureForIfaceType(IfaceType::STA); ASSERT_FALSE(createIface(IfaceType::STA).empty()); ASSERT_FALSE(createIface(IfaceType::NAN).empty()); } -TEST_F(WifiChipV2IfaceCombinationTest, StaMode_CreateStaP2PNan_ShouldFail) { +TEST_F(WifiChipV1_AwareIfaceCombinationTest, + StaMode_CreateStaP2PNan_ShouldFail) { findModeAndConfigureForIfaceType(IfaceType::STA); ASSERT_FALSE(createIface(IfaceType::STA).empty()); ASSERT_FALSE(createIface(IfaceType::P2P).empty()); ASSERT_TRUE(createIface(IfaceType::NAN).empty()); } -TEST_F(WifiChipV2IfaceCombinationTest, +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) { findModeAndConfigureForIfaceType(IfaceType::STA); ASSERT_FALSE(createIface(IfaceType::STA).empty()); @@ -313,7 +327,7 @@ TEST_F(WifiChipV2IfaceCombinationTest, ASSERT_FALSE(createIface(IfaceType::NAN).empty()); } -TEST_F(WifiChipV2IfaceCombinationTest, +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) { findModeAndConfigureForIfaceType(IfaceType::STA); ASSERT_FALSE(createIface(IfaceType::STA).empty()); @@ -326,26 +340,186 @@ TEST_F(WifiChipV2IfaceCombinationTest, ASSERT_FALSE(createIface(IfaceType::P2P).empty()); } -TEST_F(WifiChipV2IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) { +TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) { findModeAndConfigureForIfaceType(IfaceType::AP); ASSERT_FALSE(createIface(IfaceType::AP).empty()); } -TEST_F(WifiChipV2IfaceCombinationTest, ApMode_CreateSta_ShouldFail) { +TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) { findModeAndConfigureForIfaceType(IfaceType::AP); ASSERT_TRUE(createIface(IfaceType::STA).empty()); } -TEST_F(WifiChipV2IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) { +TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) { findModeAndConfigureForIfaceType(IfaceType::AP); ASSERT_TRUE(createIface(IfaceType::STA).empty()); } -TEST_F(WifiChipV2IfaceCombinationTest, ApMode_CreateNan_ShouldFail) { +TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) { findModeAndConfigureForIfaceType(IfaceType::AP); ASSERT_TRUE(createIface(IfaceType::NAN).empty()); } +////////// V2 + Aware Iface Combinations //////////// +// Mode 1 - STA + STA/AP +// - STA + P2P/NAN +class WifiChipV2_AwareIfaceCombinationTest : public WifiChipTest { + public: + void SetUp() override { + setupV2_AwareIfaceCombination(); + WifiChipTest::SetUp(); + // V2_Aware has 1 mode of operation. + assertNumberOfModes(1u); + } +}; + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaStaAp_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + CreateStaAp_AfterStaRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto sta_iface_name = createIface(IfaceType::STA); + ASSERT_FALSE(sta_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); + + // After removing STA iface, AP iface creation should succeed. + removeIface(IfaceType::STA, sta_iface_name); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + CreateStaSta_AfterApRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto ap_iface_name = createIface(IfaceType::AP); + ASSERT_FALSE(ap_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); + + // After removing AP iface, STA iface creation should succeed. + removeIface(IfaceType::AP, ap_iface_name); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + CreateStaNan_AfterP2pRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto p2p_iface_name = createIface(IfaceType::P2P); + ASSERT_FALSE(p2p_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); + + // After removing P2P iface, NAN iface creation should succeed. + removeIface(IfaceType::P2P, p2p_iface_name); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + CreateStaP2p_AfterNanRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto nan_iface_name = createIface(IfaceType::NAN); + ASSERT_FALSE(nan_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::P2P).empty()); + + // After removing NAN iface, P2P iface creation should succeed. + removeIface(IfaceType::NAN, nan_iface_name); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); + ASSERT_TRUE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto p2p_iface_name = createIface(IfaceType::P2P); + ASSERT_FALSE(p2p_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); + + // After removing P2P iface, NAN iface creation should succeed. + removeIface(IfaceType::P2P, p2p_iface_name); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto nan_iface_name = createIface(IfaceType::NAN); + ASSERT_FALSE(nan_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::P2P).empty()); + + // After removing NAN iface, P2P iface creation should succeed. + removeIface(IfaceType::NAN, nan_iface_name); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} } // namespace implementation } // namespace V1_2 } // namespace wifi diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp index c4956e016f..d7be38ffe1 100644 --- a/wifi/1.2/default/wifi_chip.cpp +++ b/wifi/1.2/default/wifi_chip.cpp @@ -30,9 +30,14 @@ using android::hardware::wifi::V1_0::IfaceType; using android::hardware::wifi::V1_0::IWifiChip; using android::sp; -constexpr ChipModeId kStaChipModeId = 0; -constexpr ChipModeId kApChipModeId = 1; constexpr ChipModeId kInvalidModeId = UINT32_MAX; +// These mode ID's should be unique (even across combo versions). Refer to +// handleChipConfiguration() for it's usage. +// Mode ID's for V1 +constexpr ChipModeId kV1StaChipModeId = 0; +constexpr ChipModeId kV1ApChipModeId = 1; +// Mode ID for V2 +constexpr ChipModeId kV2ChipModeId = 2; template void invalidateAndClear(std::vector>& ifaces, sp iface) { @@ -110,7 +115,9 @@ WifiChip::WifiChip( feature_flags_(feature_flags), is_valid_(true), current_mode_id_(kInvalidModeId), - debug_ring_buffer_cb_registered_(false) {} + debug_ring_buffer_cb_registered_(false) { + populateModes(); +} void WifiChip::invalidate() { invalidateAndRemoveAllIfaces(); @@ -394,43 +401,13 @@ std::pair WifiChip::getCapabilitiesInternal() { std::pair> WifiChip::getAvailableModesInternal() { - // The chip combination supported for current devices is fixed for now with - // 2 separate modes of operation: - // Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN iface operations - // concurrently [NAN conditional on wifiHidlFeatureAware] - // Mode 2 (AP mode): Will support 1 AP iface operations. - // TODO (b/32997844): Read this from some device specific flags in the - // makefile. - // STA mode iface combinations. - const IWifiChip::ChipIfaceCombinationLimit - sta_chip_iface_combination_limit_1 = {{IfaceType::STA}, 1}; - IWifiChip::ChipIfaceCombinationLimit sta_chip_iface_combination_limit_2; - if (feature_flags_.lock()->isAwareSupported()) { - sta_chip_iface_combination_limit_2 = {{IfaceType::P2P, IfaceType::NAN}, - 1}; - } else { - sta_chip_iface_combination_limit_2 = {{IfaceType::P2P}, 1}; - } - const IWifiChip::ChipIfaceCombination sta_chip_iface_combination = { - {sta_chip_iface_combination_limit_1, - sta_chip_iface_combination_limit_2}}; - const IWifiChip::ChipMode sta_chip_mode = {kStaChipModeId, - {sta_chip_iface_combination}}; - // AP mode iface combinations. - const IWifiChip::ChipIfaceCombinationLimit ap_chip_iface_combination_limit = - {{IfaceType::AP}, 1}; - const IWifiChip::ChipIfaceCombination ap_chip_iface_combination = { - {ap_chip_iface_combination_limit}}; - const IWifiChip::ChipMode ap_chip_mode = {kApChipModeId, - {ap_chip_iface_combination}}; - return {createWifiStatus(WifiStatusCode::SUCCESS), - {sta_chip_mode, ap_chip_mode}}; + return {createWifiStatus(WifiStatusCode::SUCCESS), modes_}; } WifiStatus WifiChip::configureChipInternal( /* NONNULL */ std::unique_lock* lock, ChipModeId mode_id) { - if (mode_id != kStaChipModeId && mode_id != kApChipModeId) { + if (!isValidModeId(mode_id)) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } if (mode_id == current_mode_id_) { @@ -458,7 +435,7 @@ WifiStatus WifiChip::configureChipInternal( } std::pair WifiChip::getModeInternal() { - if (current_mode_id_ == kInvalidModeId) { + if (!isValidModeId(current_mode_id_)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), current_mode_id_}; } @@ -526,7 +503,7 @@ WifiChip::requestFirmwareDebugDumpInternal() { } std::pair> WifiChip::createApIfaceInternal() { - if (current_mode_id_ != kApChipModeId || !ap_ifaces_.empty()) { + if (!canCurrentModeSupportIfaceOfType(IfaceType::AP)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } std::string ifname = getWlan0IfaceName(); @@ -572,24 +549,18 @@ WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) { } std::pair> WifiChip::createNanIfaceInternal() { - // Only 1 of NAN or P2P iface can be active at a time. - if (feature_flags_.lock()->isAwareSupported()) { - if (current_mode_id_ != kStaChipModeId || !nan_ifaces_.empty() || - !p2p_ifaces_.empty()) { - return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; - } - std::string ifname = getWlan0IfaceName(); - sp iface = new WifiNanIface(ifname, legacy_hal_); - nan_ifaces_.push_back(iface); - for (const auto& callback : event_cb_handler_.getCallbacks()) { - if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) { - LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; - } - } - return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; - } else { + if (!canCurrentModeSupportIfaceOfType(IfaceType::NAN)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } + std::string ifname = getWlan0IfaceName(); + sp iface = new WifiNanIface(ifname, legacy_hal_); + nan_ifaces_.push_back(iface); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) { + LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; + } + } + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } std::pair> @@ -624,9 +595,7 @@ WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) { } std::pair> WifiChip::createP2pIfaceInternal() { - // Only 1 of NAN or P2P iface can be active at a time. - if (current_mode_id_ != kStaChipModeId || !p2p_ifaces_.empty() || - !nan_ifaces_.empty()) { + if (!canCurrentModeSupportIfaceOfType(IfaceType::P2P)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } std::string ifname = getP2pIfaceName(); @@ -672,7 +641,7 @@ WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) { } std::pair> WifiChip::createStaIfaceInternal() { - if (current_mode_id_ != kStaChipModeId || !sta_ifaces_.empty()) { + if (!canCurrentModeSupportIfaceOfType(IfaceType::STA)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } std::string ifname = getWlan0IfaceName(); @@ -842,7 +811,7 @@ WifiStatus WifiChip::handleChipConfiguration( ChipModeId mode_id) { // If the chip is already configured in a different mode, stop // the legacy HAL and then start it after firmware mode change. - if (current_mode_id_ != kInvalidModeId) { + if (isValidModeId(current_mode_id_)) { LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_ << " to mode " << mode_id; invalidateAndRemoveAllIfaces(); @@ -854,10 +823,11 @@ WifiStatus WifiChip::handleChipConfiguration( return createWifiStatusFromLegacyError(legacy_status); } } - bool success; - if (mode_id == kStaChipModeId) { + // Firmware mode change not needed for V2 devices. + bool success = true; + if (mode_id == kV1StaChipModeId) { success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA); - } else { + } else if (mode_id == kV1ApChipModeId) { success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP); } if (!success) { @@ -912,6 +882,185 @@ WifiStatus WifiChip::registerDebugRingBufferCallback() { return createWifiStatusFromLegacyError(legacy_status); } +void WifiChip::populateModes() { + // The chip combination supported for current devices is fixed. + // They can be one of the following based on device features: + // a) 2 separate modes of operation with 1 interface combination each: + // Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN(optional) + // concurrent iface operations. + // Mode 2 (AP mode): Will support 1 AP iface operation. + // + // b) 1 mode of operation with 2 interface combinations + // (conditional on isDualInterfaceSupported()): + // Interface Combination 1: Will support 1 STA and 1 P2P or NAN(optional) + // concurrent iface operations. + // Interface Combination 2: Will support 1 STA and 1 STA or AP concurrent + // iface operations. + // If Aware is enabled (conditional on isAwareSupported()), the iface + // combination will be modified to support either P2P or NAN in place of + // just P2P. + if (feature_flags_.lock()->isDualInterfaceSupported()) { + // V2 Iface combinations for Mode Id = 2. + const IWifiChip::ChipIfaceCombinationLimit + chip_iface_combination_limit_1 = {{IfaceType::STA}, 1}; + const IWifiChip::ChipIfaceCombinationLimit + chip_iface_combination_limit_2 = {{IfaceType::STA, IfaceType::AP}, + 1}; + IWifiChip::ChipIfaceCombinationLimit chip_iface_combination_limit_3; + if (feature_flags_.lock()->isAwareSupported()) { + chip_iface_combination_limit_3 = {{IfaceType::P2P, IfaceType::NAN}, + 1}; + } else { + chip_iface_combination_limit_3 = {{IfaceType::P2P}, 1}; + } + const IWifiChip::ChipIfaceCombination chip_iface_combination_1 = { + {chip_iface_combination_limit_1, chip_iface_combination_limit_2}}; + const IWifiChip::ChipIfaceCombination chip_iface_combination_2 = { + {chip_iface_combination_limit_1, chip_iface_combination_limit_3}}; + const IWifiChip::ChipMode chip_mode = { + kV2ChipModeId, + {chip_iface_combination_1, chip_iface_combination_2}}; + modes_ = {chip_mode}; + } else { + // V1 Iface combinations for Mode Id = 0. (STA Mode) + const IWifiChip::ChipIfaceCombinationLimit + sta_chip_iface_combination_limit_1 = {{IfaceType::STA}, 1}; + IWifiChip::ChipIfaceCombinationLimit sta_chip_iface_combination_limit_2; + if (feature_flags_.lock()->isAwareSupported()) { + sta_chip_iface_combination_limit_2 = { + {IfaceType::P2P, IfaceType::NAN}, 1}; + } else { + sta_chip_iface_combination_limit_2 = {{IfaceType::P2P}, 1}; + } + const IWifiChip::ChipIfaceCombination sta_chip_iface_combination = { + {sta_chip_iface_combination_limit_1, + sta_chip_iface_combination_limit_2}}; + const IWifiChip::ChipMode sta_chip_mode = { + kV1StaChipModeId, {sta_chip_iface_combination}}; + // Iface combinations for Mode Id = 1. (AP Mode) + const IWifiChip::ChipIfaceCombinationLimit + ap_chip_iface_combination_limit = {{IfaceType::AP}, 1}; + const IWifiChip::ChipIfaceCombination ap_chip_iface_combination = { + {ap_chip_iface_combination_limit}}; + const IWifiChip::ChipMode ap_chip_mode = {kV1ApChipModeId, + {ap_chip_iface_combination}}; + modes_ = {sta_chip_mode, ap_chip_mode}; + } +} + +std::vector +WifiChip::getCurrentModeIfaceCombinations() { + if (!isValidModeId(current_mode_id_)) { + LOG(ERROR) << "Chip not configured in a mode yet"; + return {}; + } + for (const auto& mode : modes_) { + if (mode.id == current_mode_id_) { + return mode.availableCombinations; + } + } + CHECK(0) << "Expected to find iface combinations for current mode!"; + return {}; +} + +// Returns a map indexed by IfaceType with the number of ifaces currently +// created of the corresponding type. +std::map WifiChip::getCurrentIfaceCombination() { + std::map iface_counts; + iface_counts[IfaceType::AP] = ap_ifaces_.size(); + iface_counts[IfaceType::NAN] = nan_ifaces_.size(); + iface_counts[IfaceType::P2P] = p2p_ifaces_.size(); + iface_counts[IfaceType::STA] = sta_ifaces_.size(); + return iface_counts; +} + +// This expands the provided iface combinations to a more parseable +// form. Returns a vector of available combinations possible with the number +// of ifaces of each type in the combination. +// This method is a port of HalDeviceManager.expandIfaceCombos() from framework. +std::vector> WifiChip::expandIfaceCombinations( + const IWifiChip::ChipIfaceCombination& combination) { + uint32_t num_expanded_combos = 1; + for (const auto& limit : combination.limits) { + for (uint32_t i = 0; i < limit.maxIfaces; i++) { + num_expanded_combos *= limit.types.size(); + } + } + + // Allocate the vector of expanded combos and reset all iface counts to 0 + // in each combo. + std::vector> expanded_combos; + expanded_combos.resize(num_expanded_combos); + for (auto& expanded_combo : expanded_combos) { + for (const auto type : + {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) { + expanded_combo[type] = 0; + } + } + uint32_t span = num_expanded_combos; + for (const auto& limit : combination.limits) { + for (uint32_t i = 0; i < limit.maxIfaces; i++) { + span /= limit.types.size(); + for (uint32_t k = 0; k < num_expanded_combos; ++k) { + const auto iface_type = + limit.types[(k / span) % limit.types.size()]; + expanded_combos[k][iface_type]++; + } + } + } + return expanded_combos; +} + +bool WifiChip::canExpandedIfaceCombinationSupportIfaceOfType( + const std::map& combo, IfaceType requested_type) { + const auto current_combo = getCurrentIfaceCombination(); + + // Check if we have space for 1 more iface of |type| in this combo + for (const auto type : + {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) { + size_t num_ifaces_needed = current_combo.at(type); + if (type == requested_type) { + num_ifaces_needed++; + } + size_t num_ifaces_allowed = combo.at(type); + if (num_ifaces_needed > num_ifaces_allowed) { + return false; + } + } + return true; +} + +// This method does the following: +// a) Enumerate all possible iface combos by expanding the current +// ChipIfaceCombination. +// b) Check if the requested iface type can be added to the current mode. +bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType type) { + if (!isValidModeId(current_mode_id_)) { + LOG(ERROR) << "Chip not configured in a mode yet"; + return false; + } + const auto combinations = getCurrentModeIfaceCombinations(); + for (const auto& combination : combinations) { + const auto expanded_combos = expandIfaceCombinations(combination); + for (const auto& expanded_combo : expanded_combos) { + if (canExpandedIfaceCombinationSupportIfaceOfType(expanded_combo, + type)) { + return true; + } + } + } + return false; +} + +bool WifiChip::isValidModeId(ChipModeId mode_id) { + for (const auto& mode : modes_) { + if (mode.id == mode_id) { + return true; + } + } + return false; +} + } // namespace implementation } // namespace V1_2 } // namespace wifi diff --git a/wifi/1.2/default/wifi_chip.h b/wifi/1.2/default/wifi_chip.h index b843cf3af2..472a694f0e 100644 --- a/wifi/1.2/default/wifi_chip.h +++ b/wifi/1.2/default/wifi_chip.h @@ -193,6 +193,17 @@ class WifiChip : public V1_1::IWifiChip { std::unique_lock* lock, ChipModeId mode_id); WifiStatus registerDebugRingBufferCallback(); + void populateModes(); + std::vector + getCurrentModeIfaceCombinations(); + std::map getCurrentIfaceCombination(); + std::vector> expandIfaceCombinations( + const IWifiChip::ChipIfaceCombination& combination); + bool canExpandedIfaceCombinationSupportIfaceOfType( + const std::map& combo, IfaceType type); + bool canCurrentModeSupportIfaceOfType(IfaceType type); + bool isValidModeId(ChipModeId mode_id); + ChipId chip_id_; std::weak_ptr legacy_hal_; std::weak_ptr mode_controller_; @@ -203,7 +214,9 @@ class WifiChip : public V1_1::IWifiChip { std::vector> sta_ifaces_; std::vector> rtt_controllers_; bool is_valid_; + // Members pertaining to chip configuration. uint32_t current_mode_id_; + std::vector modes_; // The legacy ring buffer callback API has only a global callback // registration mechanism. Use this to check if we have already // registered a callback. diff --git a/wifi/1.2/default/wifi_feature_flags.cpp b/wifi/1.2/default/wifi_feature_flags.cpp index aba31fb4b8..554d4d5f6d 100644 --- a/wifi/1.2/default/wifi_feature_flags.cpp +++ b/wifi/1.2/default/wifi_feature_flags.cpp @@ -22,6 +22,11 @@ static const bool wifiHidlFeatureAware = true; #else static const bool wifiHidlFeatureAware = false; #endif // WIFI_HIDL_FEATURE_AWARE +#ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE +static const bool wifiHidlFeatureDualInterface = true; +#else +static const bool wifiHidlFeatureDualInterface = false; +#endif // WIFI_HIDL_FEATURE_DUAL_INTERFACE } // namespace namespace android { @@ -33,6 +38,9 @@ namespace feature_flags { WifiFeatureFlags::WifiFeatureFlags() {} bool WifiFeatureFlags::isAwareSupported() { return wifiHidlFeatureAware; } +bool WifiFeatureFlags::isDualInterfaceSupported() { + return wifiHidlFeatureDualInterface; +} } // namespace feature_flags } // namespace implementation diff --git a/wifi/1.2/default/wifi_feature_flags.h b/wifi/1.2/default/wifi_feature_flags.h index a31ac0f658..dc0c1ff320 100644 --- a/wifi/1.2/default/wifi_feature_flags.h +++ b/wifi/1.2/default/wifi_feature_flags.h @@ -30,6 +30,7 @@ class WifiFeatureFlags { virtual ~WifiFeatureFlags() = default; virtual bool isAwareSupported(); + virtual bool isDualInterfaceSupported(); }; } // namespace feature_flags From 8e3c7ef134e9af7c1531826fd7ae3331ca693085 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Fri, 3 Nov 2017 09:43:08 -0700 Subject: [PATCH 5/6] wifi(implementation): Different names for concurrent ifaces Allocate different iface names (wlan0, wlan1) for concurrent ifaces. Bug: 65671875 Test: ./hardware/interfaces/wifi/1.2/default/tests/runtests.sh Change-Id: Ie544404183dbb616a20f88f4fb3ce71795cf89af --- .../default/tests/wifi_chip_unit_tests.cpp | 20 ++++++++++++ wifi/1.2/default/wifi_chip.cpp | 32 +++++++++++++++---- wifi/1.2/default/wifi_chip.h | 1 + 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp index e3c51fa452..f73869bc53 100644 --- a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp +++ b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp @@ -520,6 +520,26 @@ TEST_F(WifiChipV2_AwareIfaceCombinationTest, removeIface(IfaceType::NAN, nan_iface_name); ASSERT_FALSE(createIface(IfaceType::P2P).empty()); } + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + CreateStaSta_EnsureDifferentIfaceNames) { + findModeAndConfigureForIfaceType(IfaceType::AP); + const auto sta1_iface_name = createIface(IfaceType::STA); + const auto sta2_iface_name = createIface(IfaceType::STA); + ASSERT_FALSE(sta1_iface_name.empty()); + ASSERT_FALSE(sta2_iface_name.empty()); + ASSERT_NE(sta1_iface_name, sta2_iface_name); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + CreateStaAp_EnsureDifferentIfaceNames) { + findModeAndConfigureForIfaceType(IfaceType::AP); + const auto sta_iface_name = createIface(IfaceType::STA); + const auto ap_iface_name = createIface(IfaceType::AP); + ASSERT_FALSE(sta_iface_name.empty()); + ASSERT_FALSE(ap_iface_name.empty()); + ASSERT_NE(sta_iface_name, ap_iface_name); +} } // namespace implementation } // namespace V1_2 } // namespace wifi diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp index d7be38ffe1..adba054e2d 100644 --- a/wifi/1.2/default/wifi_chip.cpp +++ b/wifi/1.2/default/wifi_chip.cpp @@ -81,13 +81,11 @@ std::string getWlan0IfaceName() { return buffer.data(); } -/** Not used yet. std::string getWlan1IfaceName() { - std::array buffer; - property_get("wifi.concurrent.interface", buffer.data(), "wlan1"); - return buffer.data(); + std::array buffer; + property_get("wifi.concurrent.interface", buffer.data(), "wlan1"); + return buffer.data(); } -*/ std::string getP2pIfaceName() { std::array buffer; @@ -506,7 +504,7 @@ std::pair> WifiChip::createApIfaceInternal() { if (!canCurrentModeSupportIfaceOfType(IfaceType::AP)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } - std::string ifname = getWlan0IfaceName(); + std::string ifname = allocateApOrStaIfaceName(); sp iface = new WifiApIface(ifname, legacy_hal_); ap_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { @@ -552,6 +550,7 @@ std::pair> WifiChip::createNanIfaceInternal() { if (!canCurrentModeSupportIfaceOfType(IfaceType::NAN)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } + // These are still assumed to be based on wlan0. std::string ifname = getWlan0IfaceName(); sp iface = new WifiNanIface(ifname, legacy_hal_); nan_ifaces_.push_back(iface); @@ -644,7 +643,7 @@ std::pair> WifiChip::createStaIfaceInternal() { if (!canCurrentModeSupportIfaceOfType(IfaceType::STA)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } - std::string ifname = getWlan0IfaceName(); + std::string ifname = allocateApOrStaIfaceName(); sp iface = new WifiStaIface(ifname, legacy_hal_); sta_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { @@ -1061,6 +1060,25 @@ bool WifiChip::isValidModeId(ChipModeId mode_id) { return false; } +// Return "wlan0", if "wlan0" is not already in use, else return "wlan1". +// This is based on the assumption that we'll have a max of 2 concurrent +// AP/STA ifaces. +std::string WifiChip::allocateApOrStaIfaceName() { + auto ap_iface = findUsingName(ap_ifaces_, getWlan0IfaceName()); + auto sta_iface = findUsingName(sta_ifaces_, getWlan0IfaceName()); + if (!ap_iface.get() && !sta_iface.get()) { + return getWlan0IfaceName(); + } + ap_iface = findUsingName(ap_ifaces_, getWlan1IfaceName()); + sta_iface = findUsingName(sta_ifaces_, getWlan1IfaceName()); + if (!ap_iface.get() && !sta_iface.get()) { + return getWlan1IfaceName(); + } + // This should never happen. We screwed up somewhere if it did. + CHECK(0) << "wlan0 and wlan1 in use already!"; + return {}; +} + } // namespace implementation } // namespace V1_2 } // namespace wifi diff --git a/wifi/1.2/default/wifi_chip.h b/wifi/1.2/default/wifi_chip.h index 472a694f0e..97c434ee6a 100644 --- a/wifi/1.2/default/wifi_chip.h +++ b/wifi/1.2/default/wifi_chip.h @@ -203,6 +203,7 @@ class WifiChip : public V1_1::IWifiChip { const std::map& combo, IfaceType type); bool canCurrentModeSupportIfaceOfType(IfaceType type); bool isValidModeId(ChipModeId mode_id); + std::string allocateApOrStaIfaceName(); ChipId chip_id_; std::weak_ptr legacy_hal_; From 8fc6d17071f1e5b8f42e68a1b7b441e942004051 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 27 Nov 2017 16:08:27 -0800 Subject: [PATCH 6/6] wifi(implementation): Load wifi driver on IWifi.start() The current implementation loads the wifi driver only when the chip is configured, but the HAL is initialized on IWifi.start(). This seems to be wrong semantically. The driver needs to be loaded before the HAL is initialized. This may have worked previously because the driver was loaded in init.rc, but may stop working when we move to proper DLKM model in 2018. Bug: 65671875 Test: Device boots up and connects to wifi networks. Change-Id: I017d3528bf0b42a6a59af43203ecc9d0d027f60d --- wifi/1.2/default/tests/mock_wifi_mode_controller.h | 1 + wifi/1.2/default/wifi.cpp | 8 ++++++-- wifi/1.2/default/wifi.h | 2 +- wifi/1.2/default/wifi_mode_controller.cpp | 6 +++++- wifi/1.2/default/wifi_mode_controller.h | 1 + 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/wifi/1.2/default/tests/mock_wifi_mode_controller.h b/wifi/1.2/default/tests/mock_wifi_mode_controller.h index 73ff5f095c..50c3e35bbc 100644 --- a/wifi/1.2/default/tests/mock_wifi_mode_controller.h +++ b/wifi/1.2/default/tests/mock_wifi_mode_controller.h @@ -31,6 +31,7 @@ namespace mode_controller { class MockWifiModeController : public WifiModeController { public: MockWifiModeController(); + MOCK_METHOD0(initialize, bool()); MOCK_METHOD1(changeFirmwareMode, bool(IfaceType)); MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType)); MOCK_METHOD0(deinitialize, bool()); diff --git a/wifi/1.2/default/wifi.cpp b/wifi/1.2/default/wifi.cpp index 5a8b66ec53..06f5058891 100644 --- a/wifi/1.2/default/wifi.cpp +++ b/wifi/1.2/default/wifi.cpp @@ -92,7 +92,7 @@ WifiStatus Wifi::startInternal() { return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping"); } - WifiStatus wifi_status = initializeLegacyHal(); + WifiStatus wifi_status = initializeModeControllerAndLegacyHal(); if (wifi_status.code == WifiStatusCode::SUCCESS) { // Create the chip instance once the HAL is started. chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_, @@ -166,7 +166,11 @@ std::pair> Wifi::getChipInternal(ChipId chip_id) { return {createWifiStatus(WifiStatusCode::SUCCESS), chip_}; } -WifiStatus Wifi::initializeLegacyHal() { +WifiStatus Wifi::initializeModeControllerAndLegacyHal() { + if (!mode_controller_->initialize()) { + LOG(ERROR) << "Failed to initialize firmware mode controller"; + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } legacy_hal::wifi_error legacy_status = legacy_hal_->initialize(); if (legacy_status != legacy_hal::WIFI_SUCCESS) { LOG(ERROR) << "Failed to initialize legacy HAL: " diff --git a/wifi/1.2/default/wifi.h b/wifi/1.2/default/wifi.h index d76e9c93e0..440c3c7984 100644 --- a/wifi/1.2/default/wifi.h +++ b/wifi/1.2/default/wifi.h @@ -68,7 +68,7 @@ class Wifi : public V1_2::IWifi { std::pair> getChipIdsInternal(); std::pair> getChipInternal(ChipId chip_id); - WifiStatus initializeLegacyHal(); + WifiStatus initializeModeControllerAndLegacyHal(); WifiStatus stopLegacyHalAndDeinitializeModeController( std::unique_lock* lock); diff --git a/wifi/1.2/default/wifi_mode_controller.cpp b/wifi/1.2/default/wifi_mode_controller.cpp index 8a89e810ba..c286d2439c 100644 --- a/wifi/1.2/default/wifi_mode_controller.cpp +++ b/wifi/1.2/default/wifi_mode_controller.cpp @@ -59,11 +59,15 @@ bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) { convertIfaceTypeToFirmwareMode(type)); } -bool WifiModeController::changeFirmwareMode(IfaceType type) { +bool WifiModeController::initialize() { if (!driver_tool_->LoadDriver()) { LOG(ERROR) << "Failed to load WiFi driver"; return false; } + return true; +} + +bool WifiModeController::changeFirmwareMode(IfaceType type) { if (!driver_tool_->ChangeFirmwareMode( convertIfaceTypeToFirmwareMode(type))) { LOG(ERROR) << "Failed to change firmware mode"; diff --git a/wifi/1.2/default/wifi_mode_controller.h b/wifi/1.2/default/wifi_mode_controller.h index e54fa6e44a..395aa5d9e8 100644 --- a/wifi/1.2/default/wifi_mode_controller.h +++ b/wifi/1.2/default/wifi_mode_controller.h @@ -42,6 +42,7 @@ class WifiModeController { // Checks if a firmware mode change is necessary to support the specified // iface type operations. virtual bool isFirmwareModeChangeNeeded(IfaceType type); + virtual bool initialize(); // Change the firmware mode to support the specified iface type operations. virtual bool changeFirmwareMode(IfaceType type); // Unload the driver. This should be invoked whenever |IWifi.stop()| is