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