Add StaLinkLayerStats V1_3

Gets additional scan related information from legacy_hal up to
framework.

Bug: 77603419
Test: compile, unit tests
Change-Id: I9c948166b640af192c8e6f85ed6c76719e0937a4
diff --git a/wifi/1.3/Android.bp b/wifi/1.3/Android.bp
index 95fbf83..5e87c1c 100644
--- a/wifi/1.3/Android.bp
+++ b/wifi/1.3/Android.bp
@@ -7,7 +7,9 @@
         enabled: true,
     },
     srcs: [
+        "types.hal",
         "IWifi.hal",
+        "IWifiStaIface.hal",
     ],
     interfaces: [
         "android.hardware.wifi@1.0",
@@ -15,6 +17,10 @@
         "android.hardware.wifi@1.2",
         "android.hidl.base@1.0",
     ],
+    types: [
+      "StaLinkLayerRadioStats",
+      "StaLinkLayerStats",
+    ],
     gen_java: true,
 }
 
diff --git a/wifi/1.3/IWifiStaIface.hal b/wifi/1.3/IWifiStaIface.hal
new file mode 100644
index 0000000..0dc6128
--- /dev/null
+++ b/wifi/1.3/IWifiStaIface.hal
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 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.3;
+
+import @1.0::WifiStatus;
+import @1.2::IWifiStaIface;
+
+/**
+ * Interface used to represent a single STA iface.
+ *
+ * IWifiChip.createStaIface() may return a @1.3::IWifiStaIface when supported.
+ */
+interface IWifiStaIface extends @1.2::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_3() generates (WifiStatus status, StaLinkLayerStats stats);
+};
diff --git a/wifi/1.3/default/hidl_struct_util.cpp b/wifi/1.3/default/hidl_struct_util.cpp
index e793236..c88ddaa 100644
--- a/wifi/1.3/default/hidl_struct_util.cpp
+++ b/wifi/1.3/default/hidl_struct_util.cpp
@@ -785,7 +785,7 @@
 
 bool convertLegacyLinkLayerStatsToHidl(
     const legacy_hal::LinkLayerStats& legacy_stats,
-    StaLinkLayerStats* hidl_stats) {
+    V1_3::StaLinkLayerStats* hidl_stats) {
     if (!hidl_stats) {
         return false;
     }
@@ -826,16 +826,26 @@
     hidl_stats->iface.wmeVoPktStats.retries =
         legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
     // radio legacy_stats conversion.
-    std::vector<StaLinkLayerRadioStats> hidl_radios_stats;
+    std::vector<V1_3::StaLinkLayerRadioStats> hidl_radios_stats;
     for (const auto& legacy_radio_stats : legacy_stats.radios) {
-        StaLinkLayerRadioStats hidl_radio_stats;
-        hidl_radio_stats.onTimeInMs = legacy_radio_stats.stats.on_time;
-        hidl_radio_stats.txTimeInMs = legacy_radio_stats.stats.tx_time;
-        hidl_radio_stats.rxTimeInMs = legacy_radio_stats.stats.rx_time;
-        hidl_radio_stats.onTimeInMsForScan =
+        V1_3::StaLinkLayerRadioStats hidl_radio_stats;
+        hidl_radio_stats.V1_0.onTimeInMs = legacy_radio_stats.stats.on_time;
+        hidl_radio_stats.V1_0.txTimeInMs = legacy_radio_stats.stats.tx_time;
+        hidl_radio_stats.V1_0.rxTimeInMs = legacy_radio_stats.stats.rx_time;
+        hidl_radio_stats.V1_0.onTimeInMsForScan =
             legacy_radio_stats.stats.on_time_scan;
-        hidl_radio_stats.txTimeInMsPerLevel =
+        hidl_radio_stats.V1_0.txTimeInMsPerLevel =
             legacy_radio_stats.tx_time_per_levels;
+        hidl_radio_stats.onTimeInMsForNanScan =
+            legacy_radio_stats.stats.on_time_nbd;
+        hidl_radio_stats.onTimeInMsForBgScan =
+            legacy_radio_stats.stats.on_time_gscan;
+        hidl_radio_stats.onTimeInMsForRoamScan =
+            legacy_radio_stats.stats.on_time_roam_scan;
+        hidl_radio_stats.onTimeInMsForPnoScan =
+            legacy_radio_stats.stats.on_time_pno_scan;
+        hidl_radio_stats.onTimeInMsForHs20Scan =
+            legacy_radio_stats.stats.on_time_hs20;
         hidl_radios_stats.push_back(hidl_radio_stats);
     }
     hidl_stats->radios = hidl_radios_stats;
diff --git a/wifi/1.3/default/hidl_struct_util.h b/wifi/1.3/default/hidl_struct_util.h
index e2ba00c..8df484d 100644
--- a/wifi/1.3/default/hidl_struct_util.h
+++ b/wifi/1.3/default/hidl_struct_util.h
@@ -24,6 +24,7 @@
 #include <android/hardware/wifi/1.2/IWifiChip.h>
 #include <android/hardware/wifi/1.2/IWifiChipEventCallback.h>
 #include <android/hardware/wifi/1.2/types.h>
+#include <android/hardware/wifi/1.3/types.h>
 
 #include "wifi_legacy_hal.h"
 
@@ -89,7 +90,7 @@
     std::vector<StaScanData>* hidl_scan_datas);
 bool convertLegacyLinkLayerStatsToHidl(
     const legacy_hal::LinkLayerStats& legacy_stats,
-    StaLinkLayerStats* hidl_stats);
+    V1_3::StaLinkLayerStats* hidl_stats);
 bool convertLegacyRoamingCapabilitiesToHidl(
     const legacy_hal::wifi_roaming_capabilities& legacy_caps,
     StaRoamingCapabilities* hidl_caps);
diff --git a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
index 4cd3719..d600a2b 100644
--- a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
+++ b/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
@@ -126,6 +126,118 @@
     EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
               hidl_iface_info2.channel);
 }
+
+TEST_F(HidlStructUtilTest, canConvertLegacyLinkLayerStatsToHidl) {
+    legacy_hal::LinkLayerStats legacy_stats{};
+    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    legacy_stats.iface.beacon_rx = rand();
+    legacy_stats.iface.rssi_mgmt = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand();
+
+    for (auto& radio : legacy_stats.radios) {
+        radio.stats.on_time = rand();
+        radio.stats.tx_time = rand();
+        radio.stats.rx_time = rand();
+        radio.stats.on_time_scan = rand();
+        radio.stats.on_time_nbd = rand();
+        radio.stats.on_time_gscan = rand();
+        radio.stats.on_time_roam_scan = rand();
+        radio.stats.on_time_pno_scan = rand();
+        radio.stats.on_time_hs20 = rand();
+        for (int i = 0; i < 4; i++) {
+            radio.tx_time_per_levels.push_back(rand());
+        }
+    }
+
+    V1_3::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.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
+              converted.iface.wmeBePktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
+              converted.iface.wmeBePktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
+              converted.iface.wmeBePktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
+              converted.iface.wmeBePktStats.retries);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
+              converted.iface.wmeBkPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
+              converted.iface.wmeBkPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
+              converted.iface.wmeBkPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
+              converted.iface.wmeBkPktStats.retries);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
+              converted.iface.wmeViPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
+              converted.iface.wmeViPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
+              converted.iface.wmeViPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
+              converted.iface.wmeViPktStats.retries);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
+              converted.iface.wmeVoPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
+              converted.iface.wmeVoPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
+              converted.iface.wmeVoPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
+              converted.iface.wmeVoPktStats.retries);
+
+    EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
+    for (int i = 0; i < legacy_stats.radios.size(); i++) {
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time,
+                  converted.radios[i].V1_0.onTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.tx_time,
+                  converted.radios[i].V1_0.txTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.rx_time,
+                  converted.radios[i].V1_0.rxTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
+                  converted.radios[i].V1_0.onTimeInMsForScan);
+        EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
+                  converted.radios[i].V1_0.txTimeInMsPerLevel.size());
+        for (int j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size();
+             j++) {
+            EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
+                      converted.radios[i].V1_0.txTimeInMsPerLevel[j]);
+        }
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
+                  converted.radios[i].onTimeInMsForNanScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
+                  converted.radios[i].onTimeInMsForBgScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
+                  converted.radios[i].onTimeInMsForRoamScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
+                  converted.radios[i].onTimeInMsForPnoScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
+                  converted.radios[i].onTimeInMsForHs20Scan);
+    }
+}
 }  // namespace implementation
 }  // namespace V1_3
 }  // namespace wifi
diff --git a/wifi/1.3/default/wifi_sta_iface.cpp b/wifi/1.3/default/wifi_sta_iface.cpp
index 63341df..b0fa1ae 100644
--- a/wifi/1.3/default/wifi_sta_iface.cpp
+++ b/wifi/1.3/default/wifi_sta_iface.cpp
@@ -152,6 +152,13 @@
                            hidl_status_cb);
 }
 
+Return<void> WifiStaIface::getLinkLayerStats_1_3(
+    getLinkLayerStats_1_3_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getLinkLayerStatsInternal_1_3,
+                           hidl_status_cb);
+}
+
 Return<void> WifiStaIface::startRssiMonitoring(
     uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
     startRssiMonitoring_cb hidl_status_cb) {
@@ -445,8 +452,13 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
-std::pair<WifiStatus, StaLinkLayerStats>
+std::pair<WifiStatus, V1_0::StaLinkLayerStats>
 WifiStaIface::getLinkLayerStatsInternal() {
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_3::StaLinkLayerStats>
+WifiStaIface::getLinkLayerStatsInternal_1_3() {
     legacy_hal::wifi_error legacy_status;
     legacy_hal::LinkLayerStats legacy_stats;
     std::tie(legacy_status, legacy_stats) =
@@ -454,7 +466,7 @@
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
         return {createWifiStatusFromLegacyError(legacy_status), {}};
     }
-    StaLinkLayerStats hidl_stats;
+    V1_3::StaLinkLayerStats hidl_stats;
     if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
                                                              &hidl_stats)) {
         return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
diff --git a/wifi/1.3/default/wifi_sta_iface.h b/wifi/1.3/default/wifi_sta_iface.h
index 0fc61e2..bc3090f 100644
--- a/wifi/1.3/default/wifi_sta_iface.h
+++ b/wifi/1.3/default/wifi_sta_iface.h
@@ -19,7 +19,7 @@
 
 #include <android-base/macros.h>
 #include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
-#include <android/hardware/wifi/1.2/IWifiStaIface.h>
+#include <android/hardware/wifi/1.3/IWifiStaIface.h>
 
 #include <wifi_system/interface_tool.h>
 
@@ -36,7 +36,7 @@
 /**
  * HIDL interface object used to control a STA Iface instance.
  */
-class WifiStaIface : public V1_2::IWifiStaIface {
+class WifiStaIface : public V1_3::IWifiStaIface {
    public:
     WifiStaIface(const std::string& ifname,
                  const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
@@ -75,6 +75,8 @@
         disableLinkLayerStatsCollection_cb hidl_status_cb) override;
     Return<void> getLinkLayerStats(
         getLinkLayerStats_cb hidl_status_cb) override;
+    Return<void> getLinkLayerStats_1_3(
+        getLinkLayerStats_1_3_cb hidl_status_cb) override;
     Return<void> startRssiMonitoring(
         uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
         startRssiMonitoring_cb hidl_status_cb) override;
@@ -130,7 +132,9 @@
     WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
     WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
     WifiStatus disableLinkLayerStatsCollectionInternal();
-    std::pair<WifiStatus, StaLinkLayerStats> getLinkLayerStatsInternal();
+    std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal();
+    std::pair<WifiStatus, V1_3::StaLinkLayerStats>
+    getLinkLayerStatsInternal_1_3();
     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.3/types.hal b/wifi/1.3/types.hal
new file mode 100644
index 0000000..4585ff3
--- /dev/null
+++ b/wifi/1.3/types.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018 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.3;
+
+import @1.0::StaLinkLayerRadioStats;
+import @1.0::StaLinkLayerIfaceStats;
+import @1.0::TimeStampInMs;
+
+struct StaLinkLayerRadioStats {
+    /**
+     * Baseline information as defined in HAL 1.0.
+     */
+    @1.0::StaLinkLayerRadioStats V1_0;
+
+    /**
+     * Total time for which the radio is awake due to NAN scan since boot or crash.
+     */
+    uint32_t onTimeInMsForNanScan;
+
+    /**
+     * Total time for which the radio is awake due to background scan since boot or crash.
+     */
+    uint32_t onTimeInMsForBgScan;
+
+    /**
+     * Total time for which the radio is awake due to roam scan since boot or crash.
+     */
+    uint32_t onTimeInMsForRoamScan;
+
+    /**
+     * Total time for which the radio is awake due to PNO scan since boot or crash.
+     */
+    uint32_t onTimeInMsForPnoScan;
+
+    /**
+     * Total time for which the radio is awake due to Hotspot 2.0 scans and GAS exchange since boot
+     * or crash.
+     */
+    uint32_t onTimeInMsForHs20Scan;
+};
+
+/**
+ * Link layer stats retrieved via |getLinkLayerStats|.
+ */
+struct StaLinkLayerStats {
+    StaLinkLayerIfaceStats iface;
+    vec<StaLinkLayerRadioStats> radios;
+    /**
+     * TimeStamp for each stats sample.
+     * This is the absolute milliseconds from boot when these stats were
+     * sampled.
+     */
+    TimeStampInMs timeStampInMs;
+};
\ No newline at end of file