Merge "BluetoothAudio: Statically link HAL dependencies" into main
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/Android.bp b/threadnetwork/aidl/default/Android.bp
index 8b938d2..bcd5704 100644
--- a/threadnetwork/aidl/default/Android.bp
+++ b/threadnetwork/aidl/default/Android.bp
@@ -79,7 +79,6 @@
         "fuzzer.cpp",
     ],
 
-    required: ["ot-rcp"],
     fuzz_config: {
         cc: [
             "zhanglongxia@google.com",
diff --git a/threadnetwork/aidl/default/fuzzer.cpp b/threadnetwork/aidl/default/fuzzer.cpp
index 512708d..fb6e548 100644
--- a/threadnetwork/aidl/default/fuzzer.cpp
+++ b/threadnetwork/aidl/default/fuzzer.cpp
@@ -22,7 +22,7 @@
 using android::fuzzService;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-    char url[] = "spinel+hdlc+forkpty:///vendor/bin/ot-rcp?forkpty-arg=2";
+    char url[] = "spinel+hdlc+null:///dev/null";
     auto service = ndk::SharedRefBase::make<ThreadChip>(url);
 
     fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
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) {