Merge "Camera: Add ICameraDevice@3.6 subinterface"
diff --git a/current.txt b/current.txt
index 71e9f05..8d068d0 100644
--- a/current.txt
+++ b/current.txt
@@ -661,14 +661,14 @@
 0589e410f519e36514e7ece18f283f022df0f70efd2c12821d822f67f74aba98 android.hardware.identity@1.0::types
 bbeee9604128ede83ee755b67e73b5ad29e6e1dbac9ec41fea6ffe2745b0c50a android.hardware.identity@1.0::IIdentityCredential
 96ce8aad80f4c476f25261f790d357c117e79e18474c7dadd850dac704bbe65e android.hardware.identity@1.0::IIdentityCredentialStore
-6e1e28a96c90ba78d47257faea3f3bb4e6360affbbfa5822f0dc31211f9266ff android.hardware.identity@1.0::IWritableIdentityCredential
+8da9c938e58f7d636ddd2f92c646f99d9a9e79612e6441b6380ab12744251873 android.hardware.identity@1.0::IWritableIdentityCredential
 27ae3724053940462114228872b3ffaf0b8e6177d5ba97f5a76339d12b8a99dd android.hardware.keymaster@4.1::IKeymasterDevice
 adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation
 ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardware.keymaster@4.1::types
 df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
 a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
 65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer
-d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardware.neuralnetworks@1.3::IDevice
+9b41dd49e2dcc2ecb4243d03f8421d72494ada5cf2945bff88f0019eeca56923 android.hardware.neuralnetworks@1.3::IDevice
 4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback
 2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
 237b23b126a66f3432658020fed78cdd06ba6297459436fe6bae0ba753370833 android.hardware.neuralnetworks@1.3::IPreparedModel
diff --git a/identity/1.0/IWritableIdentityCredential.hal b/identity/1.0/IWritableIdentityCredential.hal
index b1ce00d..f26f763 100644
--- a/identity/1.0/IWritableIdentityCredential.hal
+++ b/identity/1.0/IWritableIdentityCredential.hal
@@ -26,20 +26,56 @@
      * characteristics to an issuing authority.  Must not be called more than once.
      *
      * The certificate chain must be generated using Keymaster Attestation
-     * (see https://source.android.com/security/keystore/attestation) and must also
-     * have the Tag::IDENTITY_CREDENTIAL_KEY tag from KeyMaster 4.1 set. This tag indicates
-     * that this key is an Identity Credential key (which can only sign/MAC very
-     * specific messages) and not an Android Keystore key (which can be used to sign/MAC
-     * anything).
+     * (see https://source.android.com/security/keystore/attestation) with the
+     * following additional requirements:
+     *
+     *  - The attestationVersion field in the attestation extension must be at least 3.
+     *
+     *  - The attestationSecurityLevel field must be set to either Software (0),
+     *    TrustedEnvironment (1), or StrongBox (2) depending on how attestation is
+     *    implemented. Only the default AOSP implementation of this HAL may use
+     *    value 0 (additionally, this implementation must not be used on production
+     *    devices).
+     *
+     *  - The keymasterVersion field in the attestation extension must be set to (10*major + minor)
+     *    where major and minor are the Identity Credential interface major and minor versions.
+     *    Specifically for this version of the interface (1.0) this value is 10.
+     *
+     *  - The keymasterSecurityLevel field in the attestation extension must be set to
+     *    either Software (0), TrustedEnvironment (1), or StrongBox (2) depending on how
+     *    the Trusted Application backing the HAL implementation is implemented. Only
+     *    the default AOSP implementation of this HAL may use value 0 (additionally, this
+     *    implementation must not be used on production devices)
+     *
+     *  - The attestationChallenge field must be set to the passed-in challenge.
+     *
+     *  - The uniqueId field must be empty.
+     *
+     *  - The softwareEnforced field in the attestation extension must include
+     *    Tag::ATTESTATION_APPLICATION_ID which must be set to the bytes of the passed-in
+     *    attestationApplicationId.
+     *
+     *  - The teeEnforced field in the attestation extension must include
+     *    Tag::IDENTITY_CREDENTIAL_KEY. This tag indicates that the key is an Identity
+     *    Credential key (which can only sign/MAC very specific messages) and not an Android
+     *    Keystore key (which can be used to sign/MAC anything).
+     *
+     * Additional authorizations may be needed in the softwareEnforced and teeEnforced
+     * fields - the above is not an exhaustive list.
+     *
+     * @param attestationApplicationId is the DER encoded value to be stored
+     *     in Tag::ATTESTATION_APPLICATION_ID. This schema is described in
+     *     https://developer.android.com/training/articles/security-key-attestation#certificate_schema_attestationid
      *
      * @param attestationChallenge a challenge set by the issuer to ensure freshness.
      *
      * @return result is OK on success, FAILED if an error occurred.
      *
-     * @return certificate is the X.509 certificate chain for the credentialKey
+     * @return certificateChain is the X.509 certificate chain for the credentialKey
      */
-    getAttestationCertificate(vec<uint8_t> attestationChallenge)
-        generates(Result result, vec<uint8_t> certificate);
+    getAttestationCertificate(vec<uint8_t> attestationApplicationId,
+                              vec<uint8_t> attestationChallenge)
+        generates(Result result, vec<vec<uint8_t>> certificateChain);
 
     /**
      * Start the personalization process.
diff --git a/identity/1.0/default/WritableIdentityCredential.cpp b/identity/1.0/default/WritableIdentityCredential.cpp
index 548b4c0..4c39f85 100644
--- a/identity/1.0/default/WritableIdentityCredential.cpp
+++ b/identity/1.0/default/WritableIdentityCredential.cpp
@@ -108,7 +108,12 @@
     return true;
 }
 
+// TODO: use |attestationApplicationId| and |attestationChallenge| and also
+//       ensure the returned certificate chain satisfy the requirements listed in
+//       the docs for IWritableIdentityCredential::getAttestationCertificate()
+//
 Return<void> WritableIdentityCredential::getAttestationCertificate(
+        const hidl_vec<uint8_t>& /* attestationApplicationId */,
         const hidl_vec<uint8_t>& /* attestationChallenge */,
         getAttestationCertificate_cb _hidl_cb) {
     // For now, we dynamically generate an attestion key on each and every
@@ -181,7 +186,16 @@
     certificateChain.insert(certificateChain.end(), attestationKeyCertificate.value().begin(),
                             attestationKeyCertificate.value().end());
 
-    _hidl_cb(support::resultOK(), certificateChain);
+    optional<vector<vector<uint8_t>>> splitCertChain =
+            support::certificateChainSplit(certificateChain);
+    if (!splitCertChain) {
+        _hidl_cb(support::result(ResultCode::FAILED, "Error splitting certificate chain"), {});
+        return Void();
+    }
+    hidl_vec<hidl_vec<uint8_t>> ret;
+    ret.resize(splitCertChain.value().size());
+    std::copy(splitCertChain.value().begin(), splitCertChain.value().end(), ret.begin());
+    _hidl_cb(support::resultOK(), ret);
     return Void();
 }
 
diff --git a/identity/1.0/default/WritableIdentityCredential.h b/identity/1.0/default/WritableIdentityCredential.h
index 9f4e303..b1deb16 100644
--- a/identity/1.0/default/WritableIdentityCredential.h
+++ b/identity/1.0/default/WritableIdentityCredential.h
@@ -51,7 +51,8 @@
 
     // Methods from ::android::hardware::identity::IWritableIdentityCredential
     // follow.
-    Return<void> getAttestationCertificate(const hidl_vec<uint8_t>& attestationChallenge,
+    Return<void> getAttestationCertificate(const hidl_vec<uint8_t>& attestationApplicationId,
+                                           const hidl_vec<uint8_t>& attestationChallenge,
                                            getAttestationCertificate_cb _hidl_cb) override;
 
     Return<void> startPersonalization(uint16_t accessControlProfileCount,
diff --git a/identity/1.0/vts/functional/VtsHalIdentityCredentialTargetTest.cpp b/identity/1.0/vts/functional/VtsHalIdentityCredentialTargetTest.cpp
index 903e912..88b06df 100644
--- a/identity/1.0/vts/functional/VtsHalIdentityCredentialTargetTest.cpp
+++ b/identity/1.0/vts/functional/VtsHalIdentityCredentialTargetTest.cpp
@@ -201,13 +201,18 @@
     ASSERT_NE(writableCredential, nullptr);
 
     string challenge = "attestationChallenge";
+    // TODO: set it to something random and check it's in the cert chain
+    vector<uint8_t> attestationApplicationId = {};
     vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
     vector<uint8_t> attestationCertificate;
     writableCredential->getAttestationCertificate(
-            attestationChallenge,
-            [&](const Result& _result, const hidl_vec<uint8_t>& _attestationCertificate) {
+            attestationApplicationId, attestationChallenge,
+            [&](const Result& _result, const hidl_vec<hidl_vec<uint8_t>>& _splitCertChain) {
                 result = _result;
-                attestationCertificate = _attestationCertificate;
+                vector<vector<uint8_t>> splitCerts;
+                std::copy(_splitCertChain.begin(), _splitCertChain.end(),
+                          std::back_inserter(splitCerts));
+                attestationCertificate = support::certificateChainJoin(splitCerts);
             });
     EXPECT_EQ("", result.message);
     ASSERT_EQ(ResultCode::OK, result.code);
diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal
index 610db79..4931539 100644
--- a/neuralnetworks/1.3/IDevice.hal
+++ b/neuralnetworks/1.3/IDevice.hal
@@ -260,11 +260,6 @@
      * the model, the callback object must be invoked with the appropriate
      * ErrorStatus value and nullptr for the IPreparedModel.
      *
-     * The model is prepared with a priority. This priority is relative to other
-     * prepared models owned by the same client. Higher priority executions may
-     * use more compute resources than lower priority executions, and may
-     * preempt or starve lower priority executions.
-     *
      * prepareModelFromCache_1_3 can be called with an optional deadline. If the
      * model is not able to prepared before the provided deadline, the model
      * preparation must be aborted, and either {@link
@@ -284,8 +279,6 @@
      * used with different shapes of inputs on different (possibly concurrent)
      * executions.
      *
-     * @param priority The priority of the prepared model relative to other
-     *     prepared models owned by the client.
      * @param deadline The time by which the model must be prepared. If the
      *     model cannot be prepared by the deadline, the preparation must be
      *     aborted.
@@ -318,7 +311,7 @@
      *       met
      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      */
-    prepareModelFromCache_1_3(Priority priority, OptionalTimePoint deadline,
+    prepareModelFromCache_1_3(OptionalTimePoint deadline,
                               vec<handle> modelCache, vec<handle> dataCache,
                               uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token,
                               IPreparedModelCallback callback)
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index 576e524..0bd24da 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -370,7 +370,7 @@
         sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
         hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
         Return<ErrorStatus> prepareLaunchStatus = kDevice->prepareModelFromCache_1_3(
-                kDefaultPriority, {}, modelCache, dataCache, cacheToken, preparedModelCallback);
+                {}, modelCache, dataCache, cacheToken, preparedModelCallback);
         ASSERT_TRUE(prepareLaunchStatus.isOk());
         if (static_cast<ErrorStatus>(prepareLaunchStatus) != ErrorStatus::NONE) {
             *preparedModel = nullptr;
diff --git a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
index 4e48141..ca64305 100644
--- a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
@@ -75,38 +75,3 @@
             radioRsp_v1_3->rspInfo.error,
             {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
 }
-
-/*
- * Test IRadio.setSystemSelectionChannels() for the response returned.
- *
- * This test is excluded from manifest, due to non-implementation in Q. Tracked by b/130254624.
- */
-TEST_P(RadioHidlTest_v1_3, setSystemSelectionChannels) {
-    serial = GetRandomSerialNumber();
-
-    RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
-                                      .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
-                                      .channels = {1, 2}};
-
-    Return<void> res = radio_v1_3->setSystemSelectionChannels(serial, true, {specifier});
-    ASSERT_OK(res);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial);
-    ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n",
-          toString(radioRsp_v1_3->rspInfo.error).c_str());
-    ASSERT_TRUE(CheckAnyOfErrors(
-            radioRsp_v1_3->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR}));
-
-    if (radioRsp_v1_3->rspInfo.error == RadioError::NONE) {
-        Return<void> res = radio_v1_3->setSystemSelectionChannels(serial, false, {specifier});
-        ASSERT_OK(res);
-        EXPECT_EQ(std::cv_status::no_timeout, wait());
-        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type);
-        EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial);
-        ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n",
-              toString(radioRsp_v1_3->rspInfo.error).c_str());
-        EXPECT_EQ(RadioError::NONE, radioRsp_v1_3->rspInfo.error);
-    }
-}
\ No newline at end of file
diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp
index 4996e35..fd1d5b1 100644
--- a/wifi/1.4/default/hidl_struct_util.cpp
+++ b/wifi/1.4/default/hidl_struct_util.cpp
@@ -2715,6 +2715,21 @@
     }
     return true;
 }
+
+legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
+    IfaceType hidl_interface_type) {
+    switch (hidl_interface_type) {
+        case IfaceType::STA:
+            return legacy_hal::WIFI_INTERFACE_TYPE_STA;
+        case IfaceType::AP:
+            return legacy_hal::WIFI_INTERFACE_TYPE_AP;
+        case IfaceType::P2P:
+            return legacy_hal::WIFI_INTERFACE_TYPE_P2P;
+        case IfaceType::NAN:
+            return legacy_hal::WIFI_INTERFACE_TYPE_NAN;
+    }
+    CHECK(false);
+}
 }  // namespace hidl_struct_util
 }  // namespace implementation
 }  // namespace V1_4
diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h
index d040c1f..929f877 100644
--- a/wifi/1.4/default/hidl_struct_util.h
+++ b/wifi/1.4/default/hidl_struct_util.h
@@ -65,6 +65,8 @@
 bool convertLegacyWifiMacInfosToHidl(
     const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
     std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
+legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
+    IfaceType hidl_interface_type);
 
 // STA iface conversion methods.
 bool convertLegacyFeaturesToHidlStaCapabilities(
diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp
index 3498510..4c9fad1 100644
--- a/wifi/1.4/default/wifi_chip.cpp
+++ b/wifi/1.4/default/wifi_chip.cpp
@@ -797,6 +797,15 @@
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
     std::string ifname = allocateApIfaceName();
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->createVirtualInterface(
+            ifname,
+            hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP));
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to add interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
     sp<WifiApIface> iface = new WifiApIface(ifname, legacy_hal_, iface_util_);
     ap_ifaces_.push_back(iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -835,6 +844,12 @@
     // nan/rtt objects over AP iface. But, there is no harm to do it
     // here and not make that assumption all over the place.
     invalidateAndRemoveDependencies(ifname);
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->deleteVirtualInterface(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to remove interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+    }
     invalidateAndClear(ap_ifaces_, iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
         if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
@@ -944,6 +959,15 @@
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
     std::string ifname = allocateStaIfaceName();
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->createVirtualInterface(
+            ifname,
+            hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::STA));
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to add interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
     sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_, iface_util_);
     sta_ifaces_.push_back(iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -979,6 +1003,12 @@
     }
     // Invalidate & remove any dependent objects first.
     invalidateAndRemoveDependencies(ifname);
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->deleteVirtualInterface(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to remove interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+    }
     invalidateAndClear(sta_ifaces_, iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
         if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp
index 3ca3226..a040c89 100644
--- a/wifi/1.4/default/wifi_legacy_hal.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -19,6 +19,7 @@
 
 #include <android-base/logging.h>
 #include <cutils/properties.h>
+#include <net/if.h>
 
 #include "hidl_sync_util.h"
 #include "wifi_legacy_hal.h"
@@ -1355,6 +1356,7 @@
         LOG(ERROR) << "Failed to enumerate interface handles";
         return status;
     }
+    iface_name_to_handle_.clear();
     for (int i = 0; i < num_iface_handles; ++i) {
         std::array<char, IFNAMSIZ> iface_name_arr = {};
         status = global_func_table_.wifi_get_iface_name(
@@ -1421,6 +1423,39 @@
     return {status, std::move(cached_scan_results)};
 }
 
+wifi_error WifiLegacyHal::createVirtualInterface(const std::string& ifname,
+                                                 wifi_interface_type iftype) {
+    // Create the interface if it doesn't exist. If interface already exist,
+    // Vendor Hal should return WIFI_SUCCESS.
+    wifi_error status = global_func_table_.wifi_virtual_interface_create(
+        global_handle_, ifname.c_str(), iftype);
+    return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::deleteVirtualInterface(const std::string& ifname) {
+    // Delete the interface if it was created dynamically.
+    wifi_error status = global_func_table_.wifi_virtual_interface_delete(
+        global_handle_, ifname.c_str());
+    return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::handleVirtualInterfaceCreateOrDeleteStatus(
+    const std::string& ifname, wifi_error status) {
+    if (status == WIFI_SUCCESS) {
+        // refresh list of handlers now.
+        status = retrieveIfaceHandles();
+    } else if (status == WIFI_ERROR_NOT_SUPPORTED) {
+        // Vendor hal does not implement this API. Such vendor implementations
+        // are expected to create / delete interface by other means.
+
+        // check if interface exists.
+        if (if_nametoindex(ifname.c_str())) {
+            status = retrieveIfaceHandles();
+        }
+    }
+    return status;
+}
+
 void WifiLegacyHal::invalidate() {
     global_handle_ = nullptr;
     iface_name_to_handle_.clear();
diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h
index a7b40a0..72cf197 100644
--- a/wifi/1.4/default/wifi_legacy_hal.h
+++ b/wifi/1.4/default/wifi_legacy_hal.h
@@ -369,6 +369,11 @@
     wifi_error setCountryCode(const std::string& iface_name,
                               std::array<int8_t, 2> code);
 
+    // interface functions.
+    wifi_error createVirtualInterface(const std::string& ifname,
+                                      wifi_interface_type iftype);
+    wifi_error deleteVirtualInterface(const std::string& ifname);
+
    private:
     // Retrieve interface handles for all the available interfaces.
     wifi_error retrieveIfaceHandles();
@@ -380,6 +385,9 @@
     std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
     getGscanCachedResults(const std::string& iface_name);
     void invalidate();
+    // Handles wifi (error) status of Virtual interface create/delete
+    wifi_error handleVirtualInterfaceCreateOrDeleteStatus(
+        const std::string& ifname, wifi_error status);
 
     // Global function table of legacy HAL.
     wifi_hal_fn global_func_table_;
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
index bbe470e..6945b4c 100644
--- a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
@@ -139,6 +139,8 @@
     populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
     populateStubFor(&hal_fn->wifi_set_latency_mode);
     populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
+    populateStubFor(&hal_fn->wifi_virtual_interface_create);
+    populateStubFor(&hal_fn->wifi_virtual_interface_delete);
     return true;
 }
 }  // namespace legacy_hal