Merge "[Thread] Implement hardware reset" into main
diff --git a/threadnetwork/aidl/default/socket_interface.cpp b/threadnetwork/aidl/default/socket_interface.cpp
index 0544502..339fd6b 100644
--- a/threadnetwork/aidl/default/socket_interface.cpp
+++ b/threadnetwork/aidl/default/socket_interface.cpp
@@ -33,6 +33,7 @@
 #include <unistd.h>
 
 #include <string>
+#include <vector>
 
 #include "common/code_utils.hpp"
 #include "openthread/openthread-system.h"
@@ -49,10 +50,8 @@
     : mReceiveFrameCallback(nullptr),
       mReceiveFrameContext(nullptr),
       mReceiveFrameBuffer(nullptr),
-      mSockFd(-1),
       mRadioUrl(aRadioUrl) {
-    memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics));
-    mInterfaceMetrics.mRcpInterfaceType = kSpinelInterfaceTypeVendor;
+    ResetStates();
 }
 
 otError SocketInterface::Init(ReceiveFrameCallback aCallback, void* aCallbackContext,
@@ -120,13 +119,50 @@
     } else if (rval == 0) {
         ExitNow(error = OT_ERROR_RESPONSE_TIMEOUT);
     } else {
-        DieNowWithMessage("wait response", OT_EXIT_FAILURE);
+        DieNowWithMessage("Wait response", OT_EXIT_FAILURE);
     }
 
 exit:
     return error;
 }
 
+otError SocketInterface::WaitForHardwareResetCompletion(uint32_t aTimeoutMs) {
+    otError error = OT_ERROR_NONE;
+    int retries = 0;
+    int rval;
+
+    while (mIsHardwareResetting && retries++ < kMaxRetriesForSocketCloseCheck) {
+        struct timeval timeout;
+        timeout.tv_sec = static_cast<time_t>(aTimeoutMs / MS_PER_S);
+        timeout.tv_usec = static_cast<suseconds_t>((aTimeoutMs % MS_PER_S) * MS_PER_S);
+
+        fd_set readFds;
+
+        FD_ZERO(&readFds);
+        FD_SET(mSockFd, &readFds);
+
+        rval = TEMP_FAILURE_RETRY(select(mSockFd + 1, &readFds, nullptr, nullptr, &timeout));
+
+        if (rval > 0) {
+            Read();
+        } else if (rval < 0) {
+            DieNowWithMessage("Wait response", OT_EXIT_ERROR_ERRNO);
+        } else {
+            LogInfo("Waiting for hardware reset, retry attempt: %d, max attempt: %d", retries,
+                    kMaxRetriesForSocketCloseCheck);
+        }
+    }
+
+    VerifyOrExit(!mIsHardwareResetting, error = OT_ERROR_FAILED);
+
+    WaitForSocketFileCreated(mRadioUrl.GetPath());
+    mSockFd = OpenFile(mRadioUrl);
+    VerifyOrExit(mSockFd != -1, error = OT_ERROR_FAILED);
+
+exit:
+    return error;
+}
+
 void SocketInterface::UpdateFdSet(void* aMainloopContext) {
     otSysMainloopContext* context = reinterpret_cast<otSysMainloopContext*>(aMainloopContext);
 
@@ -150,6 +186,16 @@
     }
 }
 
+otError SocketInterface::HardwareReset(void) {
+    otError error = OT_ERROR_NONE;
+    std::vector<uint8_t> resetCommand = {SPINEL_HEADER_FLAG, SPINEL_CMD_RESET, 0x04};
+
+    mIsHardwareResetting = true;
+    SendFrame(resetCommand.data(), resetCommand.size());
+
+    return WaitForHardwareResetCompletion(kMaxSelectTimeMs);
+}
+
 void SocketInterface::Read(void) {
     uint8_t buffer[kMaxFrameSize];
 
@@ -160,8 +206,13 @@
     } else if (rval < 0) {
         DieNow(OT_EXIT_ERROR_ERRNO);
     } else {
-        LogCrit("Socket connection is closed by remote.");
-        exit(OT_EXIT_FAILURE);
+        if (mIsHardwareResetting) {
+            LogInfo("Socket connection is closed due to hardware reset.");
+            ResetStates();
+        } else {
+            LogCrit("Socket connection is closed by remote.");
+            exit(OT_EXIT_FAILURE);
+        }
     }
 }
 
@@ -298,6 +349,13 @@
     return stat(aPath, &st) == 0 && S_ISSOCK(st.st_mode);
 }
 
+void SocketInterface::ResetStates() {
+    mSockFd = -1;
+    mIsHardwareResetting = false;
+    memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics));
+    mInterfaceMetrics.mRcpInterfaceType = kSpinelInterfaceTypeVendor;
+}
+
 }  // namespace threadnetwork
 }  // namespace hardware
 }  // namespace android
diff --git a/threadnetwork/aidl/default/socket_interface.hpp b/threadnetwork/aidl/default/socket_interface.hpp
index 6f3be7f..494d76a 100644
--- a/threadnetwork/aidl/default/socket_interface.hpp
+++ b/threadnetwork/aidl/default/socket_interface.hpp
@@ -136,10 +136,10 @@
      * Hardware resets the RCP.
      *
      * @retval OT_ERROR_NONE            Successfully reset the RCP.
-     * @retval OT_ERROR_NOT_IMPLEMENT   The hardware reset is not implemented.
+     * @retval OT_ERROR_FAILED          Hardware reset is failed.
      *
      */
-    otError HardwareReset(void) { return OT_ERROR_NOT_IMPLEMENTED; }
+    otError HardwareReset(void);
 
     /**
      * Returns the RCP interface metrics.
@@ -237,9 +237,26 @@
      */
     void WaitForSocketFileCreated(const char* aPath);
 
+    /**
+     * Wait for the hardware reset completion signal.
+     *
+     * @retval OT_ERROR_NONE       Hardware reset is successfully.
+     * @retval OT_ERROR_FAILED     Hardware reset is failed.
+     *
+     */
+    otError WaitForHardwareResetCompletion(uint32_t aTimeoutMs);
+
+    /**
+     * Reset socket interface to intitial state.
+     *
+     */
+    void ResetStates(void);
+
     enum {
-        kMaxSelectTimeMs = 2000,  ///< Maximum wait time in Milliseconds for file
-                                  ///< descriptor to become available.
+        kMaxSelectTimeMs = 2000,             ///< Maximum wait time in Milliseconds for file
+                                             ///< descriptor to become available.
+        kMaxRetriesForSocketCloseCheck = 3,  ///< Maximum retry times for checking
+                                             ///< if socket is closed.
     };
 
     ReceiveFrameCallback mReceiveFrameCallback;
@@ -249,6 +266,8 @@
     int mSockFd;
     const ot::Url::Url& mRadioUrl;
 
+    bool mIsHardwareResetting;
+
     otRcpInterfaceMetrics mInterfaceMetrics;
 
     // Non-copyable, intentionally not implemented.