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
diff --git a/wifi/1.2/default/Android.mk b/wifi/1.2/default/Android.mk
index 1207320..95414bc 100644
--- a/wifi/1.2/default/Android.mk
+++ b/wifi/1.2/default/Android.mk
@@ -24,6 +24,9 @@
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 85927f9..8cf1d4b 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 @@
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 f78b852..e3c51fa 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 @@
void setupV1IfaceCombination() {
EXPECT_CALL(*feature_flags_, isAwareSupported())
.WillRepeatedly(testing::Return(false));
- chip_->getAvailableModes(
- [](const WifiStatus& status,
- const std::vector<WifiChip::ChipMode>& 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<WifiChip::ChipMode>& modes) {
+ [num_modes](const WifiStatus& status,
+ const std::vector<WifiChip::ChipMode>& 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 WifiChipV1IfaceCombinationTest : public WifiChipTest {
public:
void SetUp() override {
- WifiChipTest::SetUp();
setupV1IfaceCombination();
+ WifiChipTest::SetUp();
+ // V1 has 2 modes of operation.
+ assertNumberOfModes(2u);
}
};
@@ -250,57 +259,62 @@
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 @@
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 @@
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 c4956e0..d7be38f 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::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 <typename Iface>
void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
@@ -110,7 +115,9 @@
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<WifiStatus, std::vector<IWifiChip::ChipMode>>
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<std::recursive_mutex>* 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 @@
}
std::pair<WifiStatus, uint32_t> 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 @@
}
std::pair<WifiStatus, sp<IWifiApIface>> 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 @@
}
std::pair<WifiStatus, sp<IWifiNanIface>> 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<WifiNanIface> 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<WifiNanIface> 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<WifiStatus, std::vector<hidl_string>>
@@ -624,9 +595,7 @@
}
std::pair<WifiStatus, sp<IWifiP2pIface>> 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 @@
}
std::pair<WifiStatus, sp<IWifiStaIface>> 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 @@
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 @@
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 @@
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<IWifiChip::ChipIfaceCombination>
+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<IfaceType, size_t> WifiChip::getCurrentIfaceCombination() {
+ std::map<IfaceType, size_t> 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<std::map<IfaceType, size_t>> 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<std::map<IfaceType, size_t>> 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<IfaceType, size_t>& 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 b843cf3..472a694 100644
--- a/wifi/1.2/default/wifi_chip.h
+++ b/wifi/1.2/default/wifi_chip.h
@@ -193,6 +193,17 @@
std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
WifiStatus registerDebugRingBufferCallback();
+ void populateModes();
+ std::vector<IWifiChip::ChipIfaceCombination>
+ getCurrentModeIfaceCombinations();
+ std::map<IfaceType, size_t> getCurrentIfaceCombination();
+ std::vector<std::map<IfaceType, size_t>> expandIfaceCombinations(
+ const IWifiChip::ChipIfaceCombination& combination);
+ bool canExpandedIfaceCombinationSupportIfaceOfType(
+ const std::map<IfaceType, size_t>& combo, IfaceType type);
+ bool canCurrentModeSupportIfaceOfType(IfaceType type);
+ bool isValidModeId(ChipModeId mode_id);
+
ChipId chip_id_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
@@ -203,7 +214,9 @@
std::vector<sp<WifiStaIface>> sta_ifaces_;
std::vector<sp<WifiRttController>> rtt_controllers_;
bool is_valid_;
+ // Members pertaining to chip configuration.
uint32_t current_mode_id_;
+ std::vector<IWifiChip::ChipMode> 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 aba31fb..554d4d5 100644
--- a/wifi/1.2/default/wifi_feature_flags.cpp
+++ b/wifi/1.2/default/wifi_feature_flags.cpp
@@ -22,6 +22,11 @@
#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 @@
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 a31ac0f..dc0c1ff 100644
--- a/wifi/1.2/default/wifi_feature_flags.h
+++ b/wifi/1.2/default/wifi_feature_flags.h
@@ -30,6 +30,7 @@
virtual ~WifiFeatureFlags() = default;
virtual bool isAwareSupported();
+ virtual bool isDualInterfaceSupported();
};
} // namespace feature_flags