wifi: Add support for RSSI monitoring

Bug: 31991459
Test: Compiles
Change-Id: I8794cea12a0d1c727bd0e37123152c8da11eeabf
diff --git a/wifi/1.0/IWifiStaIface.hal b/wifi/1.0/IWifiStaIface.hal
index 41b2bad..7b514a7 100644
--- a/wifi/1.0/IWifiStaIface.hal
+++ b/wifi/1.0/IWifiStaIface.hal
@@ -45,9 +45,13 @@
      */
     LINK_LAYER_STATS = 1 << 2,
     /**
+     * If set indicates that the RSSI monitor APIs are supported.
+     */
+    RSSI_MONITOR = 1 << 3,
+    /**
      * Tracks connection packets' fate.
      */
-    DEBUG_PACKET_FATE_SUPPORTED = 1 << 3
+    DEBUG_PACKET_FATE_SUPPORTED = 1 << 4
   };
 
   /**
@@ -259,6 +263,44 @@
   getLinkLayerStats() generates (WifiStatus status, StaLinkLayerStats stats);
 
   /**
+   * Start RSSI monitoring on the currently connected access point.
+   * Once the monitoring is enabled,
+   * |IWifiStaIfaceEventCallback.onRssiThresholdBreached| callback must be
+   * invoked to indicate if the RSSI goes above |maxRssi| or below |minRssi|.
+   * Must fail if |StaIfaceCapabilityMask.RSSI_MONITOR| is not set.
+   *
+   * @param cmdId command Id to use for this invocation.
+   * @param maxRssi Maximum RSSI threshold.
+   * @param minRssi Minimum RSSI threshold.
+   * @return status WifiStatus of the operation.
+   *         Possible status codes:
+   *         |WifiStatusCode.SUCCESS|,
+   *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+   *         |WifiStatusCode.ERROR_ARGS_INVALID|,
+   *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+   *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+   *         |WifiStatusCode.ERROR_UNKNOWN|
+   */
+  startRssiMonitoring(CommandId cmdId, Rssi maxRssi, Rssi minRssi)
+      generates (WifiStatus status);
+
+  /**
+   * Stop RSSI monitoring.
+   * Must fail if |StaIfaceCapabilityMask.RSSI_MONITOR| is not set.
+   *
+   * @param cmdId command Id corresponding to the request.
+   * @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|
+   */
+  stopRssiMonitoring(CommandId cmdId) generates (WifiStatus status);
+
+  /**
    * API to start packet fate monitoring.
    * - Once stared, monitoring must remain active until HAL is unloaded.
    * - When HAL is unloaded, all packet fate buffers must be cleared.
diff --git a/wifi/1.0/IWifiStaIfaceEventCallback.hal b/wifi/1.0/IWifiStaIfaceEventCallback.hal
index d47d40c..e8df4c2 100644
--- a/wifi/1.0/IWifiStaIfaceEventCallback.hal
+++ b/wifi/1.0/IWifiStaIfaceEventCallback.hal
@@ -20,6 +20,8 @@
   /**
    * Callback indicating that an ongoing background scan request has failed.
    * The background scan needs to be restarted to continue scanning.
+   *
+   * @param cmdId command ID corresponding to the request.
    */
   oneway onBackgroundScanFailure(CommandId cmdId);
 
@@ -28,7 +30,7 @@
    * |REPORT_EVENTS_FULL_RESULTS| flag set in
    * |StaBackgroundScanBucketParameters.eventReportScheme|.
    *
-   * @param cmdId command Id corresponding to the request.
+   * @param cmdId command ID corresponding to the request.
    * @parm result Full scan result for an AP.
    */
   oneway onBackgroundFullScanResult(CommandId cmdId, StaScanResult result);
@@ -39,8 +41,18 @@
    * |REPORT_EVENTS_EACH_SCAN| or one of the configured thresholds was
    * breached.
    *
-   * @param cmdId command Id corresponding to the request.
+   * @param cmdId command ID corresponding to the request.
    * @parm scanDatas List of scan result for all AP's seen since last callback.
    */
   oneway onBackgroundScanResults(CommandId cmdId, vec<StaScanData> scanDatas);
+
+  /**
+   * Called when the RSSI of the currently connected access point goes beyond the
+   * thresholds set via |IWifiStaIface.startRssiMonitoring|.
+   *
+   * @param cmdId command ID corresponding to the request.
+   * @param currBssid BSSID of the currently connected access point.
+   * @param currRssi RSSI of the currently connected access point.
+   */
+  oneway onRssiThresholdBreached(CommandId cmdId, Bssid currBssid, Rssi currRssi);
 };
diff --git a/wifi/1.0/default/hidl_struct_util.cpp b/wifi/1.0/default/hidl_struct_util.cpp
index e3e41c3..61a2c2c 100644
--- a/wifi/1.0/default/hidl_struct_util.cpp
+++ b/wifi/1.0/default/hidl_struct_util.cpp
@@ -64,6 +64,8 @@
       return HidlStaIfaceCaps::BACKGROUND_SCAN;
     case WIFI_FEATURE_LINK_LAYER_STATS:
       return HidlStaIfaceCaps::LINK_LAYER_STATS;
+    case WIFI_FEATURE_RSSI_MONITOR:
+      return HidlStaIfaceCaps::RSSI_MONITOR;
   };
   CHECK(false) << "Unknown legacy feature: " << feature;
   return {};
@@ -210,8 +212,9 @@
       *hidl_caps |= convertLegacyLoggerFeatureToHidlStaIfaceCapability(feature);
     }
   }
-  for (const auto feature :
-       {WIFI_FEATURE_GSCAN, WIFI_FEATURE_LINK_LAYER_STATS}) {
+  for (const auto feature : {WIFI_FEATURE_GSCAN,
+                             WIFI_FEATURE_LINK_LAYER_STATS,
+                             WIFI_FEATURE_RSSI_MONITOR}) {
     if (feature & legacy_feature_set) {
       *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
     }
diff --git a/wifi/1.0/default/wifi_legacy_hal.cpp b/wifi/1.0/default/wifi_legacy_hal.cpp
index de1eb39..640a2f2 100644
--- a/wifi/1.0/default/wifi_legacy_hal.cpp
+++ b/wifi/1.0/default/wifi_legacy_hal.cpp
@@ -90,16 +90,25 @@
 // Callback to be invoked for link layer stats results.
 std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
     on_link_layer_stats_result_internal_callback;
-void onLinkLayerStatsDataResult(wifi_request_id id,
-                                wifi_iface_stat* iface_stat,
-                                int num_radios,
-                                wifi_radio_stat* radio_stat) {
+void onLinkLayerStatsResult(wifi_request_id id,
+                            wifi_iface_stat* iface_stat,
+                            int num_radios,
+                            wifi_radio_stat* radio_stat) {
   if (on_link_layer_stats_result_internal_callback) {
     on_link_layer_stats_result_internal_callback(
         id, iface_stat, num_radios, radio_stat);
   }
 }
 
+// Callback to be invoked for rssi threshold breach.
+std::function<void((wifi_request_id, uint8_t*, int8_t))>
+    on_rssi_threshold_breached_internal_callback;
+void onRssiThresholdBreached(wifi_request_id id, uint8_t* bssid, int8_t rssi) {
+  if (on_rssi_threshold_breached_internal_callback) {
+    on_rssi_threshold_breached_internal_callback(id, bssid, rssi);
+  }
+}
+
 // Callback to be invoked for ring buffer data indication.
 std::function<void(char*, char*, int, wifi_ring_buffer_status*)>
     on_ring_buffer_data_internal_callback;
@@ -537,11 +546,53 @@
   };
 
   wifi_error status = global_func_table_.wifi_get_link_stats(
-      0, wlan_interface_handle_, {onLinkLayerStatsDataResult});
+      0, wlan_interface_handle_, {onLinkLayerStatsResult});
   on_link_layer_stats_result_internal_callback = nullptr;
   return {status, link_stats};
 }
 
+wifi_error WifiLegacyHal::startRssiMonitoring(
+    wifi_request_id id,
+    int8_t max_rssi,
+    int8_t min_rssi,
+    const on_rssi_threshold_breached_callback&
+        on_threshold_breached_user_callback) {
+  if (on_rssi_threshold_breached_internal_callback) {
+    return WIFI_ERROR_NOT_AVAILABLE;
+  }
+  on_rssi_threshold_breached_internal_callback =
+      [on_threshold_breached_user_callback](
+          wifi_request_id id, uint8_t* bssid_ptr, int8_t rssi) {
+        if (!bssid_ptr) {
+          return;
+        }
+        std::array<uint8_t, 6> bssid_arr;
+        // |bssid_ptr| pointer is assumed to have 6 bytes for the mac address.
+        std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr));
+        on_threshold_breached_user_callback(id, bssid_arr, rssi);
+      };
+  return global_func_table_.wifi_start_rssi_monitoring(
+      id,
+      wlan_interface_handle_,
+      max_rssi,
+      min_rssi,
+      {onRssiThresholdBreached});
+}
+
+wifi_error WifiLegacyHal::stopRssiMonitoring(wifi_request_id id) {
+  if (!on_rssi_threshold_breached_internal_callback) {
+    return WIFI_ERROR_NOT_AVAILABLE;
+  }
+  wifi_error status =
+      global_func_table_.wifi_stop_rssi_monitoring(id, wlan_interface_handle_);
+  // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any
+  // other error should be treated as the end of background scan.
+  if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+    on_rssi_threshold_breached_internal_callback = nullptr;
+  }
+  return status;
+}
+
 std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet() {
   uint32_t supported_features;
   wifi_error status = global_func_table_.wifi_get_logger_supported_feature_set(
@@ -1017,6 +1068,7 @@
   on_gscan_event_internal_callback = nullptr;
   on_gscan_full_result_internal_callback = nullptr;
   on_link_layer_stats_result_internal_callback = nullptr;
+  on_rssi_threshold_breached_internal_callback = nullptr;
   on_ring_buffer_data_internal_callback = nullptr;
   on_rtt_results_internal_callback = nullptr;
   on_nan_notify_response_user_callback = nullptr;
diff --git a/wifi/1.0/default/wifi_legacy_hal.h b/wifi/1.0/default/wifi_legacy_hal.h
index b569dbd..b68fa50 100644
--- a/wifi/1.0/default/wifi_legacy_hal.h
+++ b/wifi/1.0/default/wifi_legacy_hal.h
@@ -101,6 +101,10 @@
 using on_gscan_results_callback = std::function<void(
     wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
 
+// Invoked when the rssi value breaches the thresholds set.
+using on_rssi_threshold_breached_callback =
+    std::function<void(wifi_request_id, std::array<uint8_t, 6>, int8_t)>;
+
 // Callback for RTT range request results.
 // Rtt results contain IE info and are hence passed by reference, to
 // preserve the |LCI| and |LCR| pointers. Callee must not retain
@@ -167,6 +171,13 @@
   wifi_error enableLinkLayerStats(bool debug);
   wifi_error disableLinkLayerStats();
   std::pair<wifi_error, LinkLayerStats> getLinkLayerStats();
+  // RSSI monitor functions.
+  wifi_error startRssiMonitoring(wifi_request_id id,
+                                 int8_t max_rssi,
+                                 int8_t min_rssi,
+                                 const on_rssi_threshold_breached_callback&
+                                     on_threshold_breached_callback);
+  wifi_error stopRssiMonitoring(wifi_request_id id);
   // Logger/debug functions.
   std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet();
   wifi_error startPktFateMonitoring();
diff --git a/wifi/1.0/default/wifi_sta_iface.cpp b/wifi/1.0/default/wifi_sta_iface.cpp
index cc8edd1..c91a99b 100644
--- a/wifi/1.0/default/wifi_sta_iface.cpp
+++ b/wifi/1.0/default/wifi_sta_iface.cpp
@@ -163,6 +163,29 @@
                          hidl_status_cb);
 }
 
+Return<void> WifiStaIface::startRssiMonitoring(
+    uint32_t cmd_id,
+    int32_t max_rssi,
+    int32_t min_rssi,
+    startRssiMonitoring_cb hidl_status_cb) {
+  return validateAndCall(this,
+                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                         &WifiStaIface::startRssiMonitoringInternal,
+                         hidl_status_cb,
+                         cmd_id,
+                         max_rssi,
+                         min_rssi);
+}
+
+Return<void> WifiStaIface::stopRssiMonitoring(
+    uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) {
+  return validateAndCall(this,
+                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                         &WifiStaIface::stopRssiMonitoringInternal,
+                         hidl_status_cb,
+                         cmd_id);
+}
+
 Return<void> WifiStaIface::startDebugPacketFateMonitoring(
     startDebugPacketFateMonitoring_cb hidl_status_cb) {
   return validateAndCall(this,
@@ -384,6 +407,35 @@
   return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
 }
 
+WifiStatus WifiStaIface::startRssiMonitoringInternal(uint32_t cmd_id,
+                                                     int32_t max_rssi,
+                                                     int32_t min_rssi) {
+  android::wp<WifiStaIface> weak_ptr_this(this);
+  const auto& on_threshold_breached_callback = [weak_ptr_this](
+      legacy_hal::wifi_request_id id,
+      std::array<uint8_t, 6> bssid,
+      int8_t rssi) {
+    const auto shared_ptr_this = weak_ptr_this.promote();
+    if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+      LOG(ERROR) << "Callback invoked on an invalid object";
+      return;
+    }
+    for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+      callback->onRssiThresholdBreached(id, bssid, rssi);
+    }
+  };
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->startRssiMonitoring(
+          cmd_id, max_rssi, min_rssi, on_threshold_breached_callback);
+  return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopRssiMonitoringInternal(uint32_t cmd_id) {
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->stopRssiMonitoring(cmd_id);
+  return createWifiStatusFromLegacyError(legacy_status);
+}
+
 WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
   legacy_hal::wifi_error legacy_status =
       legacy_hal_.lock()->startPktFateMonitoring();
diff --git a/wifi/1.0/default/wifi_sta_iface.h b/wifi/1.0/default/wifi_sta_iface.h
index cdfe951..b4f2721 100644
--- a/wifi/1.0/default/wifi_sta_iface.h
+++ b/wifi/1.0/default/wifi_sta_iface.h
@@ -70,6 +70,13 @@
   Return<void> disableLinkLayerStatsCollection(
       disableLinkLayerStatsCollection_cb hidl_status_cb) override;
   Return<void> getLinkLayerStats(getLinkLayerStats_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;
+  Return<void> stopRssiMonitoring(
+      uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
   Return<void> startDebugPacketFateMonitoring(
       startDebugPacketFateMonitoring_cb hidl_status_cb) override;
   Return<void> stopDebugPacketFateMonitoring(
@@ -100,6 +107,10 @@
   WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
   WifiStatus disableLinkLayerStatsCollectionInternal();
   std::pair<WifiStatus, StaLinkLayerStats> getLinkLayerStatsInternal();
+  WifiStatus startRssiMonitoringInternal(uint32_t cmd_id,
+                                         int32_t max_rssi,
+                                         int32_t min_rssi);
+  WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
   WifiStatus startDebugPacketFateMonitoringInternal();
   WifiStatus stopDebugPacketFateMonitoringInternal();
   std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>