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 e4d4cbe788..607ceb398d 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 @@ package android.hardware.threadnetwork; 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 eebaa46983..e695623286 100644 --- a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl +++ b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl @@ -29,20 +29,15 @@ interface IThreadChip { */ 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 @@ interface IThreadChip { * * @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 @@ interface IThreadChip { 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 94d1e93cbe..3d38cb841b 100644 --- a/threadnetwork/aidl/default/thread_chip.cpp +++ b/threadnetwork/aidl/default/thread_chip.cpp @@ -17,6 +17,8 @@ #include "thread_chip.hpp" #include +#include +#include #include #include #include @@ -46,20 +48,36 @@ ThreadChip::ThreadChip(char* url) : mUrl(), mRxFrameBuffer(), mCallback(nullptr) mSpinelInterface = std::make_shared(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(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(context)->onBinderDied(); +} + +void ThreadChip::onBinderDied(void) { + ALOGW("Thread Network HAL client is dead"); +} + +void ThreadChip::onBinderUnlinkedJump(void* context) { + reinterpret_cast(context)->onBinderUnlinked(); +} + +void ThreadChip::onBinderUnlinked(void) { + ALOGW("ThreadChip binder is unlinked"); + deinitChip(); } void ThreadChip::handleReceivedFrameJump(void* context) { @@ -76,75 +94,83 @@ void ThreadChip::handleReceivedFrame(void) { } ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr& 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& 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 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& in_frame) { ndk::ScopedAStatus status; otError error; - VerifyOrExit(mCallback != nullptr, - status = errorStatus(ERROR_FAILED, "The interface is not open")); - - error = mSpinelInterface->SendFrame(reinterpret_cast(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(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 @@ exit: 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 294190a658..1ab6d544d1 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 #include #include @@ -33,26 +34,31 @@ namespace threadnetwork { class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source { public: ThreadChip(char* url); + ~ThreadChip(); ndk::ScopedAStatus open(const std::shared_ptr& in_callback) override; ndk::ScopedAStatus close() override; ndk::ScopedAStatus sendSpinelFrame(const std::vector& 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& in_callback); + ndk::ScopedAStatus deinitChip(); ot::Url::Url mUrl; std::shared_ptr mSpinelInterface; ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer; std::shared_ptr 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 04c6deaf2a..5925b54b6a 100644 --- a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp +++ b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp @@ -91,7 +91,7 @@ TEST_P(ThreadNetworkAidl, Reset) { ndk::SharedRefBase::make([](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) {