aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-02-15 05:11:29 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-02-15 05:11:29 +0000
commitf781f63f9d734cfdfb6281ec14713786c05faa53 (patch)
tree7a87da4507a0b1e30e90fda5243f615e2a2dfde7
parent6c19e7427d11c48889f4a82c77d1961ac599a871 (diff)
parent9d31b5ced11684e6b89a70461e2cd67cb12c1a36 (diff)
downloadopenthread-android14-d1-s5-release.tar.gz
Change-Id: I73673e1b3a0a15062e06b3a437997e52b6227259
-rw-r--r--Android.bp123
-rw-r--r--src/android/thread_network_hal/hal_interface.cpp290
-rw-r--r--src/android/thread_network_hal/hal_interface.hpp210
-rw-r--r--src/android/thread_network_hal/vendor_interface.cpp116
-rw-r--r--src/posix/platform/mainloop.hpp6
5 files changed, 737 insertions, 8 deletions
diff --git a/Android.bp b/Android.bp
index 8bc8aade0..93f283d8c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -109,7 +109,7 @@ soong_config_module_type {
soong_config_string_variable {
name: "rcp_bus",
- values: ["spi", "uart"],
+ values: ["spi", "uart", "hal"],
}
ot_config_cc_defaults {
@@ -122,10 +122,9 @@ ot_config_cc_defaults {
spi: {
cflags: ["-DOPENTHREAD_POSIX_CONFIG_RCP_BUS=OT_POSIX_RCP_BUS_SPI"]
},
- uart: {
+ hal: {
cflags: [
- "-DOPENTHREAD_POSIX_CONFIG_RCP_BUS=OT_POSIX_RCP_BUS_UART",
- "-DOPENTHREAD_POSIX_CONFIG_RCP_PTY_ENABLE=1",
+ "-DOPENTHREAD_POSIX_CONFIG_RCP_BUS=OT_POSIX_RCP_BUS_VENDOR",
]
},
conditions_default: {
@@ -146,6 +145,7 @@ cc_library_static {
local_include_dirs: [
"include",
"src",
+ "src/android/thread_network_hal",
"src/cli",
"src/core",
"src/ncp",
@@ -173,6 +173,8 @@ cc_library_static {
],
srcs: [
+ "src/android/thread_network_hal/hal_interface.cpp",
+ "src/android/thread_network_hal/vendor_interface.cpp",
"src/core/api/backbone_router_api.cpp",
"src/core/api/backbone_router_ftd_api.cpp",
"src/core/api/border_agent_api.cpp",
@@ -556,6 +558,7 @@ cc_defaults {
"src/cli",
"src/core",
"src/ncp",
+ "src/lib/hdlc",
"third_party",
"third_party/mbedtls",
"third_party/mbedtls/repo/include",
@@ -586,6 +589,7 @@ cc_defaults {
cc_library_static {
name: "openthread-simulation",
+ vendor: true,
defaults: [
"ot_rcp_cflags_defaults",
@@ -606,13 +610,10 @@ cc_library_static {
"examples/platforms/simulation/system.c",
"examples/platforms/simulation/trel.c",
"examples/platforms/simulation/uart.c",
-
"examples/platforms/utils/link_metrics.cpp",
"examples/platforms/utils/mac_frame.cpp",
"examples/platforms/utils/soft_source_match_table.c",
-
"src/lib/platform/exit_code.c",
-
"third_party/mbedtls/repo/library/aes.c",
"third_party/mbedtls/repo/library/asn1parse.c",
"third_party/mbedtls/repo/library/asn1write.c",
@@ -643,6 +644,7 @@ cc_library_static {
cc_library_static {
name: "openthread-radio",
+ vendor: true,
defaults: [
"ot_rcp_cflags_defaults",
@@ -650,6 +652,9 @@ cc_library_static {
],
generated_headers: ["ot_version_header"],
+ shared_libs: [
+ "libcutils",
+ ],
srcs: [
"src/core/api/diags_api.cpp",
@@ -688,23 +693,71 @@ cc_library_static {
cc_library_static {
name: "openthread-hdlc",
+ vendor: true,
defaults: [
"ot_rcp_cflags_defaults",
"ot_simulation_cflags_defaults",
],
+ export_include_dirs: [
+ "include",
+ "src",
+ ],
srcs: [
"src/lib/hdlc/hdlc.cpp",
],
}
cc_library_static {
+ name: "openthread-url",
+ vendor: true,
+ local_include_dirs: [
+ "include",
+ "src",
+ "src/core",
+ "src/lib/url",
+ ],
+ export_include_dirs: [
+ "include",
+ "src",
+ ],
+ srcs: [
+ "src/lib/url/url.cpp",
+ ],
+}
+
+cc_library_static {
+ name: "openthread-platform",
+ vendor: true,
+ local_include_dirs: [
+ "include",
+ "src",
+ "src/core",
+ "src/lib/platform",
+ ],
+ export_include_dirs: [
+ "include",
+ "src",
+ ],
+ srcs: [
+ "src/lib/platform/exit_code.c",
+ ],
+}
+
+
+cc_library_static {
name: "openthread-spinel-rcp",
+ vendor: true,
defaults: [
"ot_rcp_cflags_defaults",
"ot_simulation_cflags_defaults",
],
+ export_include_dirs: [
+ "include",
+ "src",
+ ],
+
srcs: [
"src/lib/spinel/spinel.c",
"src/lib/spinel/spinel_buffer.cpp",
@@ -715,6 +768,7 @@ cc_library_static {
cc_library_static {
name: "openthread-rcp",
+ vendor: true,
defaults: [
"ot_rcp_cflags_defaults",
@@ -733,7 +787,7 @@ cc_library_static {
cc_binary {
name: "ot-rcp",
-
+ vendor: true,
defaults: [
"ot_rcp_cflags_defaults",
"ot_simulation_cflags_defaults",
@@ -760,3 +814,56 @@ cc_binary {
],
}
+cc_library_static {
+ name: "openthread-posix",
+ vendor: true,
+ local_include_dirs: [
+ "include",
+ "src",
+ "src/core",
+ "src/lib/platform",
+ "src/posix/platform",
+ "src/posix/platform/include",
+ ],
+ export_include_dirs: [
+ "include",
+ "src/core",
+ "src/posix/platform",
+ "src/posix/platform/include",
+ ],
+
+ cflags: [
+ "-DOPENTHREAD_POSIX_CONFIG_RCP_BUS=OT_POSIX_RCP_BUS_UART",
+ "-DOPENTHREAD_OSIX_CONFIG_RCP_PTY_ENABLE=1",
+ ],
+
+ cppflags: [
+ "-Wno-non-virtual-dtor",
+ ],
+
+ srcs: [
+ "src/posix/platform/alarm.cpp",
+ "src/posix/platform/mainloop.cpp",
+ "src/posix/platform/hdlc_interface.cpp",
+ ],
+}
+
+cc_library_static {
+ name: "openthread-common",
+ vendor: true,
+ local_include_dirs: [
+ "include",
+ "src",
+ "src/core",
+ ],
+
+ export_include_dirs: [
+ "include",
+ "src/core",
+ ],
+
+ srcs: [
+ "src/core/common/error.cpp",
+ "src/core/api/error_api.cpp",
+ ],
+}
diff --git a/src/android/thread_network_hal/hal_interface.cpp b/src/android/thread_network_hal/hal_interface.cpp
new file mode 100644
index 000000000..25d629206
--- /dev/null
+++ b/src/android/thread_network_hal/hal_interface.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2022, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes the implementation for the IPC Binder interface to radio Co-Processor (RCP).
+ */
+
+#include "hal_interface.hpp"
+
+#if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR
+
+#include <linux/gpio.h>
+#include <linux/ioctl.h>
+#include <linux/spi/spidev.h>
+#include <sys/select.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+namespace ot {
+namespace Posix {
+using ::aidl::android::hardware::threadnetwork::IThreadChip;
+using ::aidl::android::hardware::threadnetwork::IThreadChipCallback;
+using ::ndk::ScopedAStatus;
+
+using ot::Spinel::SpinelInterface;
+
+HalInterface::HalInterface(SpinelInterface::ReceiveFrameCallback aCallback,
+ void * aCallbackContext,
+ SpinelInterface::RxFrameBuffer & aFrameBuffer)
+ : mRxFrameCallback(aCallback)
+ , mRxFrameContext(aCallbackContext)
+ , mRxFrameBuffer(aFrameBuffer)
+ , mThreadChip(nullptr)
+ , mThreadChipCallback(nullptr)
+ , mDeathRecipient(AIBinder_DeathRecipient_new(BinderDeathCallback))
+ , mBinderFd(-1)
+{
+ OT_ASSERT(mRxFrameCallback != nullptr);
+}
+
+otError HalInterface::Init(const Url::Url &aRadioUrl)
+{
+ static const std::string kServicePrefix = std::string() + IThreadChip::descriptor + "/chip";
+ uint32_t id = 0;
+ const char * value;
+ binder_status_t binderStatus;
+ ScopedAStatus ndkStatus;
+ std::shared_ptr<ThreadChipCallback> callback;
+ std::string serviceName;
+
+ binderStatus = ABinderProcess_setupPolling(&mBinderFd);
+ VerifyOrDie(binderStatus == ::STATUS_OK, OT_EXIT_FAILURE);
+ VerifyOrDie(mBinderFd >= 0, OT_EXIT_FAILURE);
+
+ if ((value = aRadioUrl.GetValue("id")) != nullptr)
+ {
+ id = static_cast<uint32_t>(atoi(value));
+ }
+
+ serviceName = kServicePrefix + std::to_string(id);
+ otLogInfoPlat("[HAL] Wait for getting the service %s ...", serviceName.c_str());
+ mThreadChip = IThreadChip::fromBinder(::ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
+ VerifyOrDie(mThreadChip != nullptr, OT_EXIT_FAILURE);
+
+ callback = ndk::SharedRefBase::make<ThreadChipCallback>(this);
+ VerifyOrDie(callback->asBinder().get() != nullptr, OT_EXIT_FAILURE);
+
+ mThreadChipCallback = IThreadChipCallback::fromBinder(callback->asBinder());
+ VerifyOrDie(mThreadChipCallback != nullptr, OT_EXIT_FAILURE);
+
+ VerifyOrDie(AIBinder_linkToDeath(mThreadChip->asBinder().get(), mDeathRecipient.get(), this) == STATUS_OK,
+ OT_EXIT_FAILURE);
+
+ ndkStatus = mThreadChip->open(mThreadChipCallback);
+ if (!ndkStatus.isOk())
+ {
+ otLogCritPlat("[HAL] Open the HAL interface failed: %s", ndkStatus.getMessage());
+ DieNow(OT_EXIT_FAILURE);
+ }
+
+ otLogInfoPlat("[HAL] Successfully got the service %s", serviceName.c_str());
+
+ return OT_ERROR_NONE;
+}
+
+void HalInterface::BinderDeathCallback(void *aContext)
+{
+ OT_UNUSED_VARIABLE(aContext);
+
+ otLogInfoPlat("[HAL] Thread network HAL is dead, exit!");
+ DieNow(OT_EXIT_FAILURE);
+}
+
+HalInterface::~HalInterface(void)
+{
+ Deinit();
+}
+
+void HalInterface::Deinit(void)
+{
+ if (mThreadChip != nullptr)
+ {
+ mThreadChip->close();
+ AIBinder_unlinkToDeath(mThreadChip->asBinder().get(), mDeathRecipient.get(), this);
+ mThreadChip = nullptr;
+ mThreadChipCallback = nullptr;
+ }
+
+ if (mBinderFd >= 0)
+ {
+ close(mBinderFd);
+ }
+}
+
+uint32_t HalInterface::GetBusSpeed(void) const
+{
+ static const uint32_t kBusSpeed = 1000000;
+ return kBusSpeed;
+}
+
+void HalInterface::OnRcpReset(void)
+{
+ mThreadChip->reset();
+}
+
+void HalInterface::UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMaxFd, struct timeval &aTimeout)
+{
+ OT_UNUSED_VARIABLE(aWriteFdSet);
+ OT_UNUSED_VARIABLE(aTimeout);
+
+ if (mBinderFd >= 0)
+ {
+ FD_SET(mBinderFd, &aReadFdSet);
+ aMaxFd = std::max(aMaxFd, mBinderFd);
+ }
+}
+
+void HalInterface::Process(const RadioProcessContext &aContext)
+{
+ if ((mBinderFd >= 0) && FD_ISSET(mBinderFd, aContext.mReadFdSet))
+ {
+ ABinderProcess_handlePolledCommands();
+ }
+}
+
+otError HalInterface::WaitForFrame(uint64_t aTimeoutUs)
+{
+ otError error = OT_ERROR_NONE;
+ struct timeval timeout;
+ fd_set readFdSet;
+ int ret;
+
+ VerifyOrExit(mBinderFd >= 0, error = OT_ERROR_FAILED);
+
+ timeout.tv_sec = static_cast<time_t>(aTimeoutUs / US_PER_S);
+ timeout.tv_usec = static_cast<suseconds_t>(aTimeoutUs % US_PER_S);
+
+ FD_ZERO(&readFdSet);
+ FD_SET(mBinderFd, &readFdSet);
+
+ ret = select(mBinderFd + 1, &readFdSet, nullptr, nullptr, &timeout);
+
+ if ((ret > 0) && FD_ISSET(mBinderFd, &readFdSet))
+ {
+ ABinderProcess_handlePolledCommands();
+ }
+ else if (ret == 0)
+ {
+ ExitNow(error = OT_ERROR_RESPONSE_TIMEOUT);
+ }
+ else if (errno != EINTR)
+ {
+ DieNow(OT_EXIT_ERROR_ERRNO);
+ }
+
+exit:
+
+ if (error != OT_ERROR_NONE)
+ {
+ otLogWarnPlat("[HAL] Wait for frame failed: %s", otThreadErrorToString(error));
+ }
+
+ return error;
+}
+
+otError HalInterface::SendFrame(const uint8_t *aFrame, uint16_t aLength)
+{
+ otError error = OT_ERROR_NONE;
+ ScopedAStatus status;
+
+ VerifyOrExit((aFrame != nullptr) && (aLength <= kMaxFrameSize), error = OT_ERROR_INVALID_ARGS);
+ status = mThreadChip->sendSpinelFrame(std::vector<uint8_t>(aFrame, aFrame + aLength));
+ VerifyOrExit(!status.isOk(), error = OT_ERROR_NONE);
+ error = StatusToError(status);
+ otLogWarnPlat("[HAL] Send frame to HAL interface failed: %s", otThreadErrorToString(error));
+
+exit:
+ return error;
+}
+
+void HalInterface::ReceiveFrameCallback(const std::vector<uint8_t> &aFrame)
+{
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(aFrame.size() > 0, error = OT_ERROR_FAILED);
+
+ for (uint32_t i = 0; i < aFrame.size(); i++)
+ {
+ if ((error = mRxFrameBuffer.WriteByte(aFrame[i])) != OT_ERROR_NONE)
+ {
+ otLogNotePlat("[HAL] Drop the received spinel frame: %s", otThreadErrorToString(error));
+ mRxFrameBuffer.DiscardFrame();
+ ExitNow();
+ }
+ }
+
+ mRxFrameCallback(mRxFrameContext);
+
+exit:
+ return;
+}
+
+otError HalInterface::StatusToError(ScopedAStatus &aStatus)
+{
+ otError error = OT_ERROR_FAILED;
+
+ VerifyOrExit(!aStatus.isOk(), error = OT_ERROR_NONE);
+
+ if (aStatus.getExceptionCode() == EX_ILLEGAL_STATE)
+ {
+ error = OT_ERROR_INVALID_STATE;
+ }
+ else if (aStatus.getExceptionCode() == EX_ILLEGAL_ARGUMENT)
+ {
+ error = OT_ERROR_INVALID_ARGS;
+ }
+ else if (aStatus.getExceptionCode() == EX_SERVICE_SPECIFIC)
+ {
+ switch (aStatus.getServiceSpecificError())
+ {
+ case IThreadChip::ERROR_FAILED:
+ error = OT_ERROR_FAILED;
+ break;
+ case IThreadChip::ERROR_BUSY:
+ error = OT_ERROR_BUSY;
+ break;
+ case IThreadChip::ERROR_NO_BUFS:
+ error = OT_ERROR_NO_BUFS;
+ break;
+ default:
+ error = OT_ERROR_FAILED;
+ break;
+ }
+ }
+
+exit:
+ return error;
+}
+
+} // namespace Posix
+} // namespace ot
+
+#endif // OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR
diff --git a/src/android/thread_network_hal/hal_interface.hpp b/src/android/thread_network_hal/hal_interface.hpp
new file mode 100644
index 000000000..da1939017
--- /dev/null
+++ b/src/android/thread_network_hal/hal_interface.hpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2022, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes definitions for the IPC binder interface to radio (RCP).
+ */
+
+#ifndef ANDROID_THREAD_NETWORK_HAL_INTERFACE_HPP_
+#define ANDROID_THREAD_NETWORK_HAL_INTERFACE_HPP_
+
+#include "openthread-posix-config.h"
+
+#include "platform-posix.h"
+#include "lib/spinel/spinel_interface.hpp"
+
+#include <openthread/openthread-system.h>
+
+#if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR
+
+#include <aidl/android/hardware/threadnetwork/BnThreadChipCallback.h>
+#include <aidl/android/hardware/threadnetwork/IThreadChip.h>
+#include <aidl/android/hardware/threadnetwork/IThreadChipCallback.h>
+
+namespace ot {
+namespace Posix {
+
+/**
+ * This class defines an IPC Binder interface to the Radio Co-processor (RCP).
+ *
+ */
+class HalInterface
+{
+public:
+ /**
+ * This constructor initializes the object.
+ *
+ * @param[in] aCallback A reference to a `Callback` object.
+ * @param[in] aCallbackContext The context pointer passed to the callback.
+ * @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object.
+ *
+ */
+ HalInterface(Spinel::SpinelInterface::ReceiveFrameCallback aCallback,
+ void *aCallbackContext,
+ Spinel::SpinelInterface::RxFrameBuffer &aFrameBuffer);
+
+ /**
+ * This destructor deinitializes the object.
+ *
+ */
+ ~HalInterface(void);
+
+ /**
+ * This method initializes the interface to the Radio Co-processor (RCP).
+ *
+ * @note This method should be called before reading and sending spinel frames to the interface.
+ *
+ * @param[in] aRadioUrl Arguments parsed from radio url.
+ *
+ * @retval OT_ERROR_NONE The interface is initialized successfully.
+ * @retval OT_ERROR_ALREADY The interface is already initialized.
+ * @retval OT_ERROR_INVALID_ARGS The UART device or executable cannot be found or failed to open/run.
+ *
+ */
+ otError Init(const Url::Url &aRadioUrl);
+
+ /**
+ * This method deinitializes the interface to the RCP.
+ *
+ */
+ void Deinit(void);
+
+ /**
+ * This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket.
+ *
+ * @param[in] aFrame A pointer to buffer containing the spinel frame to send.
+ * @param[in] aLength The length (number of bytes) in the frame.
+ *
+ * @retval OT_ERROR_NONE Successfully encoded and sent the spinel frame.
+ * @retval OT_ERROR_BUSY Failed due to another operation is on going.
+ * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame.
+ * @retval OT_ERROR_FAILED Failed to call the HAL to send the frame.
+ *
+ */
+ otError SendFrame(const uint8_t *aFrame, uint16_t aLength);
+
+ /**
+ * This method waits for receiving part or all of spinel frame within specified interval.
+ *
+ * @param[in] aTimeout The timeout value in microseconds.
+ *
+ * @retval OT_ERROR_NONE Part or all of spinel frame is received.
+ * @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout.
+ *
+ */
+ otError WaitForFrame(uint64_t aTimeoutUs);
+
+ /**
+ * This method updates the file descriptor sets with file descriptors used by the radio driver.
+ *
+ * @param[inout] aReadFdSet A reference to the read file descriptors.
+ * @param[inout] aWriteFdSet A reference to the write file descriptors.
+ * @param[inout] aMaxFd A reference to the max file descriptor.
+ * @param[inout] aTimeout A reference to the timeout.
+ *
+ */
+ void UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMaxFd, struct timeval &aTimeout);
+
+ /**
+ * This method performs radio driver processing.
+ *
+ * @param[in] aContext The context containing fd_sets.
+ *
+ */
+ void Process(const RadioProcessContext &aContext);
+
+ /**
+ * This method returns the bus speed between the host and the radio.
+ *
+ * @returns Bus speed in bits/second.
+ *
+ */
+ uint32_t GetBusSpeed(void) const;
+
+ /**
+ * This method is called when RCP failure detected and resets internal states of the interface.
+ *
+ */
+ void OnRcpReset(void);
+
+ /**
+ * This method is called when RCP is reset to recreate the connection with it.
+ * Intentionally empty.
+ *
+ */
+ otError ResetConnection(void) { return OT_ERROR_NONE; }
+
+private:
+ void ReceiveFrameCallback(const std::vector<uint8_t> &aFrame);
+ static void BinderDeathCallback(void *aContext);
+ otError StatusToError(::ndk::ScopedAStatus &aStatus);
+
+ class ThreadChipCallback : public ::aidl::android::hardware::threadnetwork::BnThreadChipCallback
+ {
+ public:
+ ThreadChipCallback(HalInterface *aInterface)
+ : mInterface(aInterface)
+ {
+ }
+
+ ::ndk::ScopedAStatus onReceiveSpinelFrame(const std::vector<uint8_t> &in_aFrame)
+ {
+ mInterface->ReceiveFrameCallback(in_aFrame);
+ return ndk::ScopedAStatus::ok();
+ }
+
+ private:
+ HalInterface *mInterface;
+ };
+
+ enum
+ {
+ kMaxFrameSize = Spinel::SpinelInterface::kMaxFrameSize,
+ };
+
+ Spinel::SpinelInterface::ReceiveFrameCallback mRxFrameCallback;
+ void *mRxFrameContext;
+ Spinel::SpinelInterface::RxFrameBuffer &mRxFrameBuffer;
+
+ std::shared_ptr<::aidl::android::hardware::threadnetwork::IThreadChip> mThreadChip;
+ std::shared_ptr<::aidl::android::hardware::threadnetwork::IThreadChipCallback> mThreadChipCallback;
+
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+ int mBinderFd;
+
+ // Non-copyable, intentionally not implemented.
+ HalInterface(const HalInterface &);
+ HalInterface &operator=(const HalInterface &);
+};
+
+} // namespace Posix
+} // namespace ot
+
+#endif // OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR
+#endif // ANDROID_THREAD_NETWORK_HAL_INTERFACE_HPP_
diff --git a/src/android/thread_network_hal/vendor_interface.cpp b/src/android/thread_network_hal/vendor_interface.cpp
new file mode 100644
index 000000000..fb8c66fc2
--- /dev/null
+++ b/src/android/thread_network_hal/vendor_interface.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2022, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes the implementation for the vendor defined radio spinel interface
+ * to radio Co-Processor (RCP).
+ */
+
+#include "vendor_interface.hpp"
+
+#if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR
+
+#include <linux/gpio.h>
+#include <linux/ioctl.h>
+#include <linux/spi/spidev.h>
+#include <sys/select.h>
+
+#include <memory>
+
+#include "hal_interface.hpp"
+
+namespace ot {
+namespace Posix {
+using ot::Spinel::SpinelInterface;
+
+HalInterface *sHalInterface = nullptr;
+
+VendorInterface::VendorInterface(SpinelInterface::ReceiveFrameCallback aCallback,
+ void *aCallbackContext,
+ SpinelInterface::RxFrameBuffer &aFrameBuffer)
+{
+ sHalInterface = new HalInterface(aCallback, aCallbackContext, aFrameBuffer);
+ assert(sHalInterface != nullptr);
+}
+
+otError VendorInterface::Init(const Url::Url &aRadioUrl)
+{
+ return sHalInterface->Init(aRadioUrl);
+}
+
+VendorInterface::~VendorInterface(void)
+{
+ sHalInterface->Deinit();
+ delete sHalInterface;
+ sHalInterface = nullptr;
+}
+
+void VendorInterface::Deinit(void)
+{
+ sHalInterface->Deinit();
+}
+
+uint32_t VendorInterface::GetBusSpeed(void) const
+{
+ return sHalInterface->GetBusSpeed();
+}
+
+void VendorInterface::OnRcpReset(void)
+{
+ sHalInterface->OnRcpReset();
+}
+
+void VendorInterface::UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMaxFd, struct timeval &aTimeout)
+{
+ sHalInterface->UpdateFdSet(aReadFdSet, aWriteFdSet, aMaxFd, aTimeout);
+}
+
+void VendorInterface::Process(const RadioProcessContext &aContext)
+{
+ sHalInterface->Process(aContext);
+}
+
+otError VendorInterface::WaitForFrame(uint64_t aTimeoutUs)
+{
+ return sHalInterface->WaitForFrame(aTimeoutUs);
+}
+
+otError VendorInterface::SendFrame(const uint8_t *aFrame, uint16_t aLength)
+{
+ return sHalInterface->SendFrame(aFrame, aLength);
+}
+
+otError VendorInterface::ResetConnection(void)
+{
+ return sHalInterface->ResetConnection();
+}
+} // namespace Posix
+} // namespace ot
+
+#endif // OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_SPI
diff --git a/src/posix/platform/mainloop.hpp b/src/posix/platform/mainloop.hpp
index d4f6ac8ff..4f0fa7cc9 100644
--- a/src/posix/platform/mainloop.hpp
+++ b/src/posix/platform/mainloop.hpp
@@ -65,6 +65,12 @@ public:
*/
virtual void Process(const otSysMainloopContext &aContext) = 0;
+ /**
+ * This method marks desturctor virtual method.
+ *
+ */
+ virtual ~Source() = default;
+
private:
Source *mNext = nullptr;
};