From e9d1e7d384e557667e83228a9c3b89936b35a37e Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 4 Nov 2020 11:44:16 -0800 Subject: [PATCH] wifi: Add STA + STA HIDL API's Add the HIDL API's + shim + VTS tests. Bug: 170305665 Test: atest VtsHalWifiV1_3TargetTest VtsHalWifiV1_5TargetTest Change-Id: I26ada11aebfe8082bfda251cf7e6990e0aa08a06 --- .../functional/wifi_sta_iface_hidl_test.cpp | 15 +- wifi/1.5/Android.bp | 1 + wifi/1.5/IWifiChip.hal | 79 ++++++++++ wifi/1.5/IWifiNanIface.hal | 9 +- wifi/1.5/IWifiNanIfaceEventCallback.hal | 4 +- wifi/1.5/IWifiStaIface.hal | 44 ++++++ wifi/1.5/default/hidl_struct_util.cpp | 51 +++--- wifi/1.5/default/hidl_struct_util.h | 4 +- .../tests/hidl_struct_util_unit_tests.cpp | 43 ++--- wifi/1.5/default/wifi_chip.cpp | 31 +++- wifi/1.5/default/wifi_chip.h | 12 +- wifi/1.5/default/wifi_legacy_hal.cpp | 11 ++ wifi/1.5/default/wifi_legacy_hal.h | 4 + wifi/1.5/default/wifi_legacy_hal_stubs.cpp | 2 + wifi/1.5/default/wifi_sta_iface.cpp | 14 +- wifi/1.5/default/wifi_sta_iface.h | 8 +- wifi/1.5/types.hal | 42 ++++- wifi/1.5/vts/functional/Android.bp | 23 +++ .../vts/functional/wifi_chip_hidl_test.cpp | 149 ++++++++++++++++++ .../functional/wifi_sta_iface_hidl_test.cpp | 117 ++++++++++++++ 20 files changed, 606 insertions(+), 57 deletions(-) create mode 100644 wifi/1.5/IWifiStaIface.hal create mode 100644 wifi/1.5/vts/functional/wifi_chip_hidl_test.cpp create mode 100644 wifi/1.5/vts/functional/wifi_sta_iface_hidl_test.cpp diff --git a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp index 22efe0875a..78e62390eb 100644 --- a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp +++ b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -88,7 +89,6 @@ TEST_P(WifiStaIfaceHidlTest, GetLinkLayerStats_1_3) { // No-op if link layer stats is not supported. return; } - // Enable link layer stats collection. EXPECT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(wifi_sta_iface_, enableLinkLayerStatsCollection, true) @@ -96,8 +96,17 @@ TEST_P(WifiStaIfaceHidlTest, GetLinkLayerStats_1_3) { // Retrieve link layer stats. const auto& status_and_stats = HIDL_INVOKE(wifi_sta_iface_, getLinkLayerStats_1_3); - EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_stats.first.code); - EXPECT_GT(status_and_stats.second.timeStampInMs, 0u); + sp staIface1_5 = + android::hardware::wifi::V1_5::IWifiStaIface::castFrom(wifi_sta_iface_); + if (staIface1_5.get() == nullptr) { + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_stats.first.code); + EXPECT_GT(status_and_stats.second.timeStampInMs, 0u); + } else { + // not supported on 1.5 HAL. + EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, + status_and_stats.first.code); + } + // Disable link layer stats collection. EXPECT_EQ( WifiStatusCode::SUCCESS, diff --git a/wifi/1.5/Android.bp b/wifi/1.5/Android.bp index ecb0a35f18..5a62a3a832 100644 --- a/wifi/1.5/Android.bp +++ b/wifi/1.5/Android.bp @@ -9,6 +9,7 @@ hidl_interface { "IWifiChip.hal", "IWifiNanIface.hal", "IWifiNanIfaceEventCallback.hal", + "IWifiStaIface.hal", ], interfaces: [ "android.hardware.wifi@1.0", diff --git a/wifi/1.5/IWifiChip.hal b/wifi/1.5/IWifiChip.hal index 5243baf7f3..dcc927900a 100644 --- a/wifi/1.5/IWifiChip.hal +++ b/wifi/1.5/IWifiChip.hal @@ -35,6 +35,53 @@ interface IWifiChip extends @1.4::IWifiChip { WIGIG = 1 << 14, }; + /** + * When there are 2 or more simultaneous STA connections, this use case hint indicates what + * use-case is being enabled by the framework. This use case hint can be used by the firmware + * to modify various firmware configurations like: + * - Allowed BSSIDs the firmware can choose for the initial connection/roaming attempts. + * - Duty cycle to choose for the 2 STA connections if the radio is in MCC mode. + * - Whether roaming, APF and other offloads needs to be enabled or not. + * Note: + * - This will be invoked before an active wifi connection is established on the second + * interface. + * - This use-case hint is implicitly void when the second STA interface is brought down. + */ + enum MultiStaUseCase : uint8_t { + /** + * Usage: + * - This will be sent down for make before break use-case. + * - Platform is trying to speculatively connect to a second network and evaluate it without + * disrupting the primary connection. + * Requirements for Firmware: + * - Do not reduce the number of tx/rx chains of primary connection. + * - If using MCC, should set the MCC duty cycle of the primary connection to be higher than + * the secondary connection (maybe 70/30 split). + * - Should pick the best BSSID for the secondary STA (disregard the chip mode) independent + * of the primary STA: + * - Don’t optimize for DBS vs MCC/SCC + * - Should not impact the primary connection’s bssid selection: + * - Don’t downgrade chains of the existing primary connection. + * - Don’t optimize for DBS vs MCC/SCC. + */ + DUAL_STA_TRANSIENT_PREFER_PRIMARY = 0, + /** + * Usage: + * - This will be sent down for any app requested peer to peer connections. + * - In this case, both the connections needs to be allocated equal resources. + * - For the peer to peer use case, BSSID for the secondary connection will be chosen by the + * framework. + * + * Requirements for Firmware: + * - Can choose MCC or DBS mode depending on the MCC efficiency and HW capability. + * - If using MCC, set the MCC duty cycle of the primary connection to be equal to the + * secondary connection. + * - Prefer BSSID candidates which will help provide the best "overall" performance for both + * the connections. + */ + DUAL_STA_NON_TRANSIENT_UNBIASED = 1, + }; + /** * Get the capabilities supported by this chip. * @@ -48,4 +95,36 @@ interface IWifiChip extends @1.4::IWifiChip { */ getCapabilities_1_5() generates (WifiStatus status, bitfield capabilities); + + /** + * Invoked to indicate that the provided iface is the primary STA iface when there are more + * than 1 STA iface concurrently active. + * Note: If the wifi firmware/chip cannot support multiple instances of any offload + * (like roaming, APF, rssi threshold, etc), the firmware should ensure that these + * offloads are at least enabled for the primary interface. If the new primary interface is + * already connected to a network, the firmware must switch all the offloads on + * this new interface without disconnecting. + * + * @param ifname Name of the STA iface. + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|, + * |WifiStatusCode.ERROR_INVALID_ARGS| + */ + setMultiStaPrimaryConnection(string ifName) generates (WifiStatus status); + + /** + * Invoked to indicate the STA + STA use-case that is active. + * + * Refer to documentation of |MultiStaUseCase| for details. + * + * @param useCase Use case that is active. + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|, + * |WifiStatusCode.ERROR_INVALID_ARGS| + */ + setMultiStaUseCase(MultiStaUseCase useCase) generates (WifiStatus status); }; diff --git a/wifi/1.5/IWifiNanIface.hal b/wifi/1.5/IWifiNanIface.hal index 93257b525a..d7c15de9d8 100644 --- a/wifi/1.5/IWifiNanIface.hal +++ b/wifi/1.5/IWifiNanIface.hal @@ -92,13 +92,12 @@ interface IWifiNanIface extends @1.4::IWifiNanIface { * |WifiStatusCode.SUCCESS|, * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID| */ - registerEventCallback_1_5(IWifiNanIfaceEventCallback callback) - generates (WifiStatus status); + registerEventCallback_1_5(IWifiNanIfaceEventCallback callback) generates (WifiStatus status); /** * Get NAN capabilities. Asynchronous response is with * |IWifiNanIfaceEventCallback.notifyCapabilitiesResponse|. - + * * Note: supersedes the @1.0::IWifiNanIface.getCapabilitiesRequest() method which is deprecated * as of HAL version 1.5. * @@ -109,5 +108,5 @@ interface IWifiNanIface extends @1.4::IWifiNanIface { * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, * |WifiStatusCode.ERROR_UNKNOWN| */ - getCapabilitiesRequest_1_5(CommandIdShort cmdId) generates (WifiStatus status); -}; \ No newline at end of file + getCapabilitiesRequest_1_5(CommandIdShort cmdId) generates (WifiStatus status); +}; diff --git a/wifi/1.5/IWifiNanIfaceEventCallback.hal b/wifi/1.5/IWifiNanIfaceEventCallback.hal index 867c03c47e..046b702f4f 100644 --- a/wifi/1.5/IWifiNanIfaceEventCallback.hal +++ b/wifi/1.5/IWifiNanIfaceEventCallback.hal @@ -40,5 +40,5 @@ interface IWifiNanIfaceEventCallback extends @1.2::IWifiNanIfaceEventCallback { * @param capabilities Capability data. */ oneway notifyCapabilitiesResponse_1_5(CommandIdShort id, WifiNanStatus status, - NanCapabilities capabilities); -}; \ No newline at end of file + NanCapabilities capabilities); +}; diff --git a/wifi/1.5/IWifiStaIface.hal b/wifi/1.5/IWifiStaIface.hal new file mode 100644 index 0000000000..e9d411e00b --- /dev/null +++ b/wifi/1.5/IWifiStaIface.hal @@ -0,0 +1,44 @@ +/* + * Copyright 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. + */ + +package android.hardware.wifi@1.5; + +import @1.0::WifiStatus; +import @1.3::IWifiStaIface; + +/** + * Interface used to represent a single STA iface. + * + * IWifiChip.createStaIface() must return a @1.5::IWifiStaIface when supported. + */ +interface IWifiStaIface extends @1.3::IWifiStaIface { + /** + * Retrieve the latest link layer stats. + * Must fail if |StaIfaceCapabilityMask.LINK_LAYER_STATS| is not set or if + * link layer stats collection hasn't been explicitly enabled. + * + * @return status WifiStatus of the operation. + * Possible status codes: + * |WifiStatusCode.SUCCESS|, + * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|, + * |WifiStatusCode.ERROR_NOT_SUPPORTED|, + * |WifiStatusCode.ERROR_NOT_STARTED|, + * |WifiStatusCode.ERROR_NOT_AVAILABLE|, + * |WifiStatusCode.ERROR_UNKNOWN| + * @return stats Instance of |LinkLayerStats|. + */ + getLinkLayerStats_1_5() generates (WifiStatus status, StaLinkLayerStats stats); +}; diff --git a/wifi/1.5/default/hidl_struct_util.cpp b/wifi/1.5/default/hidl_struct_util.cpp index 578f3e2f0f..83d06fe398 100644 --- a/wifi/1.5/default/hidl_struct_util.cpp +++ b/wifi/1.5/default/hidl_struct_util.cpp @@ -866,46 +866,48 @@ bool convertLegacyLinkLayerRadioStatsToHidl( bool convertLegacyLinkLayerStatsToHidl( const legacy_hal::LinkLayerStats& legacy_stats, - V1_3::StaLinkLayerStats* hidl_stats) { + StaLinkLayerStats* hidl_stats) { if (!hidl_stats) { return false; } *hidl_stats = {}; // iface legacy_stats conversion. - hidl_stats->iface.beaconRx = legacy_stats.iface.beacon_rx; - hidl_stats->iface.avgRssiMgmt = legacy_stats.iface.rssi_mgmt; - hidl_stats->iface.wmeBePktStats.rxMpdu = + hidl_stats->iface.V1_0.beaconRx = legacy_stats.iface.beacon_rx; + hidl_stats->iface.V1_0.avgRssiMgmt = legacy_stats.iface.rssi_mgmt; + hidl_stats->iface.V1_0.wmeBePktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu; - hidl_stats->iface.wmeBePktStats.txMpdu = + hidl_stats->iface.V1_0.wmeBePktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu; - hidl_stats->iface.wmeBePktStats.lostMpdu = + hidl_stats->iface.V1_0.wmeBePktStats.lostMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost; - hidl_stats->iface.wmeBePktStats.retries = + hidl_stats->iface.V1_0.wmeBePktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries; - hidl_stats->iface.wmeBkPktStats.rxMpdu = + hidl_stats->iface.V1_0.wmeBkPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu; - hidl_stats->iface.wmeBkPktStats.txMpdu = + hidl_stats->iface.V1_0.wmeBkPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu; - hidl_stats->iface.wmeBkPktStats.lostMpdu = + hidl_stats->iface.V1_0.wmeBkPktStats.lostMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost; - hidl_stats->iface.wmeBkPktStats.retries = + hidl_stats->iface.V1_0.wmeBkPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries; - hidl_stats->iface.wmeViPktStats.rxMpdu = + hidl_stats->iface.V1_0.wmeViPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu; - hidl_stats->iface.wmeViPktStats.txMpdu = + hidl_stats->iface.V1_0.wmeViPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu; - hidl_stats->iface.wmeViPktStats.lostMpdu = + hidl_stats->iface.V1_0.wmeViPktStats.lostMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost; - hidl_stats->iface.wmeViPktStats.retries = + hidl_stats->iface.V1_0.wmeViPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries; - hidl_stats->iface.wmeVoPktStats.rxMpdu = + hidl_stats->iface.V1_0.wmeVoPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu; - hidl_stats->iface.wmeVoPktStats.txMpdu = + hidl_stats->iface.V1_0.wmeVoPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu; - hidl_stats->iface.wmeVoPktStats.lostMpdu = + hidl_stats->iface.V1_0.wmeVoPktStats.lostMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost; - hidl_stats->iface.wmeVoPktStats.retries = + hidl_stats->iface.V1_0.wmeVoPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries; + hidl_stats->iface.timeSliceDutyCycleInPercent = + legacy_stats.iface.info.time_slicing_duty_cycle_percent; // radio legacy_stats conversion. std::vector hidl_radios_stats; for (const auto& legacy_radio_stats : legacy_stats.radios) { @@ -2787,6 +2789,17 @@ legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy( } CHECK(false); } + +legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy( + IWifiChip::MultiStaUseCase use_case) { + switch (use_case) { + case IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY: + return legacy_hal::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY; + case IWifiChip::MultiStaUseCase::DUAL_STA_NON_TRANSIENT_UNBIASED: + return legacy_hal::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED; + } + CHECK(false); +} } // namespace hidl_struct_util } // namespace implementation } // namespace V1_5 diff --git a/wifi/1.5/default/hidl_struct_util.h b/wifi/1.5/default/hidl_struct_util.h index b0b1d22dfe..49d8a1213e 100644 --- a/wifi/1.5/default/hidl_struct_util.h +++ b/wifi/1.5/default/hidl_struct_util.h @@ -69,6 +69,8 @@ bool convertLegacyWifiMacInfosToHidl( hidl_radio_mode_infos); legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy( IfaceType hidl_interface_type); +legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy( + IWifiChip::MultiStaUseCase use_case); // STA iface conversion methods. bool convertLegacyFeaturesToHidlStaCapabilities( @@ -96,7 +98,7 @@ bool convertLegacyVectorOfCachedGscanResultsToHidl( std::vector* hidl_scan_datas); bool convertLegacyLinkLayerStatsToHidl( const legacy_hal::LinkLayerStats& legacy_stats, - V1_3::StaLinkLayerStats* hidl_stats); + StaLinkLayerStats* hidl_stats); bool convertLegacyRoamingCapabilitiesToHidl( const legacy_hal::wifi_roaming_capabilities& legacy_caps, StaRoamingCapabilities* hidl_caps); diff --git a/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp index 81eb14e8e0..ea84c61f66 100644 --- a/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp +++ b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp @@ -154,6 +154,8 @@ TEST_F(HidlStructUtilTest, canConvertLegacyLinkLayerStatsToHidl) { legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand(); legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand(); + legacy_stats.iface.info.time_slicing_duty_cycle_percent = rand(); + for (auto& radio : legacy_stats.radios) { radio.stats.on_time = rand(); radio.stats.tx_time = rand(); @@ -182,46 +184,49 @@ TEST_F(HidlStructUtilTest, canConvertLegacyLinkLayerStatsToHidl) { radio.channel_stats.push_back(channel_stat2); } - V1_3::StaLinkLayerStats converted{}; + V1_5::StaLinkLayerStats converted{}; hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats, &converted); - EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.beaconRx); - EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.avgRssiMgmt); + EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.V1_0.beaconRx); + EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.V1_0.avgRssiMgmt); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu, - converted.iface.wmeBePktStats.rxMpdu); + converted.iface.V1_0.wmeBePktStats.rxMpdu); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu, - converted.iface.wmeBePktStats.txMpdu); + converted.iface.V1_0.wmeBePktStats.txMpdu); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost, - converted.iface.wmeBePktStats.lostMpdu); + converted.iface.V1_0.wmeBePktStats.lostMpdu); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries, - converted.iface.wmeBePktStats.retries); + converted.iface.V1_0.wmeBePktStats.retries); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu, - converted.iface.wmeBkPktStats.rxMpdu); + converted.iface.V1_0.wmeBkPktStats.rxMpdu); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu, - converted.iface.wmeBkPktStats.txMpdu); + converted.iface.V1_0.wmeBkPktStats.txMpdu); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost, - converted.iface.wmeBkPktStats.lostMpdu); + converted.iface.V1_0.wmeBkPktStats.lostMpdu); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries, - converted.iface.wmeBkPktStats.retries); + converted.iface.V1_0.wmeBkPktStats.retries); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu, - converted.iface.wmeViPktStats.rxMpdu); + converted.iface.V1_0.wmeViPktStats.rxMpdu); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu, - converted.iface.wmeViPktStats.txMpdu); + converted.iface.V1_0.wmeViPktStats.txMpdu); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost, - converted.iface.wmeViPktStats.lostMpdu); + converted.iface.V1_0.wmeViPktStats.lostMpdu); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries, - converted.iface.wmeViPktStats.retries); + converted.iface.V1_0.wmeViPktStats.retries); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu, - converted.iface.wmeVoPktStats.rxMpdu); + converted.iface.V1_0.wmeVoPktStats.rxMpdu); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu, - converted.iface.wmeVoPktStats.txMpdu); + converted.iface.V1_0.wmeVoPktStats.txMpdu); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost, - converted.iface.wmeVoPktStats.lostMpdu); + converted.iface.V1_0.wmeVoPktStats.lostMpdu); EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries, - converted.iface.wmeVoPktStats.retries); + converted.iface.V1_0.wmeVoPktStats.retries); + + EXPECT_EQ(legacy_stats.iface.info.time_slicing_duty_cycle_percent, + converted.iface.timeSliceDutyCycleInPercent); EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size()); for (size_t i = 0; i < legacy_stats.radios.size(); i++) { diff --git a/wifi/1.5/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp index ebff722859..1c238c8ec0 100644 --- a/wifi/1.5/default/wifi_chip.cpp +++ b/wifi/1.5/default/wifi_chip.cpp @@ -678,6 +678,20 @@ Return WifiChip::registerEventCallback_1_4( hidl_status_cb, event_callback); } +Return WifiChip::setMultiStaPrimaryConnection( + const hidl_string& ifname, setMultiStaPrimaryConnection_cb hidl_status_cb) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::setMultiStaPrimaryConnectionInternal, + hidl_status_cb, ifname); +} + +Return WifiChip::setMultiStaUseCase( + MultiStaUseCase use_case, setMultiStaUseCase_cb hidl_status_cb) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::setMultiStaUseCaseInternal, + hidl_status_cb, use_case); +} + void WifiChip::invalidateAndRemoveAllIfaces() { invalidateAndClearAll(ap_ifaces_); invalidateAndClearAll(nan_ifaces_); @@ -1016,7 +1030,7 @@ WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) { return createWifiStatus(WifiStatusCode::SUCCESS); } -std::pair> +std::pair> WifiChip::createStaIfaceInternal() { if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; @@ -1050,7 +1064,7 @@ WifiChip::getStaIfaceNamesInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)}; } -std::pair> WifiChip::getStaIfaceInternal( +std::pair> WifiChip::getStaIfaceInternal( const std::string& ifname) { const auto iface = findUsingName(sta_ifaces_, ifname); if (!iface.get()) { @@ -1295,6 +1309,19 @@ WifiStatus WifiChip::registerEventCallbackInternal_1_4( return createWifiStatus(WifiStatusCode::SUCCESS); } +WifiStatus WifiChip::setMultiStaPrimaryConnectionInternal( + const std::string& ifname) { + auto legacy_status = + legacy_hal_.lock()->multiStaSetPrimaryConnection(ifname); + return createWifiStatusFromLegacyError(legacy_status); +} + +WifiStatus WifiChip::setMultiStaUseCaseInternal(MultiStaUseCase use_case) { + auto legacy_status = legacy_hal_.lock()->multiStaSetUseCase( + hidl_struct_util::convertHidlMultiStaUseCaseToLegacy(use_case)); + return createWifiStatusFromLegacyError(legacy_status); +} + WifiStatus WifiChip::handleChipConfiguration( /* NONNULL */ std::unique_lock* lock, ChipModeId mode_id) { diff --git a/wifi/1.5/default/wifi_chip.h b/wifi/1.5/default/wifi_chip.h index 8cc0452df9..693d480bda 100644 --- a/wifi/1.5/default/wifi_chip.h +++ b/wifi/1.5/default/wifi_chip.h @@ -163,6 +163,12 @@ class WifiChip : public V1_5::IWifiChip { Return registerEventCallback_1_4( const sp& event_callback, registerEventCallback_1_4_cb hidl_status_cb) override; + Return setMultiStaPrimaryConnection( + const hidl_string& ifname, + setMultiStaPrimaryConnection_cb hidl_status_cb) override; + Return setMultiStaUseCase( + MultiStaUseCase use_case, + setMultiStaUseCase_cb hidl_status_cb) override; private: void invalidateAndRemoveAllIfaces(); @@ -201,9 +207,9 @@ class WifiChip : public V1_5::IWifiChip { std::pair> getP2pIfaceInternal( const std::string& ifname); WifiStatus removeP2pIfaceInternal(const std::string& ifname); - std::pair> createStaIfaceInternal(); + std::pair> createStaIfaceInternal(); std::pair> getStaIfaceNamesInternal(); - std::pair> getStaIfaceInternal( + std::pair> getStaIfaceInternal( const std::string& ifname); WifiStatus removeStaIfaceInternal(const std::string& ifname); std::pair> @@ -233,6 +239,8 @@ class WifiChip : public V1_5::IWifiChip { createRttControllerInternal_1_4(const sp& bound_iface); WifiStatus registerEventCallbackInternal_1_4( const sp& event_callback); + WifiStatus setMultiStaPrimaryConnectionInternal(const std::string& ifname); + WifiStatus setMultiStaUseCaseInternal(MultiStaUseCase use_case); WifiStatus handleChipConfiguration( std::unique_lock* lock, ChipModeId mode_id); diff --git a/wifi/1.5/default/wifi_legacy_hal.cpp b/wifi/1.5/default/wifi_legacy_hal.cpp index 398bfac3f6..76e718b74a 100644 --- a/wifi/1.5/default/wifi_legacy_hal.cpp +++ b/wifi/1.5/default/wifi_legacy_hal.cpp @@ -1510,6 +1510,17 @@ wifi_error WifiLegacyHal::getSupportedIfaceName(uint32_t iface_type, return res; } +wifi_error WifiLegacyHal::multiStaSetPrimaryConnection( + const std::string& ifname) { + return global_func_table_.wifi_multi_sta_set_primary_connection( + global_handle_, getIfaceHandle(ifname)); +} + +wifi_error WifiLegacyHal::multiStaSetUseCase(wifi_multi_sta_use_case use_case) { + return global_func_table_.wifi_multi_sta_set_use_case(global_handle_, + use_case); +} + 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 9a06efd342..555c540102 100644 --- a/wifi/1.5/default/wifi_legacy_hal.h +++ b/wifi/1.5/default/wifi_legacy_hal.h @@ -382,6 +382,10 @@ class WifiLegacyHal { virtual wifi_error deleteVirtualInterface(const std::string& ifname); wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname); + // STA + STA functions + virtual wifi_error multiStaSetPrimaryConnection(const std::string& ifname); + virtual wifi_error multiStaSetUseCase(wifi_multi_sta_use_case use_case); + private: // Retrieve interface handles for all the available interfaces. wifi_error retrieveIfaceHandles(); diff --git a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp index a1122e97f2..71d2ddf688 100644 --- a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp +++ b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp @@ -147,6 +147,8 @@ bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) { populateStubFor(&hal_fn->wifi_get_supported_iface_name); populateStubFor(&hal_fn->wifi_early_initialize); populateStubFor(&hal_fn->wifi_get_chip_feature_set); + populateStubFor(&hal_fn->wifi_multi_sta_set_primary_connection); + populateStubFor(&hal_fn->wifi_multi_sta_set_use_case); return true; } diff --git a/wifi/1.5/default/wifi_sta_iface.cpp b/wifi/1.5/default/wifi_sta_iface.cpp index 04087fda7a..f3dcfc5bca 100644 --- a/wifi/1.5/default/wifi_sta_iface.cpp +++ b/wifi/1.5/default/wifi_sta_iface.cpp @@ -163,6 +163,13 @@ Return WifiStaIface::getLinkLayerStats_1_3( hidl_status_cb); } +Return WifiStaIface::getLinkLayerStats_1_5( + getLinkLayerStats_1_5_cb hidl_status_cb) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getLinkLayerStatsInternal_1_5, + hidl_status_cb); +} + Return WifiStaIface::startRssiMonitoring( uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi, startRssiMonitoring_cb hidl_status_cb) { @@ -470,6 +477,11 @@ WifiStaIface::getLinkLayerStatsInternal() { std::pair WifiStaIface::getLinkLayerStatsInternal_1_3() { + return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}}; +} + +std::pair +WifiStaIface::getLinkLayerStatsInternal_1_5() { legacy_hal::wifi_error legacy_status; legacy_hal::LinkLayerStats legacy_stats; std::tie(legacy_status, legacy_stats) = @@ -477,7 +489,7 @@ WifiStaIface::getLinkLayerStatsInternal_1_3() { if (legacy_status != legacy_hal::WIFI_SUCCESS) { return {createWifiStatusFromLegacyError(legacy_status), {}}; } - V1_3::StaLinkLayerStats hidl_stats; + V1_5::StaLinkLayerStats hidl_stats; if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats, &hidl_stats)) { return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}}; diff --git a/wifi/1.5/default/wifi_sta_iface.h b/wifi/1.5/default/wifi_sta_iface.h index 7695f3c9f1..94873c9494 100644 --- a/wifi/1.5/default/wifi_sta_iface.h +++ b/wifi/1.5/default/wifi_sta_iface.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include "hidl_callback_util.h" #include "wifi_iface_util.h" @@ -35,7 +35,7 @@ using namespace android::hardware::wifi::V1_0; /** * HIDL interface object used to control a STA Iface instance. */ -class WifiStaIface : public V1_3::IWifiStaIface { +class WifiStaIface : public V1_5::IWifiStaIface { public: WifiStaIface(const std::string& ifname, const std::weak_ptr legacy_hal, @@ -78,6 +78,8 @@ class WifiStaIface : public V1_3::IWifiStaIface { getLinkLayerStats_cb hidl_status_cb) override; Return getLinkLayerStats_1_3( getLinkLayerStats_1_3_cb hidl_status_cb) override; + Return getLinkLayerStats_1_5( + getLinkLayerStats_1_5_cb hidl_status_cb) override; Return startRssiMonitoring( uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi, startRssiMonitoring_cb hidl_status_cb) override; @@ -138,6 +140,8 @@ class WifiStaIface : public V1_3::IWifiStaIface { std::pair getLinkLayerStatsInternal(); std::pair getLinkLayerStatsInternal_1_3(); + std::pair + getLinkLayerStatsInternal_1_5(); WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi); WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id); diff --git a/wifi/1.5/types.hal b/wifi/1.5/types.hal index 5873f79b3b..3fbec82658 100644 --- a/wifi/1.5/types.hal +++ b/wifi/1.5/types.hal @@ -16,10 +16,14 @@ package android.hardware.wifi@1.5; +import @1.0::StaLinkLayerIfaceStats; +import @1.0::StaLinkLayerIfacePacketStats; +import @1.0::TimeStampInMs; import @1.0::WifiBand; import @1.0::NanCipherSuiteType; import @1.0::NanCapabilities; import @1.2::NanConfigRequestSupplemental; +import @1.3::StaLinkLayerRadioStats; /** * Wifi bands defined in 80211 spec. @@ -48,6 +52,7 @@ struct NanConfigRequestSupplemental { * Baseline information as defined in HAL 1.2. */ @1.2::NanConfigRequestSupplemental V1_2; + /** * Controls whether NAN instant communication mode is enabled. */ @@ -62,8 +67,43 @@ struct NanCapabilities { * Baseline information as defined in HAL 1.0. */ @1.0::NanCapabilities V1_0; + /** * Flag to indicate id instant communication mode is supported. */ bool instantCommunicationModeSupportFlag; -}; \ No newline at end of file +}; + +/** + * Iface statistics for the current connection. + */ +struct StaLinkLayerIfaceStats { + /** + * Baseline information as defined in HAL 1.0. + */ + @1.0::StaLinkLayerIfaceStats V1_0; + + /** + * Duty cycle for the iface. + * if this iface is being served using time slicing on a radio with one or more ifaces + * (i.e MCC), then the duty cycle assigned to this iface in %. + * If not using time slicing (i.e SCC or DBS), set to 100. + */ + uint8_t timeSliceDutyCycleInPercent; +}; + +/** + * Link layer stats retrieved via |getLinkLayerStats|. + */ +struct StaLinkLayerStats { + StaLinkLayerIfaceStats iface; + + vec radios; + + /** + * TimeStamp for each stats sample. + * This is the absolute milliseconds from boot when these stats were + * sampled. + */ + TimeStampInMs timeStampInMs; +}; diff --git a/wifi/1.5/vts/functional/Android.bp b/wifi/1.5/vts/functional/Android.bp index a7ba498103..eb595c9082 100644 --- a/wifi/1.5/vts/functional/Android.bp +++ b/wifi/1.5/vts/functional/Android.bp @@ -14,6 +14,29 @@ // limitations under the License. // +cc_test { + name: "VtsHalWifiV1_5TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "wifi_chip_hidl_test.cpp", + "wifi_sta_iface_hidl_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "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", + "libwifi-system-iface", + ], + test_suites: [ + "general-tests", + "vts", + ], +} + // These tests are split out so that they can be conditioned on presence of the // "android.hardware.wifi.aware" feature. cc_test { diff --git a/wifi/1.5/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.5/vts/functional/wifi_chip_hidl_test.cpp new file mode 100644 index 0000000000..eeaa7e0d38 --- /dev/null +++ b/wifi/1.5/vts/functional/wifi_chip_hidl_test.cpp @@ -0,0 +1,149 @@ +/* + * 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 +#include + +#undef NAN // NAN is defined in bionic/libc/include/math.h:38 + +#include +#include +#include +#include +#include +#include +#include + +#include "wifi_hidl_call_util.h" +#include "wifi_hidl_test_utils.h" + +using ::android::sp; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::wifi::V1_0::ChipModeId; +using ::android::hardware::wifi::V1_0::IfaceType; +using ::android::hardware::wifi::V1_0::IWifiIface; +using ::android::hardware::wifi::V1_0::IWifiStaIface; +using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus; +using ::android::hardware::wifi::V1_0::WifiStatus; +using ::android::hardware::wifi::V1_0::WifiStatusCode; +using ::android::hardware::wifi::V1_4::IWifiChipEventCallback; +using ::android::hardware::wifi::V1_5::IWifiChip; + +/** + * Fixture to use for all Wifi chip HIDL interface tests. + */ +class WifiChipHidlTest : public ::testing::TestWithParam { + public: + virtual void SetUp() override { + // Make sure to start with a clean state + stopWifi(GetInstanceName()); + + wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName())); + ASSERT_NE(nullptr, wifi_chip_.get()); + } + + virtual void TearDown() override { stopWifi(GetInstanceName()); } + + protected: + // Helper function to configure the Chip in one of the supported modes. + // Most of the non-mode-configuration-related methods require chip + // to be first configured. + ChipModeId configureChipForIfaceType(IfaceType type, bool expectSuccess) { + ChipModeId mode_id; + EXPECT_EQ(expectSuccess, + configureChipToSupportIfaceType(wifi_chip_, type, &mode_id)); + return mode_id; + } + + WifiStatusCode createStaIface(sp* sta_iface) { + const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createStaIface); + *sta_iface = status_and_iface.second; + return status_and_iface.first.code; + } + + std::string getIfaceName(const sp& iface) { + const auto& status_and_name = HIDL_INVOKE(iface, getName); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_name.first.code); + return status_and_name.second; + } + + std::vector> create2StaIfacesIfPossible() { + configureChipForIfaceType(IfaceType::STA, true); + sp iface1, iface2; + EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&iface1)); + EXPECT_NE(nullptr, iface1.get()); + + // Try to create 2nd iface + auto status = createStaIface(&iface2); + if (status != WifiStatusCode::SUCCESS) { + return {iface1}; + } + EXPECT_NE(nullptr, iface2.get()); + return {iface1, iface2}; + } + + sp wifi_chip_; + + private: + std::string GetInstanceName() { return GetParam(); } +}; + +/* + * setMultiStaPrimaryConnection + * + * Only run if device supports 2 STA ifaces. + */ +TEST_P(WifiChipHidlTest, setMultiStaPrimaryConnection) { + auto ifaces = create2StaIfacesIfPossible(); + if (ifaces.size() < 2) { + GTEST_SKIP() << "Device does not support more than 1 STA concurrently"; + } + + const auto& status = HIDL_INVOKE(wifi_chip_, setMultiStaPrimaryConnection, + getIfaceName(ifaces.front())); + if (status.code != WifiStatusCode::SUCCESS) { + EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code); + } +} + +/* + * setMultiStaUseCase + * + * Only run if device supports 2 STA ifaces. + */ +TEST_P(WifiChipHidlTest, setMultiStaUseCase) { + auto ifaces = create2StaIfacesIfPossible(); + if (ifaces.size() < 2) { + GTEST_SKIP() << "Device does not support more than 1 STA concurrently"; + } + + const auto& status = HIDL_INVOKE( + wifi_chip_, setMultiStaUseCase, + IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY); + if (status.code != WifiStatusCode::SUCCESS) { + EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code); + } +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest); +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiChipHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + ::android::hardware::wifi::V1_5::IWifi::descriptor)), + android::hardware::PrintInstanceNameToString); diff --git a/wifi/1.5/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.5/vts/functional/wifi_sta_iface_hidl_test.cpp new file mode 100644 index 0000000000..8cc3300324 --- /dev/null +++ b/wifi/1.5/vts/functional/wifi_sta_iface_hidl_test.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Staache 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 +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "wifi_hidl_call_util.h" +#include "wifi_hidl_test_utils.h" + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::wifi::V1_0::WifiStatus; +using ::android::hardware::wifi::V1_0::WifiStatusCode; +using ::android::hardware::wifi::V1_5::IWifiChip; +using ::android::hardware::wifi::V1_5::IWifiStaIface; + +/** + * Fixture to use for all STA Iface HIDL interface tests. + */ +class WifiStaIfaceHidlTest : public ::testing::TestWithParam { + public: + virtual void SetUp() override { + // Make sure to start with a clean state + stopWifi(GetInstanceName()); + + wifi_sta_iface_ = + IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName())); + ASSERT_NE(nullptr, wifi_sta_iface_.get()); + } + + virtual void TearDown() override { stopWifi(GetInstanceName()); } + + protected: + bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) { + const auto& status_and_caps = + HIDL_INVOKE(wifi_sta_iface_, getCapabilities); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code); + return (status_and_caps.second & cap_mask) != 0; + } + + WifiStatusCode createStaIface(sp* sta_iface) { + sp wifi_chip = + IWifiChip::castFrom(getWifiChip(GetInstanceName())); + EXPECT_NE(nullptr, wifi_chip.get()); + const auto& status_and_iface = HIDL_INVOKE(wifi_chip, createStaIface); + *sta_iface = IWifiStaIface::castFrom(status_and_iface.second); + return status_and_iface.first.code; + } + + sp wifi_sta_iface_; + + private: + std::string GetInstanceName() { return GetParam(); } +}; + +/* + * GetLinkLayerStats_1_5 + * Ensures that calls to get link layer stats V1_5 will retrieve a non-empty + * StaLinkLayerStats after link layer stats collection is enabled. + */ +TEST_P(WifiStaIfaceHidlTest, GetLinkLayerStats_1_5) { + if (!isCapabilitySupported( + IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) { + // No-op if link layer stats is not supported. + return; + } + + // Enable link layer stats collection. + EXPECT_EQ(WifiStatusCode::SUCCESS, + HIDL_INVOKE(wifi_sta_iface_, enableLinkLayerStatsCollection, true) + .code); + // Retrieve link layer stats. + const auto& status_and_stats = + HIDL_INVOKE(wifi_sta_iface_, getLinkLayerStats_1_5); + EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_stats.first.code); + EXPECT_GT(status_and_stats.second.timeStampInMs, 0u); + // Try to create 2nd iface. If yes, it should fill in the duty cycle field. + sp iface; + auto status = createStaIface(&iface); + if (status == WifiStatusCode::SUCCESS) { + EXPECT_GT(status_and_stats.second.iface.timeSliceDutyCycleInPercent, + 0u); + } + // Disable link layer stats collection. + EXPECT_EQ( + WifiStatusCode::SUCCESS, + HIDL_INVOKE(wifi_sta_iface_, disableLinkLayerStatsCollection).code); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceHidlTest); +INSTANTIATE_TEST_SUITE_P( + PerInstance, WifiStaIfaceHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames( + ::android::hardware::wifi::V1_5::IWifi::descriptor)), + android::hardware::PrintInstanceNameToString);