wifi: Add support for alert handler

This is a debug mechanism provided for vendors to inform the framework
about the occurence of any fatal events.

Bug: 33620898
Test: Compiles
Change-Id: Ib6ac322131796792f66f87237a62eb8f5a013433
diff --git a/wifi/1.0/IWifiChip.hal b/wifi/1.0/IWifiChip.hal
index 051a088..e903ced 100644
--- a/wifi/1.0/IWifiChip.hal
+++ b/wifi/1.0/IWifiChip.hal
@@ -163,6 +163,10 @@
      * Host wake reasons stats collection.
      */
     DEBUG_HOST_WAKE_REASON_STATS = 1 << 6,
+    /**
+     * Error alerts.
+     */
+    DEBUG_ERROR_ALERTS = 1 << 7
   };
 
   /**
@@ -640,4 +644,21 @@
    */
   getDebugHostWakeReasonStats()
       generates (WifiStatus status, WifiDebugHostWakeReasonStats stats);
+
+  /**
+   * API to enable/disable alert notifications from the chip.
+   * These alerts must be used to notify framework of any fatal error events
+   * that the chip encounters via |IWifiChipEventCallback.onDebugErrorAlert| method.
+   * Must fail if |ChipCapabilityMask.DEBUG_ERROR_ALERTS| is not set.
+   *
+   * @param enable true to enable, false to disable.
+   * @return status WifiStatus of the operation.
+   *         Possible status codes:
+   *         |WifiStatusCode.SUCCESS|,
+   *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+   *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+   *         |WifiStatusCode.NOT_AVAILABLE|,
+   *         |WifiStatusCode.UNKNOWN|
+   */
+  enableDebugErrorAlerts(bool enable) generates (WifiStatus status);
 };
diff --git a/wifi/1.0/IWifiChipEventCallback.hal b/wifi/1.0/IWifiChipEventCallback.hal
index 292b10f..1501029 100644
--- a/wifi/1.0/IWifiChipEventCallback.hal
+++ b/wifi/1.0/IWifiChipEventCallback.hal
@@ -70,4 +70,14 @@
   oneway onDebugRingBufferVendorDataEntriesAvailable(
       WifiDebugRingBufferStatus status,
       vec<WifiDebugRingEntryVendorData> entries);
+
+  /**
+   * Callback indicating that the chip has encountered a fatal error.
+   * Client must not attempt to parse either the errorCode or debugData.
+   * Must only be captured in a bugreport.
+   *
+   * @param errorCode Vendor defined error code.
+   * @param debugData Vendor defined data used for debugging.
+   */
+  oneway onDebugErrorAlert(int32_t errorCode, vec<uint8_t> debugData);
 };
diff --git a/wifi/1.0/default/hidl_struct_util.cpp b/wifi/1.0/default/hidl_struct_util.cpp
index 996f119..0aee372 100644
--- a/wifi/1.0/default/hidl_struct_util.cpp
+++ b/wifi/1.0/default/hidl_struct_util.cpp
@@ -93,10 +93,11 @@
       *hidl_caps |= convertLegacyLoggerFeatureToHidlChipCapability(feature);
     }
   }
-  // There is no flags for these 2 in the legacy feature set. Adding it to the
-  // set because all the current devices support it.
+  // There are no flags for these 3 in the legacy feature set. Adding them to
+  // the set because all the current devices support it.
   *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA_SUPPORTED;
   *hidl_caps |= HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS;
+  *hidl_caps |= HidlChipCaps::DEBUG_ERROR_ALERTS;
   return true;
 }
 
diff --git a/wifi/1.0/default/wifi_chip.cpp b/wifi/1.0/default/wifi_chip.cpp
index d70f548..d64dea6 100644
--- a/wifi/1.0/default/wifi_chip.cpp
+++ b/wifi/1.0/default/wifi_chip.cpp
@@ -69,6 +69,10 @@
   return is_valid_;
 }
 
+std::vector<sp<IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
+  return event_callbacks_;
+}
+
 Return<void> WifiChip::getId(getId_cb hidl_status_cb) {
   return validateAndCall(this,
                          WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
@@ -319,6 +323,15 @@
                          hidl_status_cb);
 }
 
+Return<void> WifiChip::enableDebugErrorAlerts(
+    bool enable, enableDebugErrorAlerts_cb hidl_status_cb) {
+  return validateAndCall(this,
+                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                         &WifiChip::enableDebugErrorAlertsInternal,
+                         hidl_status_cb,
+                         enable);
+}
+
 void WifiChip::invalidateAndRemoveAllIfaces() {
   invalidateAndClear(ap_iface_);
   invalidateAndClear(nan_iface_);
@@ -706,6 +719,28 @@
   return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
 }
 
+WifiStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
+  legacy_hal::wifi_error legacy_status;
+  if (enable) {
+    android::wp<WifiChip> weak_ptr_this(this);
+    const auto& on_alert_callback = [weak_ptr_this](
+        int32_t error_code, std::vector<uint8_t> debug_data) {
+      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->onDebugErrorAlert(error_code, debug_data);
+      }
+    };
+    legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
+        on_alert_callback);
+  } else {
+    legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler();
+  }
+  return createWifiStatusFromLegacyError(legacy_status);
+}
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace wifi
diff --git a/wifi/1.0/default/wifi_chip.h b/wifi/1.0/default/wifi_chip.h
index 5e7a0c3..cfe2ed2 100644
--- a/wifi/1.0/default/wifi_chip.h
+++ b/wifi/1.0/default/wifi_chip.h
@@ -62,6 +62,7 @@
   // valid before processing them.
   void invalidate();
   bool isValid();
+  std::vector<sp<IWifiChipEventCallback>> getEventCallbacks();
 
   // HIDL methods exposed.
   Return<void> getId(getId_cb hidl_status_cb) override;
@@ -119,6 +120,8 @@
       forceDumpToDebugRingBuffer_cb hidl_status_cb) override;
   Return<void> getDebugHostWakeReasonStats(
       getDebugHostWakeReasonStats_cb hidl_status_cb) override;
+  Return<void> enableDebugErrorAlerts(
+      bool enable, enableDebugErrorAlerts_cb hidl_status_cb) override;
 
  private:
   void invalidateAndRemoveAllIfaces();
@@ -168,6 +171,7 @@
   WifiStatus forceDumpToDebugRingBufferInternal(const hidl_string& ring_name);
   std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
   getDebugHostWakeReasonStatsInternal();
+  WifiStatus enableDebugErrorAlertsInternal(bool enable);
 
   ChipId chip_id_;
   std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
diff --git a/wifi/1.0/default/wifi_legacy_hal.cpp b/wifi/1.0/default/wifi_legacy_hal.cpp
index d10e181..678ebb1 100644
--- a/wifi/1.0/default/wifi_legacy_hal.cpp
+++ b/wifi/1.0/default/wifi_legacy_hal.cpp
@@ -121,6 +121,18 @@
   }
 }
 
+// Callback to be invoked for error alert indication.
+std::function<void(wifi_request_id, char*, int, int)>
+    on_error_alert_internal_callback;
+void onErrorAlert(wifi_request_id id,
+                  char* buffer,
+                  int buffer_size,
+                  int err_code) {
+  if (on_error_alert_internal_callback) {
+    on_error_alert_internal_callback(id, buffer, buffer_size, err_code);
+  }
+}
+
 // Callback to be invoked for rtt results results.
 std::function<void(
     wifi_request_id, unsigned num_results, wifi_rtt_result* rtt_results[])>
@@ -764,6 +776,38 @@
                                                ring_name_internal.data());
 }
 
+wifi_error WifiLegacyHal::registerErrorAlertCallbackHandler(
+    const on_error_alert_callback& on_user_alert_callback) {
+  if (on_error_alert_internal_callback) {
+    return WIFI_ERROR_NOT_AVAILABLE;
+  }
+  on_error_alert_internal_callback = [on_user_alert_callback](
+      wifi_request_id id, char* buffer, int buffer_size, int err_code) {
+    if (buffer) {
+      CHECK(id == 0);
+      on_user_alert_callback(
+          err_code,
+          std::vector<uint8_t>(
+              reinterpret_cast<uint8_t*>(buffer),
+              reinterpret_cast<uint8_t*>(buffer) + buffer_size));
+    }
+  };
+  wifi_error status = global_func_table_.wifi_set_alert_handler(
+      0, wlan_interface_handle_, {onErrorAlert});
+  if (status != WIFI_SUCCESS) {
+    on_error_alert_internal_callback = nullptr;
+  }
+  return status;
+}
+
+wifi_error WifiLegacyHal::deregisterErrorAlertCallbackHandler() {
+  if (!on_error_alert_internal_callback) {
+    return WIFI_ERROR_NOT_AVAILABLE;
+  }
+  on_error_alert_internal_callback = nullptr;
+  return global_func_table_.wifi_reset_alert_handler(0, wlan_interface_handle_);
+}
+
 wifi_error WifiLegacyHal::startRttRangeRequest(
     wifi_request_id id,
     const std::vector<wifi_rtt_config>& rtt_configs,
@@ -1114,6 +1158,7 @@
   on_link_layer_stats_result_internal_callback = nullptr;
   on_rssi_threshold_breached_internal_callback = nullptr;
   on_ring_buffer_data_internal_callback = nullptr;
+  on_error_alert_internal_callback = nullptr;
   on_rtt_results_internal_callback = nullptr;
   on_nan_notify_response_user_callback = nullptr;
   on_nan_event_publish_terminated_user_callback = nullptr;
diff --git a/wifi/1.0/default/wifi_legacy_hal.h b/wifi/1.0/default/wifi_legacy_hal.h
index 77b1705..c846fc8 100644
--- a/wifi/1.0/default/wifi_legacy_hal.h
+++ b/wifi/1.0/default/wifi_legacy_hal.h
@@ -118,6 +118,9 @@
                        const std::vector<uint8_t>&,
                        const wifi_ring_buffer_status&)>;
 
+// Callback for alerts.
+using on_error_alert_callback =
+    std::function<void(int32_t, const std::vector<uint8_t>&)>;
 /**
  * Class that encapsulates all legacy HAL interactions.
  * This class manages the lifetime of the event loop thread used by legacy HAL.
@@ -196,6 +199,9 @@
                                     uint32_t max_interval_sec,
                                     uint32_t min_data_size);
   wifi_error getRingBufferData(const std::string& ring_name);
+  wifi_error registerErrorAlertCallbackHandler(
+      const on_error_alert_callback& on_alert_callback);
+  wifi_error deregisterErrorAlertCallbackHandler();
   // RTT functions.
   wifi_error startRttRangeRequest(
       wifi_request_id id,