wifi(implementation): Pin primary STA iface to wlan0

The primary STA iface will always be pinned to wlan0.
The primary AP iface will be pinned to wlan0 for devices not supporting
STA + AP concurrency & wlan1 for devices supporting STA + AP concurrency.

All secondary STA or AP ifaces will be allocated on a first come first
service basis (the current logic).

Also, refactored/renamed some of the iface combo selection logic methods
to help check whether concurrency is allowed in the current mode.

Bug: 128946563
Test: ./data/android.hardware.wifi@1.0-service-tests
Test: Will send for full regression tests.
Test: On crosshatch, ensured that STA always comes up on wlan0 & AP
comes up on wlan1 regardless of the sequence of toggle followed.
Change-Id: Idca8de42ce819240bf0fac2a9039d15ed4bcaf90
diff --git a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
index 134563c..7df9705 100644
--- a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
@@ -122,7 +122,7 @@
     void setup_MultiIfaceCombination() {
         // clang-format off
         const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
-            {{{{IfaceType::STA}, 3}}}
+            {{{{IfaceType::STA}, 3}, {{IfaceType::AP}, 1}}}
         };
         const std::vector<V1_0::IWifiChip::ChipMode> modes = {
             {feature_flags::chip_mode_ids::kV3, combinations}
@@ -272,6 +272,13 @@
             .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
     }
 
+    void TearDown() override {
+        // Restore default system iface names (This should ideally be using a
+        // mock).
+        property_set("wifi.interface", "wlan0");
+        property_set("wifi.concurrent.interface", "wlan1");
+    }
+
    private:
     sp<WifiChip> chip_;
     ChipId chip_id_ = kFakeChipId;
@@ -300,7 +307,7 @@
 
 TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
 }
 
 TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
@@ -326,7 +333,7 @@
 
 TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
 }
 
 TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
@@ -359,7 +366,7 @@
 
 TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
 }
 
 TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
@@ -427,7 +434,7 @@
 
 TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
 }
 
 TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
@@ -483,7 +490,7 @@
 
 TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
 }
 
 TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) {
@@ -498,19 +505,25 @@
 
 TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
 }
 
 TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldFail) {
     findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
     ASSERT_TRUE(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());
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
 }
 
 TEST_F(WifiChipV2_AwareIfaceCombinationTest,
@@ -707,8 +720,8 @@
     property_set("wifi.interface", "bad0");
     property_set("wifi.concurrent.interface", "bad1");
     findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "test0");
-    ASSERT_EQ(createIface(IfaceType::STA), "test1");
+    ASSERT_EQ(createIface(IfaceType::STA), "bad0");
+    ASSERT_EQ(createIface(IfaceType::STA), "bad1");
     ASSERT_EQ(createIface(IfaceType::STA), "test2");
 }
 
@@ -724,6 +737,16 @@
     ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
 }
 
+TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    // First AP will be slotted to wlan1.
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    // First STA will be slotted to wlan0.
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    // All further STA will be slotted to the remaining free indices.
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
+}
 }  // namespace implementation
 }  // namespace V1_3
 }  // namespace wifi
diff --git a/wifi/1.3/default/wifi_chip.cpp b/wifi/1.3/default/wifi_chip.cpp
index 3697d50..ce5df17 100644
--- a/wifi/1.3/default/wifi_chip.cpp
+++ b/wifi/1.3/default/wifi_chip.cpp
@@ -766,10 +766,10 @@
 }
 
 std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::createApIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfType(IfaceType::AP)) {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
-    std::string ifname = allocateApOrStaIfaceName();
+    std::string ifname = allocateApIfaceName();
     sp<WifiApIface> iface =
         new WifiApIface(ifname, legacy_hal_, iface_util_, feature_flags_);
     ap_ifaces_.push_back(iface);
@@ -813,7 +813,7 @@
 }
 
 std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::createNanIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfType(IfaceType::NAN)) {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) {
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
     // These are still assumed to be based on wlan0.
@@ -860,7 +860,7 @@
 }
 
 std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfType(IfaceType::P2P)) {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::P2P)) {
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
     std::string ifname = getP2pIfaceName();
@@ -906,10 +906,10 @@
 }
 
 std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::createStaIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) {
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
-    std::string ifname = allocateApOrStaIfaceName();
+    std::string ifname = allocateStaIfaceName();
     sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_, iface_util_);
     sta_ifaces_.push_back(iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -1298,8 +1298,9 @@
     return expanded_combos;
 }
 
-bool WifiChip::canExpandedIfaceCombinationSupportIfaceOfType(
-    const std::map<IfaceType, size_t>& combo, IfaceType requested_type) {
+bool WifiChip::canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+    const std::map<IfaceType, size_t>& expanded_combo,
+    IfaceType requested_type) {
     const auto current_combo = getCurrentIfaceCombination();
 
     // Check if we have space for 1 more iface of |type| in this combo
@@ -1309,7 +1310,7 @@
         if (type == requested_type) {
             num_ifaces_needed++;
         }
-        size_t num_ifaces_allowed = combo.at(type);
+        size_t num_ifaces_allowed = expanded_combo.at(type);
         if (num_ifaces_needed > num_ifaces_allowed) {
             return false;
         }
@@ -1320,8 +1321,10 @@
 // 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) {
+// b) Check if the requested iface type can be added to the current mode
+//    with the iface combination that is already active.
+bool WifiChip::canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
+    IfaceType requested_type) {
     if (!isValidModeId(current_mode_id_)) {
         LOG(ERROR) << "Chip not configured in a mode yet";
         return false;
@@ -1330,8 +1333,8 @@
     for (const auto& combination : combinations) {
         const auto expanded_combos = expandIfaceCombinations(combination);
         for (const auto& expanded_combo : expanded_combos) {
-            if (canExpandedIfaceCombinationSupportIfaceOfType(expanded_combo,
-                                                              type)) {
+            if (canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+                    expanded_combo, requested_type)) {
                 return true;
             }
         }
@@ -1339,6 +1342,62 @@
     return false;
 }
 
+// Note: This does not consider ifaces already active. It only checks if the
+// provided expanded iface combination can support the requested combo.
+bool WifiChip::canExpandedIfaceComboSupportIfaceCombo(
+    const std::map<IfaceType, size_t>& expanded_combo,
+    const std::map<IfaceType, size_t>& req_combo) {
+    // 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}) {
+        if (req_combo.count(type) == 0) {
+            // Iface of "type" not in the req_combo.
+            continue;
+        }
+        size_t num_ifaces_needed = req_combo.at(type);
+        size_t num_ifaces_allowed = expanded_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 combo can be added to the current mode.
+// Note: This does not consider ifaces already active. It only checks if the
+// current mode can support the requested combo.
+bool WifiChip::canCurrentModeSupportIfaceCombo(
+    const std::map<IfaceType, size_t>& req_combo) {
+    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 (canExpandedIfaceComboSupportIfaceCombo(expanded_combo,
+                                                       req_combo)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+// 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 requested_type) {
+    // Check if we can support atleast 1 iface of type.
+    std::map<IfaceType, size_t> req_iface_combo;
+    req_iface_combo[requested_type] = 1;
+    return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
 bool WifiChip::isValidModeId(ChipModeId mode_id) {
     for (const auto& mode : modes_) {
         if (mode.id == mode_id) {
@@ -1348,11 +1407,20 @@
     return false;
 }
 
-// Return the first wlan (wlan0, wlan1 etc.) not already in use.
-// This doesn't check the actual presence of these interfaces.
-std::string WifiChip::allocateApOrStaIfaceName() {
-    for (unsigned i = 0; i < kMaxWlanIfaces; i++) {
-        const auto ifname = getWlanIfaceName(i);
+bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() {
+    // Check if we can support atleast 1 STA & 1 AP concurrently.
+    std::map<IfaceType, size_t> req_iface_combo;
+    req_iface_combo[IfaceType::AP] = 1;
+    req_iface_combo[IfaceType::STA] = 1;
+    return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
+// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
+// not already in use.
+// Note: This doesn't check the actual presence of these interfaces.
+std::string WifiChip::allocateApOrStaIfaceName(uint32_t start_idx) {
+    for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
+        const auto ifname = getWlanIfaceName(idx);
         if (findUsingName(ap_ifaces_, ifname)) continue;
         if (findUsingName(sta_ifaces_, ifname)) continue;
         return ifname;
@@ -1362,6 +1430,19 @@
     return {};
 }
 
+// AP iface names start with idx 1 for modes supporting
+// concurrent STA, else start with idx 0.
+std::string WifiChip::allocateApIfaceName() {
+    return allocateApOrStaIfaceName(
+        isStaApConcurrencyAllowedInCurrentMode() ? 1 : 0);
+}
+
+// STA iface names start with idx 0.
+// Primary STA iface will always be 0.
+std::string WifiChip::allocateStaIfaceName() {
+    return allocateApOrStaIfaceName(0);
+}
+
 bool WifiChip::writeRingbufferFilesInternal() {
     if (!removeOldFilesInternal()) {
         LOG(ERROR) << "Error occurred while deleting old tombstone files";
diff --git a/wifi/1.3/default/wifi_chip.h b/wifi/1.3/default/wifi_chip.h
index 3eb0aee..27db9a4 100644
--- a/wifi/1.3/default/wifi_chip.h
+++ b/wifi/1.3/default/wifi_chip.h
@@ -224,11 +224,22 @@
     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 canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+        const std::map<IfaceType, size_t>& expanded_combo,
+        IfaceType requested_type);
+    bool canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
+        IfaceType requested_type);
+    bool canExpandedIfaceComboSupportIfaceCombo(
+        const std::map<IfaceType, size_t>& expanded_combo,
+        const std::map<IfaceType, size_t>& req_combo);
+    bool canCurrentModeSupportIfaceCombo(
+        const std::map<IfaceType, size_t>& req_combo);
+    bool canCurrentModeSupportIfaceOfType(IfaceType requested_type);
     bool isValidModeId(ChipModeId mode_id);
-    std::string allocateApOrStaIfaceName();
+    bool isStaApConcurrencyAllowedInCurrentMode();
+    std::string allocateApOrStaIfaceName(uint32_t start_idx);
+    std::string allocateApIfaceName();
+    std::string allocateStaIfaceName();
     bool writeRingbufferFilesInternal();
 
     ChipId chip_id_;