WiFi: Get channel stats from linklayer radio stats

Get the list of channel stats from linklayerstats radiostats
and send it to framework.

Bug: 79111545
Test: Connected STA to AP and verified the link layer stats
Test: Unit test
Test: ./wifi/1.3/default/tests/runtests.sh
Change-Id: If1008256afe0ec918cdbd952aa4f14012d5b0caf
diff --git a/wifi/1.3/Android.bp b/wifi/1.3/Android.bp
index 163a870..45e2e88 100644
--- a/wifi/1.3/Android.bp
+++ b/wifi/1.3/Android.bp
@@ -21,6 +21,7 @@
     types: [
       "StaLinkLayerRadioStats",
       "StaLinkLayerStats",
+      "WifiChannelStats",
     ],
     gen_java: true,
 }
diff --git a/wifi/1.3/default/hidl_struct_util.cpp b/wifi/1.3/default/hidl_struct_util.cpp
index c88ddaa..5bf206f 100644
--- a/wifi/1.3/default/hidl_struct_util.cpp
+++ b/wifi/1.3/default/hidl_struct_util.cpp
@@ -783,6 +783,55 @@
     return true;
 }
 
+bool convertLegacyLinkLayerRadioStatsToHidl(
+    const legacy_hal::LinkLayerRadioStats& legacy_radio_stat,
+    V1_3::StaLinkLayerRadioStats* hidl_radio_stat) {
+    if (!hidl_radio_stat) {
+        return false;
+    }
+    *hidl_radio_stat = {};
+
+    hidl_radio_stat->V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
+    hidl_radio_stat->V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
+    hidl_radio_stat->V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
+    hidl_radio_stat->V1_0.onTimeInMsForScan =
+        legacy_radio_stat.stats.on_time_scan;
+    hidl_radio_stat->V1_0.txTimeInMsPerLevel =
+        legacy_radio_stat.tx_time_per_levels;
+    hidl_radio_stat->onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd;
+    hidl_radio_stat->onTimeInMsForBgScan =
+        legacy_radio_stat.stats.on_time_gscan;
+    hidl_radio_stat->onTimeInMsForRoamScan =
+        legacy_radio_stat.stats.on_time_roam_scan;
+    hidl_radio_stat->onTimeInMsForPnoScan =
+        legacy_radio_stat.stats.on_time_pno_scan;
+    hidl_radio_stat->onTimeInMsForHs20Scan =
+        legacy_radio_stat.stats.on_time_hs20;
+
+    std::vector<V1_3::WifiChannelStats> hidl_channel_stats;
+
+    for (const auto& channel_stat : legacy_radio_stat.channel_stats) {
+        V1_3::WifiChannelStats hidl_channel_stat;
+        hidl_channel_stat.onTimeInMs = channel_stat.on_time;
+        hidl_channel_stat.ccaBusyTimeInMs = channel_stat.cca_busy_time;
+        /*
+         * TODO once b/119142899 is fixed,
+         * replace below code with convertLegacyWifiChannelInfoToHidl()
+         */
+        hidl_channel_stat.channel.width = WifiChannelWidthInMhz::WIDTH_20;
+        hidl_channel_stat.channel.centerFreq = channel_stat.channel.center_freq;
+        hidl_channel_stat.channel.centerFreq0 =
+            channel_stat.channel.center_freq0;
+        hidl_channel_stat.channel.centerFreq1 =
+            channel_stat.channel.center_freq1;
+        hidl_channel_stats.push_back(hidl_channel_stat);
+    }
+
+    hidl_radio_stat->channelStats = hidl_channel_stats;
+
+    return true;
+}
+
 bool convertLegacyLinkLayerStatsToHidl(
     const legacy_hal::LinkLayerStats& legacy_stats,
     V1_3::StaLinkLayerStats* hidl_stats) {
@@ -829,23 +878,10 @@
     std::vector<V1_3::StaLinkLayerRadioStats> hidl_radios_stats;
     for (const auto& legacy_radio_stats : legacy_stats.radios) {
         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.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;
+        if (!convertLegacyLinkLayerRadioStatsToHidl(legacy_radio_stats,
+                                                    &hidl_radio_stats)) {
+            return false;
+        }
         hidl_radios_stats.push_back(hidl_radio_stats);
     }
     hidl_stats->radios = hidl_radios_stats;
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 d600a2b..a4828ca 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
@@ -37,6 +37,7 @@
 namespace V1_3 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
+using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
 
 class HidlStructUtilTest : public Test {};
 
@@ -166,6 +167,17 @@
         for (int i = 0; i < 4; i++) {
             radio.tx_time_per_levels.push_back(rand());
         }
+
+        legacy_hal::wifi_channel_stat channel_stat1 = {
+            .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
+            .cca_busy_time = 0x55,
+            .on_time = 0x1111};
+        legacy_hal::wifi_channel_stat channel_stat2 = {
+            .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
+            .cca_busy_time = 0x66,
+            .on_time = 0x2222};
+        radio.channel_stats.push_back(channel_stat1);
+        radio.channel_stats.push_back(channel_stat2);
     }
 
     V1_3::StaLinkLayerStats converted{};
@@ -236,6 +248,25 @@
                   converted.radios[i].onTimeInMsForPnoScan);
         EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
                   converted.radios[i].onTimeInMsForHs20Scan);
+        EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(),
+                  converted.radios[i].channelStats.size());
+        for (int k = 0; k < legacy_stats.radios[i].channel_stats.size(); k++) {
+            EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
+                      converted.radios[i].channelStats[k].channel.width);
+            EXPECT_EQ(
+                legacy_stats.radios[i].channel_stats[k].channel.center_freq,
+                converted.radios[i].channelStats[k].channel.centerFreq);
+            EXPECT_EQ(
+                legacy_stats.radios[i].channel_stats[k].channel.center_freq0,
+                converted.radios[i].channelStats[k].channel.centerFreq0);
+            EXPECT_EQ(
+                legacy_stats.radios[i].channel_stats[k].channel.center_freq1,
+                converted.radios[i].channelStats[k].channel.centerFreq1);
+            EXPECT_EQ(legacy_stats.radios[i].channel_stats[k].cca_busy_time,
+                      converted.radios[i].channelStats[k].ccaBusyTimeInMs);
+            EXPECT_EQ(legacy_stats.radios[i].channel_stats[k].on_time,
+                      converted.radios[i].channelStats[k].onTimeInMs);
+        }
     }
 }
 }  // namespace implementation
diff --git a/wifi/1.3/default/wifi_legacy_hal.cpp b/wifi/1.3/default/wifi_legacy_hal.cpp
index 817c860..5c654e5 100644
--- a/wifi/1.3/default/wifi_legacy_hal.cpp
+++ b/wifi/1.3/default/wifi_legacy_hal.cpp
@@ -652,6 +652,8 @@
         [&link_stats_ptr](wifi_request_id /* id */,
                           wifi_iface_stat* iface_stats_ptr, int num_radios,
                           wifi_radio_stat* radio_stats_ptr) {
+            wifi_radio_stat* l_radio_stats_ptr;
+
             if (iface_stats_ptr != nullptr) {
                 link_stats_ptr->iface = *iface_stats_ptr;
                 link_stats_ptr->iface.num_peers = 0;
@@ -662,20 +664,35 @@
                 LOG(ERROR) << "Invalid radio stats in link layer stats";
                 return;
             }
+            l_radio_stats_ptr = radio_stats_ptr;
             for (int i = 0; i < num_radios; i++) {
                 LinkLayerRadioStats radio;
-                radio.stats = radio_stats_ptr[i];
+
+                radio.stats = *l_radio_stats_ptr;
                 // Copy over the tx level array to the separate vector.
-                if (radio_stats_ptr[i].num_tx_levels > 0 &&
-                    radio_stats_ptr[i].tx_time_per_levels != nullptr) {
+                if (l_radio_stats_ptr->num_tx_levels > 0 &&
+                    l_radio_stats_ptr->tx_time_per_levels != nullptr) {
                     radio.tx_time_per_levels.assign(
-                        radio_stats_ptr[i].tx_time_per_levels,
-                        radio_stats_ptr[i].tx_time_per_levels +
-                            radio_stats_ptr[i].num_tx_levels);
+                        l_radio_stats_ptr->tx_time_per_levels,
+                        l_radio_stats_ptr->tx_time_per_levels +
+                            l_radio_stats_ptr->num_tx_levels);
                 }
                 radio.stats.num_tx_levels = 0;
                 radio.stats.tx_time_per_levels = nullptr;
+                /* Copy over the channel stat to separate vector */
+                if (l_radio_stats_ptr->num_channels > 0) {
+                    /* Copy the channel stats */
+                    radio.channel_stats.assign(
+                        l_radio_stats_ptr->channels,
+                        l_radio_stats_ptr->channels +
+                            l_radio_stats_ptr->num_channels);
+                }
                 link_stats_ptr->radios.push_back(radio);
+                l_radio_stats_ptr =
+                    (wifi_radio_stat*)((u8*)l_radio_stats_ptr +
+                                       sizeof(wifi_radio_stat) +
+                                       (sizeof(wifi_channel_stat) *
+                                        l_radio_stats_ptr->num_channels));
             }
         };
 
diff --git a/wifi/1.3/default/wifi_legacy_hal.h b/wifi/1.3/default/wifi_legacy_hal.h
index af654fa..d1687a3 100644
--- a/wifi/1.3/default/wifi_legacy_hal.h
+++ b/wifi/1.3/default/wifi_legacy_hal.h
@@ -61,6 +61,7 @@
 struct LinkLayerRadioStats {
     wifi_radio_stat stats;
     std::vector<uint32_t> tx_time_per_levels;
+    std::vector<wifi_channel_stat> channel_stats;
 };
 
 struct LinkLayerStats {
diff --git a/wifi/1.3/types.hal b/wifi/1.3/types.hal
index 4585ff3..3b292b0 100644
--- a/wifi/1.3/types.hal
+++ b/wifi/1.3/types.hal
@@ -19,6 +19,22 @@
 import @1.0::StaLinkLayerRadioStats;
 import @1.0::StaLinkLayerIfaceStats;
 import @1.0::TimeStampInMs;
+import @1.0::WifiChannelInfo;
+
+struct WifiChannelStats {
+    /**
+    * Channel information.
+    */
+    WifiChannelInfo channel;
+    /**
+     * Total time for which the radio is awake on this channel.
+     */
+    uint32_t onTimeInMs;
+    /**
+     * Total time for which CCA is held busy on this channel.
+     */
+    uint32_t ccaBusyTimeInMs;
+};
 
 struct StaLinkLayerRadioStats {
     /**
@@ -51,6 +67,11 @@
      * or crash.
      */
     uint32_t onTimeInMsForHs20Scan;
+
+    /**
+     * List of channel stats associated with this radio
+     */
+    vec<WifiChannelStats> channelStats;
 };
 
 /**