1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "ThreadNetworkHalTargetTest"
18
19 #include <future>
20
21 #include <aidl/Gtest.h>
22 #include <aidl/Vintf.h>
23 #include <android-base/logging.h>
24 #include <android/binder_auto_utils.h>
25 #include <android/binder_manager.h>
26 #include <binder/IServiceManager.h>
27 #include <binder/ProcessState.h>
28 #include <log/log.h>
29
30 #include <aidl/android/hardware/threadnetwork/BnThreadChipCallback.h>
31 #include <aidl/android/hardware/threadnetwork/IThreadChip.h>
32
33 using aidl::android::hardware::threadnetwork::BnThreadChipCallback;
34 using aidl::android::hardware::threadnetwork::IThreadChip;
35 using android::ProcessState;
36 using ndk::ScopedAStatus;
37 using ndk::SpAIBinder;
38
39 namespace {
40 constexpr static int kCallbackTimeoutMs = 5000;
41 } // namespace
42
43 class ThreadChipCallback : public BnThreadChipCallback {
44 public:
ThreadChipCallback(const std::function<void (const std::vector<uint8_t> &)> & on_spinel_message_cb)45 ThreadChipCallback(const std::function<void(const std::vector<uint8_t>&)>& on_spinel_message_cb)
46 : on_spinel_message_cb_(on_spinel_message_cb) {}
47
onReceiveSpinelFrame(const std::vector<uint8_t> & in_aFrame)48 ScopedAStatus onReceiveSpinelFrame(const std::vector<uint8_t>& in_aFrame) {
49 on_spinel_message_cb_(in_aFrame);
50 return ScopedAStatus::ok();
51 }
52
53 private:
54 std::function<void(const std::vector<uint8_t>&)> on_spinel_message_cb_;
55 };
56
57 class ThreadNetworkAidl : public testing::TestWithParam<std::string> {
58 public:
SetUp()59 virtual void SetUp() override {
60 std::string serviceName = GetParam();
61
62 ALOGI("serviceName: %s", serviceName.c_str());
63
64 thread_chip = IThreadChip::fromBinder(
65 SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
66 ASSERT_NE(thread_chip, nullptr);
67 }
68
TearDown()69 virtual void TearDown() override { thread_chip->close(); }
70
71 std::shared_ptr<IThreadChip> thread_chip;
72 };
73
TEST_P(ThreadNetworkAidl,Open)74 TEST_P(ThreadNetworkAidl, Open) {
75 std::shared_ptr<ThreadChipCallback> callback =
76 ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
77
78 EXPECT_TRUE(thread_chip->open(callback).isOk());
79 }
80
TEST_P(ThreadNetworkAidl,Close)81 TEST_P(ThreadNetworkAidl, Close) {
82 std::shared_ptr<ThreadChipCallback> callback =
83 ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
84
85 EXPECT_TRUE(thread_chip->open(callback).isOk());
86 EXPECT_TRUE(thread_chip->close().isOk());
87 }
88
TEST_P(ThreadNetworkAidl,Reset)89 TEST_P(ThreadNetworkAidl, Reset) {
90 ndk::ScopedAStatus status;
91 std::shared_ptr<ThreadChipCallback> callback =
92 ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
93
94 EXPECT_TRUE(thread_chip->open(callback).isOk());
95 status = thread_chip->hardwareReset();
96 EXPECT_TRUE(status.isOk() || (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION));
97 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
98 GTEST_SKIP() << "Hardware reset is not supported";
99 }
100 }
101
TEST_P(ThreadNetworkAidl,SendSpinelFrame)102 TEST_P(ThreadNetworkAidl, SendSpinelFrame) {
103 const uint8_t kCmdOffset = 2;
104 const uint8_t kMajorVersionOffset = 3;
105 const uint8_t kMinorVersionOffset = 4;
106 const std::vector<uint8_t> kGetSpinelProtocolVersion({0x81, 0x02, 0x01});
107 const std::vector<uint8_t> kGetSpinelProtocolVersionResponse({0x81, 0x06, 0x01, 0x04, 0x03});
108 uint8_t min_major_version = kGetSpinelProtocolVersionResponse[kMajorVersionOffset];
109 uint8_t min_minor_version = kGetSpinelProtocolVersionResponse[kMinorVersionOffset];
110 uint8_t major_version;
111 uint8_t minor_version;
112 std::promise<void> open_cb_promise;
113 std::future<void> open_cb_future{open_cb_promise.get_future()};
114 std::shared_ptr<ThreadChipCallback> callback;
115 std::vector<uint8_t> received_frame;
116 std::chrono::milliseconds timeout{kCallbackTimeoutMs};
117
118 callback = ndk::SharedRefBase::make<ThreadChipCallback>(
119 [&](const std::vector<uint8_t>& in_aFrame) {
120 if (in_aFrame.size() == kGetSpinelProtocolVersionResponse.size() &&
121 in_aFrame[kCmdOffset] == kGetSpinelProtocolVersionResponse[kCmdOffset]) {
122 major_version = in_aFrame[kMajorVersionOffset];
123 minor_version = in_aFrame[kMinorVersionOffset];
124 open_cb_promise.set_value();
125 }
126 });
127
128 ASSERT_NE(callback, nullptr);
129
130 EXPECT_TRUE(thread_chip->open(callback).isOk());
131
132 EXPECT_TRUE(thread_chip->sendSpinelFrame(kGetSpinelProtocolVersion).isOk());
133 EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready);
134
135 EXPECT_GE(major_version, min_major_version);
136 if (major_version == min_major_version) {
137 EXPECT_GE(minor_version, min_minor_version);
138 }
139 }
140
141 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThreadNetworkAidl);
142 INSTANTIATE_TEST_SUITE_P(
143 Thread, ThreadNetworkAidl,
144 testing::ValuesIn(android::getAidlHalInstanceNames(IThreadChip::descriptor)),
145 android::PrintInstanceNameToString);
146
main(int argc,char ** argv)147 int main(int argc, char** argv) {
148 ::testing::InitGoogleTest(&argc, argv);
149 ProcessState::self()->setThreadPoolMaxThreadCount(1);
150 ProcessState::self()->startThreadPool();
151 return RUN_ALL_TESTS();
152 }
153