Add Thread network HAL
Bug: b/203492431
Test: Build and run the VTS test and run otbr-agent on Android emulator.
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:b82b0478059dd6203f43d5917558e34fd4ed44d5)
Merged-In: If58b5a8c75e40376ae6c6e93554afe750496308b
Change-Id: If58b5a8c75e40376ae6c6e93554afe750496308b
diff --git a/threadnetwork/aidl/vts/Android.bp b/threadnetwork/aidl/vts/Android.bp
new file mode 100644
index 0000000..864e885
--- /dev/null
+++ b/threadnetwork/aidl/vts/Android.bp
@@ -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",
+ ],
+}
diff --git a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
new file mode 100644
index 0000000..04c6dea
--- /dev/null
+++ b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
@@ -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();
+}