change the Thread Network HAL api from 'reset' to 'hardwareReset'

This CL changes the API from 'reset' to 'hardwareReset' to make the
the definition of the API clearer. This CL also optimizes the Thread
Network HAL default implementation.

Bug: 289867661
Test: Run Thread stack on cuttlefish.
(cherry picked from https://android-review.googlesource.com/q/commit:a6165dcccf0096f8363b4b64b0f5332267eea330)
Merged-In: Id742453d9d7a0d369ac8f16905efdacfcfba1dbc
Change-Id: Id742453d9d7a0d369ac8f16905efdacfcfba1dbc
diff --git a/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
index e4d4cbe..607ceb3 100644
--- a/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
+++ b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
@@ -36,10 +36,9 @@
 interface IThreadChip {
   void open(in android.hardware.threadnetwork.IThreadChipCallback callback);
   void close();
-  void reset();
+  void hardwareReset();
   void sendSpinelFrame(in byte[] frame);
   const int ERROR_FAILED = 1;
-  const int ERROR_INVALID_ARGS = 2;
-  const int ERROR_NO_BUFS = 3;
-  const int ERROR_BUSY = 4;
+  const int ERROR_NO_BUFS = 2;
+  const int ERROR_BUSY = 3;
 }
diff --git a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
index eebaa46..e695623 100644
--- a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
+++ b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
@@ -30,19 +30,14 @@
     const int ERROR_FAILED = 1;
 
     /**
-     * The invalid arguments.
-     */
-    const int ERROR_INVALID_ARGS = 2;
-
-    /**
      * Insufficient buffers available to send frames.
      */
-    const int ERROR_NO_BUFS = 3;
+    const int ERROR_NO_BUFS = 2;
 
     /**
      * Service is busy and could not service the operation.
      */
-    const int ERROR_BUSY = 4;
+    const int ERROR_BUSY = 3;
 
     /**
      * This method initializes the Thread HAL instance. If open completes
@@ -51,9 +46,10 @@
      *
      * @param callback  A IThreadChipCallback callback instance.
      *
+     * @throws EX_ILLEGAL_ARGUMENT  if the callback handle is invalid (for example, it is null).
+     *
      * @throws ServiceSpecificException with one of the following values:
      *     - ERROR_FAILED        The interface cannot be opened due to an internal error.
-     *     - ERROR_INVALID_ARGS  The callback handle is invalid (for example, it is null).
      *     - ERROR_BUSY          This interface is in use.
      */
     void open(in IThreadChipCallback callback);
@@ -64,11 +60,14 @@
     void close();
 
     /**
-     * This method resets the Thread HAL internal state. The callback registered by
-     * `open()` won’t be reset and the resource allocated by `open()` won’t be free.
+     * This method hardware resets the Thread radio chip via the physical reset pin.
+     * The callback registered by `open()` won’t be reset and the resource allocated
+     * by `open()` won’t be free.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION  if the Thread radio chip doesn't support the hardware reset.
      *
      */
-    void reset();
+    void hardwareReset();
 
     /**
      * This method sends a spinel frame to the Thread HAL.
diff --git a/threadnetwork/aidl/default/thread_chip.cpp b/threadnetwork/aidl/default/thread_chip.cpp
index 94d1e93..3d38cb8 100644
--- a/threadnetwork/aidl/default/thread_chip.cpp
+++ b/threadnetwork/aidl/default/thread_chip.cpp
@@ -17,6 +17,8 @@
 #include "thread_chip.hpp"
 
 #include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <utils/Log.h>
@@ -46,20 +48,36 @@
         mSpinelInterface = std::make_shared<ot::Posix::HdlcInterface>(handleReceivedFrameJump, this,
                                                                       mRxFrameBuffer);
     } else {
-        ALOGE("The protocol \"%s\" is not supported!", protocol);
-        exit(1);
+        ALOGE("The protocol \"%s\" is not supported", protocol);
+        exit(EXIT_FAILURE);
     }
 
     CHECK_NE(mSpinelInterface, nullptr);
+
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+            AIBinder_DeathRecipient_new(ThreadChip::onBinderDiedJump));
+    AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinkedJump);
 }
 
-void ThreadChip::clientDeathCallback(void* context) {
-    reinterpret_cast<ThreadChip*>(context)->clientDeathCallback();
+ThreadChip::~ThreadChip() {
+    AIBinder_DeathRecipient_delete(mDeathRecipient.get());
 }
 
-void ThreadChip::clientDeathCallback(void) {
-    ALOGW("Thread Network HAL client is dead.");
-    close();
+void ThreadChip::onBinderDiedJump(void* context) {
+    reinterpret_cast<ThreadChip*>(context)->onBinderDied();
+}
+
+void ThreadChip::onBinderDied(void) {
+    ALOGW("Thread Network HAL client is dead");
+}
+
+void ThreadChip::onBinderUnlinkedJump(void* context) {
+    reinterpret_cast<ThreadChip*>(context)->onBinderUnlinked();
+}
+
+void ThreadChip::onBinderUnlinked(void) {
+    ALOGW("ThreadChip binder is unlinked");
+    deinitChip();
 }
 
 void ThreadChip::handleReceivedFrameJump(void* context) {
@@ -76,75 +94,83 @@
 }
 
 ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr<IThreadChipCallback>& in_callback) {
-    ndk::ScopedAStatus status;
-    AIBinder* binder;
+    ndk::ScopedAStatus status = initChip(in_callback);
 
-    VerifyOrExit(mCallback == nullptr,
-                 status = errorStatus(ERROR_BUSY, "Interface is already opened"));
-    VerifyOrExit(in_callback != nullptr,
-                 status = errorStatus(ERROR_INVALID_ARGS, "The callback is NULL"));
-    binder = in_callback->asBinder().get();
-    VerifyOrExit(binder != nullptr,
-                 status = errorStatus(ERROR_FAILED, "Failed to get the callback binder"));
-    mBinderDeathRecipient = AIBinder_DeathRecipient_new(clientDeathCallback);
-    VerifyOrExit(AIBinder_linkToDeath(binder, mBinderDeathRecipient, this) == STATUS_OK,
-                 status = errorStatus(ERROR_FAILED, "Failed to link the binder to death"));
-    VerifyOrExit(mSpinelInterface->Init(mUrl) == OT_ERROR_NONE,
-                 status = errorStatus(ERROR_FAILED, "Failed to initialize the interface"));
-
-    mCallback = in_callback;
-    ot::Posix::Mainloop::Manager::Get().Add(*this);
-    status = ndk::ScopedAStatus::ok();
-
-exit:
-    if (!status.isOk()) {
-        if (mBinderDeathRecipient != nullptr) {
-            AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
-            mBinderDeathRecipient = nullptr;
-        }
-        ALOGW("Open failed, error: %s", status.getDescription().c_str());
+    if (status.isOk()) {
+        AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this);
+        ALOGI("Open IThreadChip successfully");
     } else {
-        ALOGI("open()");
+        ALOGW("Failed to open IThreadChip: %s", status.getDescription().c_str());
     }
 
     return status;
 }
 
+ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr<IThreadChipCallback>& in_callback) {
+    if (in_callback == nullptr) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    } else if (mCallback == nullptr) {
+        if (mSpinelInterface->Init(mUrl) != OT_ERROR_NONE) {
+            return errorStatus(ERROR_FAILED, "Failed to initialize the interface");
+        }
+
+        mCallback = in_callback;
+        ot::Posix::Mainloop::Manager::Get().Add(*this);
+        return ndk::ScopedAStatus::ok();
+    } else {
+        return errorStatus(ERROR_BUSY, "Interface has been opened");
+    }
+}
+
 ndk::ScopedAStatus ThreadChip::close() {
-    VerifyOrExit(mCallback != nullptr);
-    mCallback = nullptr;
-    mSpinelInterface->Deinit();
+    ndk::ScopedAStatus status;
+    std::shared_ptr<IThreadChipCallback> callback = mCallback;
 
-    ot::Posix::Mainloop::Manager::Get().Remove(*this);
+    status = deinitChip();
+    if (status.isOk()) {
+        if (callback != nullptr) {
+            AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this);
+        }
 
-    AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
-    mBinderDeathRecipient = nullptr;
+        ALOGI("Close IThreadChip successfully");
+    } else {
+        ALOGW("Failed to close IThreadChip: %s", status.getDescription().c_str());
+    }
 
-exit:
-    ALOGI("close()");
-    return ndk::ScopedAStatus::ok();
+    return status;
+}
+
+ndk::ScopedAStatus ThreadChip::deinitChip() {
+    if (mCallback != nullptr) {
+        mSpinelInterface->Deinit();
+        ot::Posix::Mainloop::Manager::Get().Remove(*this);
+        mCallback = nullptr;
+        return ndk::ScopedAStatus::ok();
+    }
+
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
 }
 
 ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector<uint8_t>& in_frame) {
     ndk::ScopedAStatus status;
     otError error;
 
-    VerifyOrExit(mCallback != nullptr,
-                 status = errorStatus(ERROR_FAILED, "The interface is not open"));
-
-    error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
-                                        in_frame.size());
-    if (error == OT_ERROR_NONE) {
-        status = ndk::ScopedAStatus::ok();
-    } else if (error == OT_ERROR_NO_BUFS) {
-        status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
-    } else if (error == OT_ERROR_BUSY) {
-        status = errorStatus(ERROR_BUSY, "The interface is busy");
+    if (mCallback == nullptr) {
+        status = errorStatus(ERROR_FAILED, "The interface is not open");
     } else {
-        status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
+        error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
+                                            in_frame.size());
+        if (error == OT_ERROR_NONE) {
+            status = ndk::ScopedAStatus::ok();
+        } else if (error == OT_ERROR_NO_BUFS) {
+            status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
+        } else if (error == OT_ERROR_BUSY) {
+            status = errorStatus(ERROR_BUSY, "The interface is busy");
+        } else {
+            status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
+        }
     }
 
-exit:
     if (!status.isOk()) {
         ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str());
     }
@@ -152,8 +178,11 @@
     return status;
 }
 
-ndk::ScopedAStatus ThreadChip::reset() {
-    mSpinelInterface->HardwareReset();
+ndk::ScopedAStatus ThreadChip::hardwareReset() {
+    if (mSpinelInterface->HardwareReset() == OT_ERROR_NOT_IMPLEMENTED) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+
     ALOGI("reset()");
     return ndk::ScopedAStatus::ok();
 }
diff --git a/threadnetwork/aidl/default/thread_chip.hpp b/threadnetwork/aidl/default/thread_chip.hpp
index 294190a..1ab6d54 100644
--- a/threadnetwork/aidl/default/thread_chip.hpp
+++ b/threadnetwork/aidl/default/thread_chip.hpp
@@ -22,6 +22,7 @@
 #include "lib/spinel/spinel_interface.hpp"
 #include "mainloop.hpp"
 
+#include <android/binder_auto_utils.h>
 #include <android/binder_ibinder.h>
 #include <utils/Mutex.h>
 
@@ -33,26 +34,31 @@
 class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source {
   public:
     ThreadChip(char* url);
+    ~ThreadChip();
 
     ndk::ScopedAStatus open(const std::shared_ptr<IThreadChipCallback>& in_callback) override;
     ndk::ScopedAStatus close() override;
     ndk::ScopedAStatus sendSpinelFrame(const std::vector<uint8_t>& in_frame) override;
-    ndk::ScopedAStatus reset() override;
+    ndk::ScopedAStatus hardwareReset() override;
     void Update(otSysMainloopContext& context) override;
     void Process(const otSysMainloopContext& context) override;
 
   private:
-    static void clientDeathCallback(void* context);
-    void clientDeathCallback(void);
+    static void onBinderDiedJump(void* context);
+    void onBinderDied(void);
+    static void onBinderUnlinkedJump(void* context);
+    void onBinderUnlinked(void);
     static void handleReceivedFrameJump(void* context);
     void handleReceivedFrame(void);
     ndk::ScopedAStatus errorStatus(int32_t error, const char* message);
+    ndk::ScopedAStatus initChip(const std::shared_ptr<IThreadChipCallback>& in_callback);
+    ndk::ScopedAStatus deinitChip();
 
     ot::Url::Url mUrl;
     std::shared_ptr<ot::Spinel::SpinelInterface> mSpinelInterface;
     ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer;
     std::shared_ptr<IThreadChipCallback> mCallback;
-    AIBinder_DeathRecipient* mBinderDeathRecipient;
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
 };
 
 }  // namespace threadnetwork
diff --git a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
index 04c6dea..5925b54 100644
--- a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
+++ b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
@@ -91,7 +91,7 @@
             ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
 
     EXPECT_TRUE(thread_chip->open(callback).isOk());
-    EXPECT_TRUE(thread_chip->reset().isOk());
+    EXPECT_TRUE(thread_chip->hardwareReset().isOk());
 }
 
 TEST_P(ThreadNetworkAidl, SendSpinelFrame) {