Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 086e1384 authored by Zhanglong Xia's avatar Zhanglong Xia Committed by Gerrit Code Review
Browse files

Merge "change the Thread Network HAL api from 'reset' to 'hardwareReset'" into main

parents 9d0b975f a6165dcc
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -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;
}
+10 −11
Original line number Diff line number Diff line
@@ -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.
+88 −59
Original line number Diff line number Diff line
@@ -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 @@ ThreadChip::ThreadChip(char* url) : mUrl(), mRxFrameBuffer(), mCallback(nullptr)
        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);
}

ThreadChip::~ThreadChip() {
    AIBinder_DeathRecipient_delete(mDeathRecipient.get());
}

void ThreadChip::onBinderDiedJump(void* context) {
    reinterpret_cast<ThreadChip*>(context)->onBinderDied();
}

void ThreadChip::clientDeathCallback(void* context) {
    reinterpret_cast<ThreadChip*>(context)->clientDeathCallback();
void ThreadChip::onBinderDied(void) {
    ALOGW("Thread Network HAL client is dead");
}

void ThreadChip::clientDeathCallback(void) {
    ALOGW("Thread Network HAL client is dead.");
    close();
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,62 +94,70 @@ void ThreadChip::handleReceivedFrame(void) {
}

ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr<IThreadChipCallback>& in_callback) {
    ndk::ScopedAStatus status;
    AIBinder* binder;

    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"));
    ndk::ScopedAStatus status = initChip(in_callback);

    if (status.isOk()) {
        AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this);
        ALOGI("Open IThreadChip successfully");
    } else {
        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);
    status = ndk::ScopedAStatus::ok();
        return ndk::ScopedAStatus::ok();
    } else {
        return errorStatus(ERROR_BUSY, "Interface has been opened");
    }
}

exit:
    if (!status.isOk()) {
        if (mBinderDeathRecipient != nullptr) {
            AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
            mBinderDeathRecipient = nullptr;
ndk::ScopedAStatus ThreadChip::close() {
    ndk::ScopedAStatus status;
    std::shared_ptr<IThreadChipCallback> callback = mCallback;

    status = deinitChip();
    if (status.isOk()) {
        if (callback != nullptr) {
            AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this);
        }
        ALOGW("Open failed, error: %s", status.getDescription().c_str());

        ALOGI("Close IThreadChip successfully");
    } else {
        ALOGI("open()");
        ALOGW("Failed to close IThreadChip: %s", status.getDescription().c_str());
    }

    return status;
}

ndk::ScopedAStatus ThreadChip::close() {
    VerifyOrExit(mCallback != nullptr);
    mCallback = nullptr;
ndk::ScopedAStatus ThreadChip::deinitChip() {
    if (mCallback != nullptr) {
        mSpinelInterface->Deinit();

        ot::Posix::Mainloop::Manager::Get().Remove(*this);

    AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
    mBinderDeathRecipient = nullptr;

exit:
    ALOGI("close()");
        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"));

    if (mCallback == nullptr) {
        status = errorStatus(ERROR_FAILED, "The interface is not open");
    } else {
        error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
                                            in_frame.size());
        if (error == OT_ERROR_NONE) {
@@ -143,8 +169,8 @@ ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector<uint8_t>& in_fr
        } 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();
}
+10 −4
Original line number Diff line number Diff line
@@ -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 @@ namespace threadnetwork {
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
+1 −1
Original line number Diff line number Diff line
@@ -91,7 +91,7 @@ TEST_P(ThreadNetworkAidl, Reset) {
            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) {