Merge "change the Thread Network HAL api from 'reset' to 'hardwareReset'" into main am: 086e138474 am: 715b1abf5b am: 39d9ddb327

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2649860

Change-Id: I32482790baea4aa13c993f1201d98572e58cc222
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Zhanglong Xia
2023-07-11 04:44:20 +00:00
committed by Automerger Merge Worker
5 changed files with 111 additions and 78 deletions

View File

@@ -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;
}

View File

@@ -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()` wont be reset and the resource allocated by `open()` wont be free.
* This method hardware resets the Thread radio chip via the physical reset pin.
* The callback registered by `open()` wont be reset and the resource allocated
* by `open()` wont 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.

View File

@@ -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);
}
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 @@ void ThreadChip::handleReceivedFrame(void) {
}
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 @@ 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();
}

View File

@@ -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

View File

@@ -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) {