Merge changes from topic "60ghz-1-vendor-hal-multi-chip"

* changes:
  Wifi: support multiple WIFI chips
  Wifi: fix bug during WIFI HAL stop
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index 5b11dd3..092822f 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -112,7 +112,7 @@
     const auto& status_and_chip_ids = HIDL_INVOKE(wifi, getChipIds);
     const auto& chip_ids = status_and_chip_ids.second;
     if (status_and_chip_ids.first.code != WifiStatusCode::SUCCESS ||
-        chip_ids.size() != 1) {
+        chip_ids.size() < 1) {
         return nullptr;
     }
     const auto& status_and_chip = HIDL_INVOKE(wifi, getChip, chip_ids[0]);
diff --git a/wifi/1.5/default/Android.mk b/wifi/1.5/default/Android.mk
index 236dae2..dc9e89b 100644
--- a/wifi/1.5/default/Android.mk
+++ b/wifi/1.5/default/Android.mk
@@ -51,6 +51,7 @@
     wifi_feature_flags.cpp \
     wifi_iface_util.cpp \
     wifi_legacy_hal.cpp \
+    wifi_legacy_hal_factory.cpp \
     wifi_legacy_hal_stubs.cpp \
     wifi_mode_controller.cpp \
     wifi_nan_iface.cpp \
@@ -67,12 +68,14 @@
     libutils \
     libwifi-hal \
     libwifi-system-iface \
+    libxml2 \
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
     android.hardware.wifi@1.2 \
     android.hardware.wifi@1.3 \
     android.hardware.wifi@1.4 \
     android.hardware.wifi@1.5
+LOCAL_C_INCLUDES += $(TOP)/external/libxml2/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
 include $(BUILD_STATIC_LIBRARY)
 
@@ -96,6 +99,7 @@
     libutils \
     libwifi-hal \
     libwifi-system-iface \
+    libxml2 \
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
     android.hardware.wifi@1.2 \
@@ -129,6 +133,7 @@
     libutils \
     libwifi-hal \
     libwifi-system-iface \
+    libxml2 \
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
     android.hardware.wifi@1.2 \
diff --git a/wifi/1.5/default/service.cpp b/wifi/1.5/default/service.cpp
index f53d528..8539a37 100644
--- a/wifi/1.5/default/service.cpp
+++ b/wifi/1.5/default/service.cpp
@@ -23,6 +23,7 @@
 #include "wifi.h"
 #include "wifi_feature_flags.h"
 #include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_factory.h"
 #include "wifi_mode_controller.h"
 
 using android::hardware::configureRpcThreadpool;
@@ -32,6 +33,8 @@
     WifiFeatureFlags;
 using android::hardware::wifi::V1_5::implementation::iface_util::WifiIfaceUtil;
 using android::hardware::wifi::V1_5::implementation::legacy_hal::WifiLegacyHal;
+using android::hardware::wifi::V1_5::implementation::legacy_hal::
+    WifiLegacyHalFactory;
 using android::hardware::wifi::V1_5::implementation::mode_controller::
     WifiModeController;
 
@@ -50,10 +53,13 @@
 
     const auto iface_tool =
         std::make_shared<android::wifi_system::InterfaceTool>();
+    const auto legacy_hal_factory =
+        std::make_shared<WifiLegacyHalFactory>(iface_tool);
+
     // Setup hwbinder service
     android::sp<android::hardware::wifi::V1_5::IWifi> service =
         new android::hardware::wifi::V1_5::implementation::Wifi(
-            iface_tool, std::make_shared<WifiLegacyHal>(iface_tool),
+            iface_tool, legacy_hal_factory,
             std::make_shared<WifiModeController>(),
             std::make_shared<WifiIfaceUtil>(iface_tool),
             std::make_shared<WifiFeatureFlags>());
diff --git a/wifi/1.5/default/tests/mock_wifi_feature_flags.h b/wifi/1.5/default/tests/mock_wifi_feature_flags.h
index 92fbb05..c3877ed 100644
--- a/wifi/1.5/default/tests/mock_wifi_feature_flags.h
+++ b/wifi/1.5/default/tests/mock_wifi_feature_flags.h
@@ -33,7 +33,8 @@
    public:
     MockWifiFeatureFlags();
 
-    MOCK_METHOD0(getChipModes, std::vector<V1_0::IWifiChip::ChipMode>());
+    MOCK_METHOD1(getChipModes,
+                 std::vector<V1_0::IWifiChip::ChipMode>(bool is_primary));
     MOCK_METHOD0(isApMacRandomizationDisabled, bool());
 };
 
diff --git a/wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp
index 501bd7f..d13c556 100644
--- a/wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp
@@ -29,8 +29,9 @@
 namespace legacy_hal {
 
 MockWifiLegacyHal::MockWifiLegacyHal(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
-    : WifiLegacyHal(iface_tool) {}
+    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+    const wifi_hal_fn& fn, bool is_primary)
+    : WifiLegacyHal(iface_tool, fn, is_primary) {}
 }  // namespace legacy_hal
 }  // namespace implementation
 }  // namespace V1_5
diff --git a/wifi/1.5/default/tests/mock_wifi_legacy_hal.h b/wifi/1.5/default/tests/mock_wifi_legacy_hal.h
index f938347..9ab2fd5 100644
--- a/wifi/1.5/default/tests/mock_wifi_legacy_hal.h
+++ b/wifi/1.5/default/tests/mock_wifi_legacy_hal.h
@@ -31,7 +31,8 @@
 class MockWifiLegacyHal : public WifiLegacyHal {
    public:
     MockWifiLegacyHal(
-        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+        const wifi_hal_fn& fn, bool is_primary);
     MOCK_METHOD0(initialize, wifi_error());
     MOCK_METHOD0(start, wifi_error());
     MOCK_METHOD2(stop, wifi_error(std::unique_lock<std::recursive_mutex>*,
diff --git a/wifi/1.5/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.5/default/tests/wifi_chip_unit_tests.cpp
index 1d55e16..d99bfbd 100644
--- a/wifi/1.5/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.5/default/tests/wifi_chip_unit_tests.cpp
@@ -59,7 +59,7 @@
             {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
         };
         // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
+        EXPECT_CALL(*feature_flags_, getChipModes(true))
             .WillRepeatedly(testing::Return(modes));
     }
 
@@ -76,7 +76,7 @@
             {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
         };
         // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
+        EXPECT_CALL(*feature_flags_, getChipModes(true))
             .WillRepeatedly(testing::Return(modes));
     }
 
@@ -89,7 +89,7 @@
             {feature_flags::chip_mode_ids::kV1Sta, combinationsSta}
         };
         // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
+        EXPECT_CALL(*feature_flags_, getChipModes(true))
             .WillRepeatedly(testing::Return(modes));
     }
 
@@ -103,7 +103,7 @@
             {feature_flags::chip_mode_ids::kV3, combinations}
         };
         // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
+        EXPECT_CALL(*feature_flags_, getChipModes(true))
             .WillRepeatedly(testing::Return(modes));
     }
 
@@ -116,7 +116,7 @@
             {feature_flags::chip_mode_ids::kV3, combinations}
         };
         // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
+        EXPECT_CALL(*feature_flags_, getChipModes(true))
             .WillRepeatedly(testing::Return(modes));
     }
 
@@ -129,7 +129,7 @@
             {feature_flags::chip_mode_ids::kV3, combinations}
         };
         // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
+        EXPECT_CALL(*feature_flags_, getChipModes(true))
             .WillRepeatedly(testing::Return(modes));
     }
 
@@ -267,10 +267,12 @@
 
     sp<WifiChip> chip_;
     ChipId chip_id_ = kFakeChipId;
+    legacy_hal::wifi_hal_fn fake_func_table_;
     std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
         new NiceMock<wifi_system::MockInterfaceTool>};
     std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
+        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_,
+                                                    fake_func_table_, true)};
     std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>>
         mode_controller_{new NiceMock<mode_controller::MockWifiModeController>};
     std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
@@ -281,8 +283,8 @@
    public:
     void SetUp() override {
         chip_ =
-            new WifiChip(chip_id_, legacy_hal_, mode_controller_, iface_util_,
-                         feature_flags_, subsystemRestartHandler);
+            new WifiChip(chip_id_, true, legacy_hal_, mode_controller_,
+                         iface_util_, feature_flags_, subsystemRestartHandler);
 
         EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
             .WillRepeatedly(testing::Return(true));
diff --git a/wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp
index 3e7026f..411190b 100644
--- a/wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp
+++ b/wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -112,10 +112,12 @@
 
 class WifiNanIfaceTest : public Test {
    protected:
+    legacy_hal::wifi_hal_fn fake_func_table_;
     std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
         new NiceMock<wifi_system::MockInterfaceTool>};
     std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
+        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_,
+                                                    fake_func_table_, true)};
     std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
         new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
 };
diff --git a/wifi/1.5/default/wifi.cpp b/wifi/1.5/default/wifi.cpp
index c4e2333..17db51d 100644
--- a/wifi/1.5/default/wifi.cpp
+++ b/wifi/1.5/default/wifi.cpp
@@ -21,8 +21,8 @@
 #include "wifi_status_util.h"
 
 namespace {
-// Chip ID to use for the only supported chip.
-static constexpr android::hardware::wifi::V1_0::ChipId kChipId = 0;
+// Starting Chip ID, will be assigned to primary chip
+static constexpr android::hardware::wifi::V1_0::ChipId kPrimaryChipId = 0;
 }  // namespace
 
 namespace android {
@@ -35,12 +35,12 @@
 
 Wifi::Wifi(
     const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
-    const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    const std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory,
     const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
     const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
     const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
     : iface_tool_(iface_tool),
-      legacy_hal_(legacy_hal),
+      legacy_hal_factory_(legacy_hal_factory),
       mode_controller_(mode_controller),
       iface_util_(iface_util),
       feature_flags_(feature_flags),
@@ -84,10 +84,16 @@
 Return<void> Wifi::debug(const hidl_handle& handle,
                          const hidl_vec<hidl_string>&) {
     LOG(INFO) << "-----------Debug is called----------------";
-    if (!chip_.get()) {
+    if (chips_.size() == 0) {
         return Void();
     }
-    return chip_->debug(handle, {});
+
+    for (sp<WifiChip> chip : chips_) {
+        if (!chip.get()) continue;
+
+        chip->debug(handle, {});
+    }
+    return Void();
 }
 
 WifiStatus Wifi::registerEventCallbackInternal(
@@ -120,10 +126,13 @@
             };
 
         // Create the chip instance once the HAL is started.
-        // Need to consider the case of multiple chips TODO(156998862)
-        chip_ =
-            new WifiChip(kChipId, legacy_hal_, mode_controller_, iface_util_,
-                         feature_flags_, on_subsystem_restart_callback);
+        android::hardware::wifi::V1_0::ChipId chipId = kPrimaryChipId;
+        for (auto& hal : legacy_hals_) {
+            chips_.push_back(new WifiChip(
+                chipId, chipId == kPrimaryChipId, hal, mode_controller_,
+                iface_util_, feature_flags_, on_subsystem_restart_callback));
+            chipId++;
+        }
         run_state_ = RunState::STARTED;
         for (const auto& callback : event_cb_handler_.getCallbacks()) {
             if (!callback->onStart().isOk()) {
@@ -154,10 +163,13 @@
     }
     // Clear the chip object and its child objects since the HAL is now
     // stopped.
-    if (chip_.get()) {
-        chip_->invalidate();
-        chip_.clear();
+    for (auto& chip : chips_) {
+        if (chip.get()) {
+            chip->invalidate();
+            chip.clear();
+        }
     }
+    chips_.clear();
     WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
     if (wifi_status.code == WifiStatusCode::SUCCESS) {
         for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -181,21 +193,23 @@
 
 std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
     std::vector<ChipId> chip_ids;
-    if (chip_.get()) {
-        chip_ids.emplace_back(kChipId);
+
+    for (auto& chip : chips_) {
+        ChipId chip_id = getChipIdFromWifiChip(chip);
+        if (chip_id != UINT32_MAX) chip_ids.emplace_back(chip_id);
     }
     return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
 }
 
 std::pair<WifiStatus, sp<V1_4::IWifiChip>> Wifi::getChipInternal(
     ChipId chip_id) {
-    if (!chip_.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_STARTED), nullptr};
+    for (auto& chip : chips_) {
+        ChipId cand_id = getChipIdFromWifiChip(chip);
+        if ((cand_id != UINT32_MAX) && (cand_id == chip_id))
+            return {createWifiStatus(WifiStatusCode::SUCCESS), chip};
     }
-    if (chip_id != kChipId) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), chip_};
+
+    return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
 }
 
 WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
@@ -203,23 +217,46 @@
         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: "
-                   << legacyErrorToString(legacy_status);
-        return createWifiStatusFromLegacyError(legacy_status);
+
+    legacy_hals_ = legacy_hal_factory_->getHals();
+    if (legacy_hals_.empty())
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    int index = 0;  // for failure log
+    for (auto& hal : legacy_hals_) {
+        legacy_hal::wifi_error legacy_status = hal->initialize();
+        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+            // Currently WifiLegacyHal::initialize does not allocate extra mem,
+            // only initializes the function table. If this changes, need to
+            // implement WifiLegacyHal::deinitialize and deinitalize the
+            // HALs already initialized
+            LOG(ERROR) << "Failed to initialize legacy HAL index: " << index
+                       << " error: " << legacyErrorToString(legacy_status);
+            return createWifiStatusFromLegacyError(legacy_status);
+        }
+        index++;
     }
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
 WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
     /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+    legacy_hal::wifi_error legacy_status = legacy_hal::WIFI_SUCCESS;
+    int index = 0;
+
     run_state_ = RunState::STOPPING;
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_->stop(lock, [&]() { run_state_ = RunState::STOPPED; });
+    for (auto& hal : legacy_hals_) {
+        legacy_hal::wifi_error tmp = hal->stop(lock, [&]() {});
+        if (tmp != legacy_hal::WIFI_SUCCESS) {
+            LOG(ERROR) << "Failed to stop legacy HAL index: " << index
+                       << " error: " << legacyErrorToString(legacy_status);
+            legacy_status = tmp;
+        }
+        index++;
+    }
+    run_state_ = RunState::STOPPED;
+
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to stop legacy HAL: "
-                   << legacyErrorToString(legacy_status);
+        LOG(ERROR) << "One or more legacy HALs failed to stop";
         return createWifiStatusFromLegacyError(legacy_status);
     }
     if (!mode_controller_->deinitialize()) {
@@ -228,6 +265,19 @@
     }
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
+
+ChipId Wifi::getChipIdFromWifiChip(sp<WifiChip>& chip) {
+    ChipId chip_id = UINT32_MAX;
+    if (chip.get()) {
+        chip->getId([&](WifiStatus status, uint32_t id) {
+            if (status.code == WifiStatusCode::SUCCESS) {
+                chip_id = id;
+            }
+        });
+    }
+
+    return chip_id;
+}
 }  // namespace implementation
 }  // namespace V1_5
 }  // namespace wifi
diff --git a/wifi/1.5/default/wifi.h b/wifi/1.5/default/wifi.h
index 8de0ef4..9f5a1b0 100644
--- a/wifi/1.5/default/wifi.h
+++ b/wifi/1.5/default/wifi.h
@@ -27,6 +27,7 @@
 #include "wifi_chip.h"
 #include "wifi_feature_flags.h"
 #include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_factory.h"
 #include "wifi_mode_controller.h"
 
 namespace android {
@@ -41,7 +42,8 @@
 class Wifi : public V1_5::IWifi {
    public:
     Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
-         const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+         const std::shared_ptr<legacy_hal::WifiLegacyHalFactory>
+             legacy_hal_factory,
          const std::shared_ptr<mode_controller::WifiModeController>
              mode_controller,
          const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
@@ -75,16 +77,18 @@
     WifiStatus initializeModeControllerAndLegacyHal();
     WifiStatus stopLegacyHalAndDeinitializeModeController(
         std::unique_lock<std::recursive_mutex>* lock);
+    ChipId getChipIdFromWifiChip(sp<WifiChip>& chip);
 
     // Instance is created in this root level |IWifi| HIDL interface object
     // and shared with all the child HIDL interface objects.
     std::shared_ptr<wifi_system::InterfaceTool> iface_tool_;
-    std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory_;
     std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
+    std::vector<std::shared_ptr<legacy_hal::WifiLegacyHal>> legacy_hals_;
     std::shared_ptr<iface_util::WifiIfaceUtil> iface_util_;
     std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
     RunState run_state_;
-    sp<WifiChip> chip_;
+    std::vector<sp<WifiChip>> chips_;
     hidl_callback_util::HidlCallbackHandler<IWifiEventCallback>
         event_cb_handler_;
 
diff --git a/wifi/1.5/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
index 069fd65..9c352bc 100644
--- a/wifi/1.5/default/wifi_chip.cpp
+++ b/wifi/1.5/default/wifi_chip.cpp
@@ -332,7 +332,8 @@
 using hidl_return_util::validateAndCallWithLock;
 
 WifiChip::WifiChip(
-    ChipId chip_id, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    ChipId chip_id, bool is_primary,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
     const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
     const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
     const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
@@ -343,7 +344,7 @@
       iface_util_(iface_util),
       is_valid_(true),
       current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
-      modes_(feature_flags.lock()->getChipModes()),
+      modes_(feature_flags.lock()->getChipModes(is_primary)),
       debug_ring_buffer_cb_registered_(false),
       subsystemCallbackHandler_(handler) {
     setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
@@ -681,9 +682,10 @@
 
 void WifiChip::invalidateAndRemoveDependencies(
     const std::string& removed_iface_name) {
-    for (const auto& nan_iface : nan_ifaces_) {
+    for (auto it = nan_ifaces_.begin(); it != nan_ifaces_.end();) {
+        auto nan_iface = *it;
         if (nan_iface->getName() == removed_iface_name) {
-            invalidateAndClear(nan_ifaces_, nan_iface);
+            nan_iface->invalidate();
             for (const auto& callback : event_cb_handler_.getCallbacks()) {
                 if (!callback
                          ->onIfaceRemoved(IfaceType::NAN, removed_iface_name)
@@ -691,11 +693,19 @@
                     LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
                 }
             }
+            it = nan_ifaces_.erase(it);
+        } else {
+            ++it;
         }
     }
-    for (const auto& rtt : rtt_controllers_) {
+
+    for (auto it = rtt_controllers_.begin(); it != rtt_controllers_.end();) {
+        auto rtt = *it;
         if (rtt->getIfaceName() == removed_iface_name) {
-            invalidateAndClear(rtt_controllers_, rtt);
+            rtt->invalidate();
+            it = rtt_controllers_.erase(it);
+        } else {
+            ++it;
         }
     }
 }
@@ -1590,15 +1600,16 @@
     // This could happen if the chip call is made before any STA/AP
     // iface is created. Default to wlan0 for such cases.
     LOG(WARNING) << "No active wlan interfaces in use! Using default";
-    return getWlanIfaceName(0);
+    return getWlanIfaceNameWithType(IfaceType::STA, 0);
 }
 
 // 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) {
+std::string WifiChip::allocateApOrStaIfaceName(IfaceType type,
+                                               uint32_t start_idx) {
     for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
-        const auto ifname = getWlanIfaceName(idx);
+        const auto ifname = getWlanIfaceNameWithType(type, idx);
         if (findUsingName(ap_ifaces_, ifname)) continue;
         if (findUsingName(sta_ifaces_, ifname)) continue;
         return ifname;
@@ -1616,7 +1627,8 @@
     if (!ifname.empty()) {
         return ifname;
     }
-    return allocateApOrStaIfaceName((isStaApConcurrencyAllowedInCurrentMode() &&
+    return allocateApOrStaIfaceName(IfaceType::AP,
+                                    (isStaApConcurrencyAllowedInCurrentMode() &&
                                      !isDualApAllowedInCurrentMode())
                                         ? 1
                                         : 0);
@@ -1625,7 +1637,7 @@
 // STA iface names start with idx 0.
 // Primary STA iface will always be 0.
 std::string WifiChip::allocateStaIfaceName() {
-    return allocateApOrStaIfaceName(0);
+    return allocateApOrStaIfaceName(IfaceType::STA, 0);
 }
 
 bool WifiChip::writeRingbufferFilesInternal() {
@@ -1661,6 +1673,17 @@
     return true;
 }
 
+std::string WifiChip::getWlanIfaceNameWithType(IfaceType type, unsigned idx) {
+    std::string ifname;
+
+    // let the legacy hal override the interface name
+    legacy_hal::wifi_error err =
+        legacy_hal_.lock()->getSupportedIfaceName((uint32_t)type, ifname);
+    if (err == legacy_hal::WIFI_SUCCESS) return ifname;
+
+    return getWlanIfaceName(idx);
+}
+
 }  // namespace implementation
 }  // namespace V1_5
 }  // namespace wifi
diff --git a/wifi/1.5/default/wifi_chip.h b/wifi/1.5/default/wifi_chip.h
index 36c191c..5f1d9e8 100644
--- a/wifi/1.5/default/wifi_chip.h
+++ b/wifi/1.5/default/wifi_chip.h
@@ -50,7 +50,7 @@
  */
 class WifiChip : public V1_4::IWifiChip {
    public:
-    WifiChip(ChipId chip_id,
+    WifiChip(ChipId chip_id, bool is_primary,
              const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
              const std::weak_ptr<mode_controller::WifiModeController>
                  mode_controller,
@@ -256,10 +256,11 @@
     bool isStaApConcurrencyAllowedInCurrentMode();
     bool isDualApAllowedInCurrentMode();
     std::string getFirstActiveWlanIfaceName();
-    std::string allocateApOrStaIfaceName(uint32_t start_idx);
+    std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx);
     std::string allocateApIfaceName();
     std::string allocateStaIfaceName();
     bool writeRingbufferFilesInternal();
+    std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
 
     ChipId chip_id_;
     std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
diff --git a/wifi/1.5/default/wifi_feature_flags.cpp b/wifi/1.5/default/wifi_feature_flags.cpp
index 151d473..9f91bd7 100644
--- a/wifi/1.5/default/wifi_feature_flags.cpp
+++ b/wifi/1.5/default/wifi_feature_flags.cpp
@@ -139,6 +139,13 @@
      ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
 #endif
 };
+
+static const std::vector<IWifiChip::ChipMode> kChipModesSecondary{
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP
+    {chip_mode_ids::kV3, ChipIfaceCombination::make_vec(
+                             {WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP})},
+#endif
+};
 #undef STA
 #undef AP
 #undef P2P
@@ -154,8 +161,9 @@
 
 WifiFeatureFlags::WifiFeatureFlags() {}
 
-std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes() {
-    return kChipModes;
+std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes(
+    bool is_primary) {
+    return (is_primary) ? kChipModes : kChipModesSecondary;
 }
 
 }  // namespace feature_flags
diff --git a/wifi/1.5/default/wifi_feature_flags.h b/wifi/1.5/default/wifi_feature_flags.h
index 73d18ec..cb68b8c 100644
--- a/wifi/1.5/default/wifi_feature_flags.h
+++ b/wifi/1.5/default/wifi_feature_flags.h
@@ -42,7 +42,8 @@
     WifiFeatureFlags();
     virtual ~WifiFeatureFlags() = default;
 
-    virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes();
+    virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes(
+        bool is_primary);
 };
 
 }  // namespace feature_flags
diff --git a/wifi/1.5/default/wifi_legacy_hal.cpp b/wifi/1.5/default/wifi_legacy_hal.cpp
index 4070568..6ee8937 100644
--- a/wifi/1.5/default/wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal.cpp
@@ -36,7 +36,8 @@
 static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
 static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
 static constexpr uint32_t kMaxRingBuffers = 10;
-static constexpr uint32_t kMaxStopCompleteWaitMs = 100;
+// need a long timeout (1000ms) for chips that unload their driver.
+static constexpr uint32_t kMaxStopCompleteWaitMs = 1000;
 static constexpr char kDriverPropName[] = "wlan.driver.status";
 
 // Helper function to create a non-const char* for legacy Hal API's.
@@ -54,6 +55,7 @@
 namespace V1_5 {
 namespace implementation {
 namespace legacy_hal {
+
 // Legacy HAL functions accept "C" style function pointers, so use global
 // functions to pass to the legacy HAL function and store the corresponding
 // std::function methods to be invoked.
@@ -344,26 +346,20 @@
 // End of the free-standing "C" style callbacks.
 
 WifiLegacyHal::WifiLegacyHal(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
-    : global_handle_(nullptr),
+    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+    const wifi_hal_fn& fn, bool is_primary)
+    : global_func_table_(fn),
+      global_handle_(nullptr),
       awaiting_event_loop_termination_(false),
       is_started_(false),
-      iface_tool_(iface_tool) {}
+      iface_tool_(iface_tool),
+      is_primary_(is_primary) {}
 
 wifi_error WifiLegacyHal::initialize() {
     LOG(DEBUG) << "Initialize legacy HAL";
-    // TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
-    // for now is this function call which we can directly call.
-    if (!initHalFuncTableWithStubs(&global_func_table_)) {
-        LOG(ERROR)
-            << "Failed to initialize legacy hal function table with stubs";
-        return WIFI_ERROR_UNKNOWN;
-    }
-    wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
-    if (status != WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to initialize legacy hal function table";
-    }
-    return status;
+    // this now does nothing, since HAL function table is provided
+    // to the constructor
+    return WIFI_SUCCESS;
 }
 
 wifi_error WifiLegacyHal::start() {
@@ -380,13 +376,17 @@
         LOG(ERROR) << "Timed out awaiting driver ready";
         return status;
     }
-    property_set(kDriverPropName, "ok");
+
+    if (is_primary_) {
+        property_set(kDriverPropName, "ok");
+
+        if (!iface_tool_.lock()->SetWifiUpState(true)) {
+            LOG(ERROR) << "Failed to set WiFi interface up";
+            return WIFI_ERROR_UNKNOWN;
+        }
+    }
 
     LOG(DEBUG) << "Starting legacy HAL";
-    if (!iface_tool_.lock()->SetWifiUpState(true)) {
-        LOG(ERROR) << "Failed to set WiFi interface up";
-        return WIFI_ERROR_UNKNOWN;
-    }
     status = global_func_table_.wifi_initialize(&global_handle_);
     if (status != WIFI_SUCCESS || !global_handle_) {
         LOG(ERROR) << "Failed to retrieve global handle";
@@ -419,7 +419,7 @@
         // Invalidate all the internal pointers now that the HAL is
         // stopped.
         invalidate();
-        iface_tool_.lock()->SetWifiUpState(false);
+        if (is_primary_) iface_tool_.lock()->SetWifiUpState(false);
         on_stop_complete_user_callback();
         is_started_ = false;
     };
@@ -488,12 +488,21 @@
 
 std::pair<wifi_error, uint32_t> WifiLegacyHal::getSupportedFeatureSet(
     const std::string& iface_name) {
-    feature_set set;
+    feature_set set = 0, chip_set = 0;
+    wifi_error status = WIFI_SUCCESS;
+
     static_assert(sizeof(set) == sizeof(uint64_t),
                   "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<uint32_t>(set)};
+    wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
+
+    global_func_table_.wifi_get_chip_feature_set(
+        global_handle_, &chip_set); /* ignore error, chip_set will stay 0 */
+
+    if (iface_handle) {
+        status = global_func_table_.wifi_get_supported_feature_set(iface_handle,
+                                                                   &set);
+    }
+    return {status, static_cast<uint32_t>(set | chip_set)};
 }
 
 std::pair<wifi_error, PacketFilterCapabilities>
@@ -845,10 +854,15 @@
 
 std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
     const std::string& iface_name) {
-    uint32_t supported_feature_flags;
-    wifi_error status =
-        global_func_table_.wifi_get_logger_supported_feature_set(
-            getIfaceHandle(iface_name), &supported_feature_flags);
+    uint32_t supported_feature_flags = 0;
+    wifi_error status = WIFI_SUCCESS;
+
+    wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
+
+    if (iface_handle) {
+        status = global_func_table_.wifi_get_logger_supported_feature_set(
+            iface_handle, &supported_feature_flags);
+    }
     return {status, supported_feature_flags};
 }
 
@@ -1485,6 +1499,17 @@
     return status;
 }
 
+wifi_error WifiLegacyHal::getSupportedIfaceName(uint32_t iface_type,
+                                                std::string& ifname) {
+    std::array<char, IFNAMSIZ> buffer;
+
+    wifi_error res = global_func_table_.wifi_get_supported_iface_name(
+        global_handle_, (uint32_t)iface_type, buffer.data(), buffer.size());
+    if (res == WIFI_SUCCESS) ifname = buffer.data();
+
+    return res;
+}
+
 void WifiLegacyHal::invalidate() {
     global_handle_ = nullptr;
     iface_name_to_handle_.clear();
diff --git a/wifi/1.5/default/wifi_legacy_hal.h b/wifi/1.5/default/wifi_legacy_hal.h
index ae520a8..2984a00 100644
--- a/wifi/1.5/default/wifi_legacy_hal.h
+++ b/wifi/1.5/default/wifi_legacy_hal.h
@@ -173,7 +173,8 @@
  */
 class WifiLegacyHal {
    public:
-    WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+    WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+                  const wifi_hal_fn& fn, bool is_primary);
     virtual ~WifiLegacyHal() = default;
 
     // Initialize the legacy HAL function table.
@@ -379,6 +380,7 @@
     virtual wifi_error createVirtualInterface(const std::string& ifname,
                                               wifi_interface_type iftype);
     virtual wifi_error deleteVirtualInterface(const std::string& ifname);
+    wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname);
 
    private:
     // Retrieve interface handles for all the available interfaces.
@@ -408,6 +410,11 @@
     // Flag to indicate if the legacy HAL has been started.
     bool is_started_;
     std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+    // flag to indicate if this HAL is for the primary chip. This is used
+    // in order to avoid some hard-coded behavior used with older HALs,
+    // such as bring wlan0 interface up/down on start/stop HAL.
+    // it may be removed once vendor HALs are updated.
+    bool is_primary_;
 };
 
 }  // namespace legacy_hal
diff --git a/wifi/1.5/default/wifi_legacy_hal_factory.cpp b/wifi/1.5/default/wifi_legacy_hal_factory.cpp
new file mode 100644
index 0000000..fbaa284
--- /dev/null
+++ b/wifi/1.5/default/wifi_legacy_hal_factory.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2020 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 <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+#include <dlfcn.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+
+#include "wifi_legacy_hal_factory.h"
+#include "wifi_legacy_hal_stubs.h"
+
+namespace {
+static constexpr char kVendorHalsDescPath[] = "/vendor/etc/wifi/vendor_hals";
+static constexpr char kVendorHalsDescExt[] = ".xml";
+static constexpr uint32_t kVendorHalsDescVersion = 1;
+
+bool isDirectory(struct dirent* entryPtr) {
+    bool isDir = false;
+    if (entryPtr->d_type != DT_UNKNOWN && entryPtr->d_type != DT_LNK) {
+        isDir = (entryPtr->d_type == DT_DIR);
+    } else {
+        struct stat entryStat;
+        stat(entryPtr->d_name, &entryStat);
+        isDir = S_ISDIR(entryStat.st_mode);
+    }
+    return isDir;
+}
+
+bool isFileExtension(const char* name, const char* ext) {
+    if (name == NULL) return false;
+    if (ext == NULL) return false;
+
+    size_t extLen = strlen(ext);
+    size_t nameLen = strlen(name);
+
+    if (extLen > nameLen) return false;
+
+    if (strncmp(name + nameLen - extLen, ext, extLen) != 0) return false;
+
+    return true;
+}
+};  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_5 {
+namespace implementation {
+namespace legacy_hal {
+
+WifiLegacyHalFactory::WifiLegacyHalFactory(
+    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+    : iface_tool_(iface_tool) {}
+
+std::vector<std::shared_ptr<WifiLegacyHal>> WifiLegacyHalFactory::getHals() {
+    if (legacy_hals_.empty()) {
+        if (!initVendorHalDescriptorFromLinked())
+            initVendorHalsDescriptorList();
+        for (auto& desc : descs_) {
+            std::shared_ptr<WifiLegacyHal> hal =
+                std::make_shared<WifiLegacyHal>(iface_tool_, desc.fn,
+                                                desc.primary);
+            legacy_hals_.push_back(hal);
+        }
+    }
+
+    return legacy_hals_;
+}
+
+bool WifiLegacyHalFactory::initVendorHalDescriptorFromLinked() {
+    wifi_hal_lib_desc desc;
+
+    if (!initLinkedHalFunctionTable(&desc.fn)) return false;
+
+    desc.primary = true;
+    desc.handle = NULL;
+    descs_.push_back(desc);
+    return true;
+}
+
+bool WifiLegacyHalFactory::initLinkedHalFunctionTable(wifi_hal_fn* hal_fn) {
+    init_wifi_vendor_hal_func_table_t initfn;
+
+    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(
+        RTLD_DEFAULT, "init_wifi_vendor_hal_func_table");
+    if (!initfn) {
+        LOG(INFO) << "no vendor HAL library linked, will try dynamic load";
+        return false;
+    }
+
+    if (!initHalFuncTableWithStubs(hal_fn)) {
+        LOG(ERROR) << "Can not initialize the basic function pointer table";
+        return false;
+    }
+
+    if (initfn(hal_fn) != WIFI_SUCCESS) {
+        LOG(ERROR) << "Can not initialize the vendor function pointer table";
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Overall structure of the HAL descriptor XML schema
+ *
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <WifiVendorHal version="1">
+ * <path>/vendor/lib64/libwifi-hal-qcom.so</path>
+ * <primary>1</primary>
+ * </WifiVendorHal>
+ */
+void WifiLegacyHalFactory::initVendorHalsDescriptorList() {
+    xmlDocPtr xml;
+    xmlNodePtr node, cnode;
+    char* version;
+    std::string path;
+    xmlChar* value;
+    wifi_hal_lib_desc desc;
+
+    LOG(INFO) << "processing vendor HALs descriptions in "
+              << kVendorHalsDescPath;
+    DIR* dirPtr = ::opendir(kVendorHalsDescPath);
+    if (dirPtr == NULL) {
+        LOG(ERROR) << "failed to open " << kVendorHalsDescPath;
+        return;
+    }
+    for (struct dirent* entryPtr = ::readdir(dirPtr); entryPtr != NULL;
+         entryPtr = ::readdir(dirPtr)) {
+        if (isDirectory(entryPtr)) continue;
+
+        if (!isFileExtension(entryPtr->d_name, kVendorHalsDescExt))
+            continue;  // only process .xml files
+
+        LOG(INFO) << "processing config file: " << entryPtr->d_name;
+
+        std::string fullPath(kVendorHalsDescPath);
+        fullPath.append("/");
+        fullPath.append(entryPtr->d_name);
+        xml = xmlReadFile(fullPath.c_str(), "UTF-8", XML_PARSE_RECOVER);
+        if (!xml) {
+            LOG(ERROR) << "failed to parse: " << entryPtr->d_name
+                       << " skipping...";
+            continue;
+        }
+        node = xmlDocGetRootElement(xml);
+        if (!node) {
+            LOG(ERROR) << "empty config file: " << entryPtr->d_name
+                       << " skipping...";
+            goto skip;
+        }
+        if (xmlStrcmp(node->name, BAD_CAST "WifiVendorHal")) {
+            LOG(ERROR) << "bad config, root element not WifiVendorHal: "
+                       << entryPtr->d_name << " skipping...";
+            goto skip;
+        }
+        version = (char*)xmlGetProp(node, BAD_CAST "version");
+        if (!version || strtoul(version, NULL, 0) != kVendorHalsDescVersion) {
+            LOG(ERROR) << "conf file: " << entryPtr->d_name
+                       << "must have version: " << kVendorHalsDescVersion
+                       << ", skipping...";
+            goto skip;
+        }
+        cnode = node->children;
+        path.clear();
+        desc.primary = false;
+        while (cnode) {
+            if (!xmlStrcmp(cnode->name, BAD_CAST "path")) {
+                value = xmlNodeListGetString(xml, cnode->children, 1);
+                if (value) path = (char*)value;
+                xmlFree(value);
+            } else if (!xmlStrcmp(cnode->name, BAD_CAST "primary")) {
+                value = xmlNodeListGetString(xml, cnode->children, 1);
+                desc.primary = !xmlStrcmp(value, BAD_CAST "1");
+                xmlFree(value);
+            }
+            cnode = cnode->next;
+        }
+        if (path.empty()) {
+            LOG(ERROR) << "hal library path not provided in: "
+                       << entryPtr->d_name << ", skipping...";
+            goto skip;
+        }
+        if (loadVendorHalLib(path, desc)) {
+            if (desc.primary)
+                descs_.insert(descs_.begin(), desc);
+            else
+                descs_.push_back(desc);
+        }
+    skip:
+        xmlFreeDoc(xml);
+    }
+    ::closedir(dirPtr);
+}
+
+bool WifiLegacyHalFactory::loadVendorHalLib(const std::string& path,
+                                            wifi_hal_lib_desc& desc) {
+    void* h = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
+    init_wifi_vendor_hal_func_table_t initfn;
+    wifi_error res;
+
+    if (!h) {
+        LOG(ERROR) << "failed to open vendor hal library: " << path;
+        return false;
+    }
+    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(
+        h, "init_wifi_vendor_hal_func_table");
+    if (!initfn) {
+        LOG(ERROR) << "init_wifi_vendor_hal_func_table not found in: " << path;
+        goto out_err;
+    }
+
+    if (!initHalFuncTableWithStubs(&desc.fn)) {
+        LOG(ERROR) << "Can not initialize the basic function pointer table";
+        goto out_err;
+    }
+    res = initfn(&desc.fn);
+    if (res != WIFI_SUCCESS) {
+        LOG(ERROR) << "failed to initialize the vendor func table in: " << path
+                   << " error: " << res;
+        goto out_err;
+    }
+
+    res = desc.fn.wifi_early_initialize();
+    // vendor HALs which do not implement early_initialize will return
+    // WIFI_ERROR_NOT_SUPPORTED, treat this as success.
+    if (res != WIFI_SUCCESS && res != WIFI_ERROR_NOT_SUPPORTED) {
+        LOG(ERROR) << "early initialization failed in: " << path
+                   << " error: " << res;
+        goto out_err;
+    }
+
+    desc.handle = h;
+    return true;
+out_err:
+    dlclose(h);
+    return false;
+}
+
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_5
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.5/default/wifi_legacy_hal_factory.h b/wifi/1.5/default/wifi_legacy_hal_factory.h
new file mode 100644
index 0000000..e3440fa
--- /dev/null
+++ b/wifi/1.5/default/wifi_legacy_hal_factory.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 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 WIFI_LEGACY_HAL_FACTORY_H_
+#define WIFI_LEGACY_HAL_FACTORY_H_
+
+#include <wifi_system/interface_tool.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_5 {
+namespace implementation {
+// This is in a separate namespace to prevent typename conflicts between
+// the legacy HAL types and the HIDL interface types.
+namespace legacy_hal {
+/**
+ * Class that creates WifiLegacyHal objects for vendor HALs in the system.
+ */
+class WifiLegacyHalFactory {
+   public:
+    WifiLegacyHalFactory(
+        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+    virtual ~WifiLegacyHalFactory() = default;
+
+    std::vector<std::shared_ptr<WifiLegacyHal>> getHals();
+
+   private:
+    typedef struct {
+        wifi_hal_fn fn;
+        bool primary;
+        void* handle;
+    } wifi_hal_lib_desc;
+
+    bool initVendorHalDescriptorFromLinked();
+    void initVendorHalsDescriptorList();
+    bool initLinkedHalFunctionTable(wifi_hal_fn* hal_fn);
+    bool loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc);
+
+    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+    std::vector<wifi_hal_lib_desc> descs_;
+    std::vector<std::shared_ptr<WifiLegacyHal>> legacy_hals_;
+};
+
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_5
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_LEGACY_HAL_FACTORY_H_
diff --git a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
index 73b5856..a1122e9 100644
--- a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
@@ -144,6 +144,10 @@
     populateStubFor(&hal_fn->wifi_map_dscp_access_category);
     populateStubFor(&hal_fn->wifi_reset_dscp_mapping);
     populateStubFor(&hal_fn->wifi_set_subsystem_restart_handler);
+    populateStubFor(&hal_fn->wifi_get_supported_iface_name);
+    populateStubFor(&hal_fn->wifi_early_initialize);
+    populateStubFor(&hal_fn->wifi_get_chip_feature_set);
+
     return true;
 }
 }  // namespace legacy_hal