Add Thread network HAL am: 24e527475f
am: 0e9126e492
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2625530 Change-Id: I635e8e70df32c2b2ae7f6446445078cbdf68a6bc Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
85ac25df61
19 changed files with 939 additions and 0 deletions
|
@ -834,4 +834,12 @@
|
|||
<regex-instance>.*</regex-instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="aidl" optional="true">
|
||||
<name>android.hardware.threadnetwork</name>
|
||||
<version>1</version>
|
||||
<interface>
|
||||
<name>IThreadChip</name>
|
||||
<regex-instance>chip[0-9]+</regex-instance>
|
||||
</interface>
|
||||
</hal>
|
||||
</compatibility-matrix>
|
||||
|
|
22
threadnetwork/aidl/Android.bp
Normal file
22
threadnetwork/aidl/Android.bp
Normal file
|
@ -0,0 +1,22 @@
|
|||
aidl_interface {
|
||||
name: "android.hardware.threadnetwork",
|
||||
vendor_available: true,
|
||||
srcs: [
|
||||
"android/hardware/threadnetwork/*.aidl",
|
||||
],
|
||||
|
||||
stability: "vintf",
|
||||
|
||||
backend: {
|
||||
java: {
|
||||
platform_apis: true,
|
||||
},
|
||||
ndk: {
|
||||
apex_available: [
|
||||
"//apex_available:platform",
|
||||
"com.android.threadnetwork",
|
||||
],
|
||||
min_sdk_version: "33",
|
||||
},
|
||||
},
|
||||
}
|
3
threadnetwork/aidl/OWNERS
Normal file
3
threadnetwork/aidl/OWNERS
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Bug component: 1288834
|
||||
zhanglongxia@google.com
|
||||
xyk@google.com
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
|
||||
// two cases:
|
||||
// 1). this is a frozen version file - do not edit this in any case.
|
||||
// 2). this is a 'current' file. If you make a backwards compatible change to
|
||||
// the interface (from the latest frozen version), the build system will
|
||||
// prompt you to update this file with `m <name>-update-api`.
|
||||
//
|
||||
// You must not make a backward incompatible change to any AIDL file built
|
||||
// with the aidl_interface module type with versions property set. The module
|
||||
// type is used to build AIDL files in a way that they can be used across
|
||||
// independently updatable components of the system. If a device is shipped
|
||||
// with such a backward incompatible change, it has a high risk of breaking
|
||||
// later when a module using the interface is updated, e.g., Mainline modules.
|
||||
|
||||
package android.hardware.threadnetwork;
|
||||
@VintfStability
|
||||
interface IThreadChip {
|
||||
void open(in android.hardware.threadnetwork.IThreadChipCallback callback);
|
||||
void close();
|
||||
void reset();
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
|
||||
// two cases:
|
||||
// 1). this is a frozen version file - do not edit this in any case.
|
||||
// 2). this is a 'current' file. If you make a backwards compatible change to
|
||||
// the interface (from the latest frozen version), the build system will
|
||||
// prompt you to update this file with `m <name>-update-api`.
|
||||
//
|
||||
// You must not make a backward incompatible change to any AIDL file built
|
||||
// with the aidl_interface module type with versions property set. The module
|
||||
// type is used to build AIDL files in a way that they can be used across
|
||||
// independently updatable components of the system. If a device is shipped
|
||||
// with such a backward incompatible change, it has a high risk of breaking
|
||||
// later when a module using the interface is updated, e.g., Mainline modules.
|
||||
|
||||
package android.hardware.threadnetwork;
|
||||
@VintfStability
|
||||
interface IThreadChipCallback {
|
||||
oneway void onReceiveSpinelFrame(in byte[] frame);
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.hardware.threadnetwork;
|
||||
|
||||
import android.hardware.threadnetwork.IThreadChipCallback;
|
||||
|
||||
/**
|
||||
* Controls a Thread radio chip on the device.
|
||||
*/
|
||||
|
||||
@VintfStability
|
||||
interface IThreadChip {
|
||||
/**
|
||||
* The operation failed for the internal error.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Service is busy and could not service the operation.
|
||||
*/
|
||||
const int ERROR_BUSY = 4;
|
||||
|
||||
/**
|
||||
* This method initializes the Thread HAL instance. If open completes
|
||||
* successfully, then the Thread HAL instance is ready to accept spinel
|
||||
* messages through sendSpinelFrame() API.
|
||||
*
|
||||
* @param callback A IThreadChipCallback callback instance.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Close the Thread HAL instance. Must free all resources.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* This method sends a spinel frame to the Thread HAL.
|
||||
*
|
||||
* This method should block until the frame is sent out successfully or
|
||||
* the method throws errors immediately.
|
||||
*
|
||||
* Spinel Protocol:
|
||||
* https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h
|
||||
*
|
||||
* @param frame The spinel frame to be sent.
|
||||
*
|
||||
* @throws ServiceSpecificException with one of the following values:
|
||||
* - ERROR_FAILED The Thread HAL failed to send the frame for an internal reason.
|
||||
* - ERROR_NO_BUFS Insufficient buffer space to send the frame.
|
||||
* - ERROR_BUSY The Thread HAL is busy.
|
||||
*/
|
||||
void sendSpinelFrame(in byte[] frame);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.hardware.threadnetwork;
|
||||
|
||||
@VintfStability
|
||||
interface IThreadChipCallback {
|
||||
/**
|
||||
* This method is called when a spinel frame is received. Thread network
|
||||
* will process the received spinel frame.
|
||||
*
|
||||
* Spinel Protocol:
|
||||
* https://github.com/openthread/openthread/blob/main/src/lib/spinel/spinel.h
|
||||
*
|
||||
* @param frame The received spinel frame.
|
||||
*/
|
||||
oneway void onReceiveSpinelFrame(in byte[] frame);
|
||||
}
|
56
threadnetwork/aidl/default/Android.bp
Normal file
56
threadnetwork/aidl/default/Android.bp
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// Copyright (c) 2022 Google LLC.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This document is the property of Google LLC, Inc. It is
|
||||
// considered proprietary and confidential information.
|
||||
//
|
||||
// This document may not be reproduced or transmitted in any form,
|
||||
// in whole or in part, without the express written permission of
|
||||
// Google LLC.
|
||||
|
||||
cc_defaults {
|
||||
name: "threadnetwork_service_default",
|
||||
vintf_fragments: ["threadnetwork-default.xml"],
|
||||
vendor: true,
|
||||
relative_install_path: "hw",
|
||||
|
||||
shared_libs: [
|
||||
"android.hardware.threadnetwork-V1-ndk",
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"libcutils",
|
||||
"liblog",
|
||||
"libutils",
|
||||
],
|
||||
|
||||
cppflags: [
|
||||
"-Wno-non-virtual-dtor",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"openthread-common",
|
||||
"openthread-hdlc",
|
||||
"openthread-platform",
|
||||
"openthread-posix",
|
||||
"openthread-url",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"main.cpp",
|
||||
"service.cpp",
|
||||
"thread_chip.cpp",
|
||||
"utils.cpp",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "android.hardware.threadnetwork-service.sim",
|
||||
defaults: ["threadnetwork_service_default"],
|
||||
init_rc: ["android.hardware.threadnetwork-service.sim.rc"],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "android.hardware.threadnetwork-service",
|
||||
defaults: ["threadnetwork_service_default"],
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
service vendor.threadnetwork_hal /vendor/bin/hw/android.hardware.threadnetwork-service.sim spinel+hdlc+forkpty:///vendor/bin/ot-rcp?forkpty-arg=1
|
||||
class hal
|
||||
user thread_network
|
30
threadnetwork/aidl/default/main.cpp
Normal file
30
threadnetwork/aidl/default/main.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include "service.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
CHECK_GT(argc, 1);
|
||||
aidl::android::hardware::threadnetwork::Service service(&argv[1], argc - 1);
|
||||
|
||||
ALOGI("Thread Network HAL is running");
|
||||
|
||||
service.startLoop();
|
||||
return EXIT_FAILURE; // should not reach
|
||||
}
|
87
threadnetwork/aidl/default/service.cpp
Normal file
87
threadnetwork/aidl/default/service.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "service.hpp"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/binder_process.h>
|
||||
|
||||
#include "thread_chip.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace threadnetwork {
|
||||
|
||||
Service::Service(char* urls[], int numUrls) : mBinderFd(-1) {
|
||||
CHECK_NE(urls, nullptr);
|
||||
CHECK_GT(numUrls, 0);
|
||||
|
||||
for (int i = 0; i < numUrls; i++) {
|
||||
auto threadChip = ndk::SharedRefBase::make<ThreadChip>(i, urls[i]);
|
||||
CHECK_NE(threadChip, nullptr);
|
||||
mThreadChips.push_back(std::move(threadChip));
|
||||
}
|
||||
|
||||
binder_status_t status = ABinderProcess_setupPolling(&mBinderFd);
|
||||
CHECK_EQ(status, ::STATUS_OK);
|
||||
CHECK_GE(mBinderFd, 0);
|
||||
}
|
||||
|
||||
void Service::Update(otSysMainloopContext& context) {
|
||||
FD_SET(mBinderFd, &context.mReadFdSet);
|
||||
context.mMaxFd = std::max(context.mMaxFd, mBinderFd);
|
||||
}
|
||||
|
||||
void Service::Process(const otSysMainloopContext& context) {
|
||||
if (FD_ISSET(mBinderFd, &context.mReadFdSet)) {
|
||||
ABinderProcess_handlePolledCommands();
|
||||
}
|
||||
}
|
||||
|
||||
void Service::startLoop(void) {
|
||||
const struct timeval kPollTimeout = {1, 0};
|
||||
otSysMainloopContext context;
|
||||
int rval;
|
||||
|
||||
ot::Posix::Mainloop::Manager::Get().Add(*this);
|
||||
|
||||
while (true) {
|
||||
context.mMaxFd = -1;
|
||||
context.mTimeout = kPollTimeout;
|
||||
|
||||
FD_ZERO(&context.mReadFdSet);
|
||||
FD_ZERO(&context.mWriteFdSet);
|
||||
FD_ZERO(&context.mErrorFdSet);
|
||||
|
||||
ot::Posix::Mainloop::Manager::Get().Update(context);
|
||||
|
||||
rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet,
|
||||
&context.mErrorFdSet, &context.mTimeout);
|
||||
|
||||
if (rval >= 0) {
|
||||
ot::Posix::Mainloop::Manager::Get().Process(context);
|
||||
} else if (errno != EINTR) {
|
||||
ALOGE("select() failed: %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace threadnetwork
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
40
threadnetwork/aidl/default/service.hpp
Normal file
40
threadnetwork/aidl/default/service.hpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mainloop.hpp"
|
||||
#include "thread_chip.hpp"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace threadnetwork {
|
||||
|
||||
class Service : public ot::Posix::Mainloop::Source {
|
||||
public:
|
||||
Service(char* urls[], int numUrls);
|
||||
|
||||
void Update(otSysMainloopContext& context) override;
|
||||
void Process(const otSysMainloopContext& context) override;
|
||||
void startLoop(void);
|
||||
|
||||
private:
|
||||
int mBinderFd;
|
||||
std::vector<std::shared_ptr<ThreadChip>> mThreadChips;
|
||||
};
|
||||
} // namespace threadnetwork
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
177
threadnetwork/aidl/default/thread_chip.cpp
Normal file
177
threadnetwork/aidl/default/thread_chip.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "thread_chip.hpp"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/binder_process.h>
|
||||
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace threadnetwork {
|
||||
|
||||
ThreadChip::ThreadChip(uint8_t id, char* url)
|
||||
: mUrl(),
|
||||
mInterface(handleReceivedFrame, this, mRxFrameBuffer),
|
||||
mRxFrameBuffer(),
|
||||
mCallback(nullptr) {
|
||||
const std::string name(std::string() + IThreadChip::descriptor + "/chip" + std::to_string(id));
|
||||
binder_status_t status;
|
||||
|
||||
ALOGI("ServiceName: %s, Url: %s", name.c_str(), url);
|
||||
CHECK_EQ(mUrl.Init(url), 0);
|
||||
status = AServiceManager_addService(asBinder().get(), name.c_str());
|
||||
CHECK_EQ(status, STATUS_OK);
|
||||
}
|
||||
|
||||
void ThreadChip::clientDeathCallback(void* context) {
|
||||
reinterpret_cast<ThreadChip*>(context)->clientDeathCallback();
|
||||
}
|
||||
|
||||
void ThreadChip::clientDeathCallback(void) {
|
||||
ALOGW("Thread Network HAL client is dead.");
|
||||
close();
|
||||
}
|
||||
|
||||
void ThreadChip::handleReceivedFrame(void* context) {
|
||||
static_cast<ThreadChip*>(context)->handleReceivedFrame();
|
||||
}
|
||||
|
||||
void ThreadChip::handleReceivedFrame(void) {
|
||||
if (mCallback != nullptr) {
|
||||
mCallback->onReceiveSpinelFrame(std::vector<uint8_t>(
|
||||
mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetFrame() + mRxFrameBuffer.GetLength()));
|
||||
}
|
||||
|
||||
mRxFrameBuffer.DiscardFrame();
|
||||
}
|
||||
|
||||
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(mInterface.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());
|
||||
}
|
||||
else
|
||||
{
|
||||
ALOGI("open()");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ThreadChip::close() {
|
||||
VerifyOrExit(mCallback != nullptr);
|
||||
mCallback = nullptr;
|
||||
mInterface.Deinit();
|
||||
|
||||
ot::Posix::Mainloop::Manager::Get().Remove(*this);
|
||||
|
||||
AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
|
||||
mBinderDeathRecipient = nullptr;
|
||||
|
||||
exit:
|
||||
ALOGI("close()");
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
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 = mInterface.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());
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ThreadChip::reset() {
|
||||
mInterface.OnRcpReset();
|
||||
ALOGI("reset()");
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
void ThreadChip::Update(otSysMainloopContext& context) {
|
||||
if (mCallback != nullptr) {
|
||||
mInterface.UpdateFdSet(context.mReadFdSet, context.mWriteFdSet, context.mMaxFd,
|
||||
context.mTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadChip::Process(const otSysMainloopContext& context) {
|
||||
struct RadioProcessContext radioContext;
|
||||
|
||||
if (mCallback != nullptr) {
|
||||
radioContext.mReadFdSet = &context.mReadFdSet;
|
||||
radioContext.mWriteFdSet = &context.mWriteFdSet;
|
||||
mInterface.Process(radioContext);
|
||||
}
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ThreadChip::errorStatus(int32_t error, const char* message) {
|
||||
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(error, message));
|
||||
}
|
||||
} // namespace threadnetwork
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
62
threadnetwork/aidl/default/thread_chip.hpp
Normal file
62
threadnetwork/aidl/default/thread_chip.hpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/threadnetwork/BnThreadChip.h>
|
||||
#include <aidl/android/hardware/threadnetwork/IThreadChipCallback.h>
|
||||
|
||||
#include "hdlc_interface.hpp"
|
||||
#include "lib/spinel/spinel_interface.hpp"
|
||||
#include "mainloop.hpp"
|
||||
|
||||
#include <android/binder_ibinder.h>
|
||||
#include <utils/Mutex.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace threadnetwork {
|
||||
|
||||
class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source {
|
||||
public:
|
||||
ThreadChip(uint8_t id, char* url);
|
||||
|
||||
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;
|
||||
void Update(otSysMainloopContext& context) override;
|
||||
void Process(const otSysMainloopContext& context) override;
|
||||
|
||||
private:
|
||||
static void clientDeathCallback(void* context);
|
||||
void clientDeathCallback(void);
|
||||
static void handleReceivedFrame(void* context);
|
||||
void handleReceivedFrame(void);
|
||||
ndk::ScopedAStatus errorStatus(int32_t error, const char* message);
|
||||
|
||||
ot::Url::Url mUrl;
|
||||
ot::Posix::HdlcInterface mInterface;
|
||||
ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer;
|
||||
std::shared_ptr<IThreadChipCallback> mCallback;
|
||||
AIBinder_DeathRecipient* mBinderDeathRecipient;
|
||||
};
|
||||
|
||||
} // namespace threadnetwork
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
6
threadnetwork/aidl/default/threadnetwork-default.xml
Normal file
6
threadnetwork/aidl/default/threadnetwork-default.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.threadnetwork</name>
|
||||
<fqname>IThreadChip/chip0</fqname>
|
||||
</hal>
|
||||
</manifest>
|
36
threadnetwork/aidl/default/utils.cpp
Normal file
36
threadnetwork/aidl/default/utils.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "utils.hpp"
|
||||
|
||||
#include <openthread/logging.h>
|
||||
|
||||
void otLogCritPlat(const char* format, ...) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
__android_log_vprint(ANDROID_LOG_FATAL, LOG_TAG, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void otLogWarnPlat(const char* format, ...) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
__android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, format, args);
|
||||
va_end(args);
|
||||
}
|
20
threadnetwork/aidl/default/utils.hpp
Normal file
20
threadnetwork/aidl/default/utils.hpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define LOG_TAG "threadnetwork_hal"
|
||||
#include <utils/Log.h>
|
38
threadnetwork/aidl/vts/Android.bp
Normal file
38
threadnetwork/aidl/vts/Android.bp
Normal file
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// Copyright (C) 2022 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
cc_test {
|
||||
name: "VtsHalThreadNetworkTargetTest",
|
||||
defaults: [
|
||||
"VtsHalTargetTestDefaults",
|
||||
"use_libaidlvintf_gtest_helper_static",
|
||||
],
|
||||
srcs: [
|
||||
"VtsHalThreadNetworkTargetTest.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libbinder",
|
||||
"libbinder_ndk",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.threadnetwork-V1-ndk",
|
||||
],
|
||||
test_suites: [
|
||||
"general-tests",
|
||||
"vts",
|
||||
],
|
||||
}
|
147
threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
Normal file
147
threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "ThreadNetworkHalTargetTest"
|
||||
|
||||
#include <future>
|
||||
|
||||
#include <aidl/Gtest.h>
|
||||
#include <aidl/Vintf.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_auto_utils.h>
|
||||
#include <android/binder_manager.h>
|
||||
#include <binder/IServiceManager.h>
|
||||
#include <binder/ProcessState.h>
|
||||
#include <log/log.h>
|
||||
|
||||
#include <aidl/android/hardware/threadnetwork/BnThreadChipCallback.h>
|
||||
#include <aidl/android/hardware/threadnetwork/IThreadChip.h>
|
||||
|
||||
using aidl::android::hardware::threadnetwork::BnThreadChipCallback;
|
||||
using aidl::android::hardware::threadnetwork::IThreadChip;
|
||||
using android::ProcessState;
|
||||
using ndk::ScopedAStatus;
|
||||
using ndk::SpAIBinder;
|
||||
|
||||
namespace {
|
||||
constexpr static int kCallbackTimeoutMs = 5000;
|
||||
} // namespace
|
||||
|
||||
class ThreadChipCallback : public BnThreadChipCallback {
|
||||
public:
|
||||
ThreadChipCallback(const std::function<void(const std::vector<uint8_t>&)>& on_spinel_message_cb)
|
||||
: on_spinel_message_cb_(on_spinel_message_cb) {}
|
||||
|
||||
ScopedAStatus onReceiveSpinelFrame(const std::vector<uint8_t>& in_aFrame) {
|
||||
on_spinel_message_cb_(in_aFrame);
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(const std::vector<uint8_t>&)> on_spinel_message_cb_;
|
||||
};
|
||||
|
||||
class ThreadNetworkAidl : public testing::TestWithParam<std::string> {
|
||||
public:
|
||||
virtual void SetUp() override {
|
||||
std::string serviceName = GetParam();
|
||||
|
||||
ALOGI("serviceName: %s", serviceName.c_str());
|
||||
|
||||
thread_chip = IThreadChip::fromBinder(
|
||||
SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
|
||||
ASSERT_NE(thread_chip, nullptr);
|
||||
}
|
||||
|
||||
virtual void TearDown() override { thread_chip->close(); }
|
||||
|
||||
std::shared_ptr<IThreadChip> thread_chip;
|
||||
};
|
||||
|
||||
TEST_P(ThreadNetworkAidl, Open) {
|
||||
std::shared_ptr<ThreadChipCallback> callback =
|
||||
ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
|
||||
|
||||
EXPECT_TRUE(thread_chip->open(callback).isOk());
|
||||
}
|
||||
|
||||
TEST_P(ThreadNetworkAidl, Close) {
|
||||
std::shared_ptr<ThreadChipCallback> callback =
|
||||
ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
|
||||
|
||||
EXPECT_TRUE(thread_chip->open(callback).isOk());
|
||||
EXPECT_TRUE(thread_chip->close().isOk());
|
||||
}
|
||||
|
||||
TEST_P(ThreadNetworkAidl, Reset) {
|
||||
std::shared_ptr<ThreadChipCallback> callback =
|
||||
ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
|
||||
|
||||
EXPECT_TRUE(thread_chip->open(callback).isOk());
|
||||
EXPECT_TRUE(thread_chip->reset().isOk());
|
||||
}
|
||||
|
||||
TEST_P(ThreadNetworkAidl, SendSpinelFrame) {
|
||||
const uint8_t kCmdOffset = 2;
|
||||
const uint8_t kMajorVersionOffset = 3;
|
||||
const uint8_t kMinorVersionOffset = 4;
|
||||
const std::vector<uint8_t> kGetSpinelProtocolVersion({0x81, 0x02, 0x01});
|
||||
const std::vector<uint8_t> kGetSpinelProtocolVersionResponse({0x81, 0x06, 0x01, 0x04, 0x03});
|
||||
uint8_t min_major_version = kGetSpinelProtocolVersionResponse[kMajorVersionOffset];
|
||||
uint8_t min_minor_version = kGetSpinelProtocolVersionResponse[kMinorVersionOffset];
|
||||
uint8_t major_version;
|
||||
uint8_t minor_version;
|
||||
std::promise<void> open_cb_promise;
|
||||
std::future<void> open_cb_future{open_cb_promise.get_future()};
|
||||
std::shared_ptr<ThreadChipCallback> callback;
|
||||
std::vector<uint8_t> received_frame;
|
||||
std::chrono::milliseconds timeout{kCallbackTimeoutMs};
|
||||
|
||||
callback = ndk::SharedRefBase::make<ThreadChipCallback>(
|
||||
[&](const std::vector<uint8_t>& in_aFrame) {
|
||||
if (in_aFrame.size() == kGetSpinelProtocolVersionResponse.size() &&
|
||||
in_aFrame[kCmdOffset] == kGetSpinelProtocolVersionResponse[kCmdOffset]) {
|
||||
major_version = in_aFrame[kMajorVersionOffset];
|
||||
minor_version = in_aFrame[kMinorVersionOffset];
|
||||
open_cb_promise.set_value();
|
||||
}
|
||||
});
|
||||
|
||||
ASSERT_NE(callback, nullptr);
|
||||
|
||||
EXPECT_TRUE(thread_chip->open(callback).isOk());
|
||||
|
||||
EXPECT_TRUE(thread_chip->sendSpinelFrame(kGetSpinelProtocolVersion).isOk());
|
||||
EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
|
||||
|
||||
EXPECT_GE(major_version, min_major_version);
|
||||
if (major_version == min_major_version) {
|
||||
EXPECT_GE(minor_version, min_minor_version);
|
||||
}
|
||||
}
|
||||
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThreadNetworkAidl);
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Thread, ThreadNetworkAidl,
|
||||
testing::ValuesIn(android::getAidlHalInstanceNames(IThreadChip::descriptor)),
|
||||
android::PrintInstanceNameToString);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
ProcessState::self()->setThreadPoolMaxThreadCount(1);
|
||||
ProcessState::self()->startThreadPool();
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
Loading…
Reference in a new issue