1 /*
2 * Copyright (C) 2023 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 #include "chre_host/hal_client.h"
17 #include "chre_host/hal_error.h"
18
19 #include <unordered_set>
20
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23
24 #include <aidl/android/hardware/contexthub/IContextHub.h>
25
26 namespace android::chre {
27
28 namespace {
29 using ::aidl::android::hardware::contexthub::ContextHubMessage;
30 using ::aidl::android::hardware::contexthub::HostEndpointInfo;
31 using ::aidl::android::hardware::contexthub::IContextHub;
32 using ::aidl::android::hardware::contexthub::IContextHubCallbackDefault;
33 using ::aidl::android::hardware::contexthub::IContextHubDefault;
34
35 using ::ndk::ScopedAStatus;
36
37 using ::testing::_;
38 using ::testing::ByMove;
39 using ::testing::Field;
40 using ::testing::IsEmpty;
41 using ::testing::Return;
42 using ::testing::UnorderedElementsAre;
43
44 using HostEndpointId = char16_t;
45 constexpr HostEndpointId kEndpointId = 0x10;
46
47 class HalClientForTest : public HalClient {
48 public:
HalClientForTest(const std::shared_ptr<IContextHub> & contextHub,const std::vector<HostEndpointId> & connectedEndpoints,const std::shared_ptr<IContextHubCallback> & callback=ndk::SharedRefBase::make<IContextHubCallbackDefault> ())49 HalClientForTest(const std::shared_ptr<IContextHub> &contextHub,
50 const std::vector<HostEndpointId> &connectedEndpoints,
51 const std::shared_ptr<IContextHubCallback> &callback =
52 ndk::SharedRefBase::make<IContextHubCallbackDefault>())
53 : HalClient(callback) {
54 mContextHub = contextHub;
55 for (const HostEndpointId &endpointId : connectedEndpoints) {
56 mConnectedEndpoints[endpointId] = {.hostEndpointId = endpointId};
57 }
58 }
59
getConnectedEndpointIds()60 std::unordered_set<HostEndpointId> getConnectedEndpointIds() {
61 std::unordered_set<HostEndpointId> result{};
62 for (const auto &[endpointId, unusedEndpointInfo] : mConnectedEndpoints) {
63 result.insert(endpointId);
64 }
65 return result;
66 }
67
getClientCallback()68 HalClientCallback *getClientCallback() {
69 return mCallback.get();
70 }
71 };
72
73 class MockContextHub : public IContextHubDefault {
74 public:
75 MOCK_METHOD(ScopedAStatus, onHostEndpointConnected,
76 (const HostEndpointInfo &info), (override));
77 MOCK_METHOD(ScopedAStatus, onHostEndpointDisconnected,
78 (HostEndpointId endpointId), (override));
79 MOCK_METHOD(ScopedAStatus, queryNanoapps, (int32_t icontextHubId),
80 (override));
81 MOCK_METHOD(ScopedAStatus, sendMessageToHub,
82 (int32_t contextHubId, const ContextHubMessage &message),
83 (override));
84 };
85
86 } // namespace
87
TEST(HalClientTest,EndpointConnectionBasic)88 TEST(HalClientTest, EndpointConnectionBasic) {
89 auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
90 const HostEndpointInfo kInfo = {
91 .hostEndpointId = kEndpointId,
92 .type = HostEndpointInfo::Type::NATIVE,
93 .packageName = "HalClientTest",
94 .attributionTag{},
95 };
96
97 auto halClient = std::make_unique<HalClientForTest>(
98 mockContextHub, std::vector<HostEndpointId>{});
99 EXPECT_THAT(halClient->getConnectedEndpointIds(), IsEmpty());
100
101 EXPECT_CALL(*mockContextHub,
102 onHostEndpointConnected(
103 Field(&HostEndpointInfo::hostEndpointId, kEndpointId)))
104 .WillOnce(Return(ScopedAStatus::ok()));
105
106 halClient->connectEndpoint(kInfo);
107 EXPECT_THAT(halClient->getConnectedEndpointIds(),
108 UnorderedElementsAre(kEndpointId));
109 }
110
TEST(HalClientTest,EndpointConnectionMultipleRequests)111 TEST(HalClientTest, EndpointConnectionMultipleRequests) {
112 auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
113 const HostEndpointInfo kInfo = {
114 .hostEndpointId = kEndpointId,
115 .type = HostEndpointInfo::Type::NATIVE,
116 .packageName = "HalClientTest",
117 .attributionTag{},
118 };
119
120 auto halClient = std::make_unique<HalClientForTest>(
121 mockContextHub, std::vector<HostEndpointId>{});
122 EXPECT_THAT(halClient->getConnectedEndpointIds(), IsEmpty());
123
124 // multiple requests are tolerated
125 EXPECT_CALL(*mockContextHub,
126 onHostEndpointConnected(
127 Field(&HostEndpointInfo::hostEndpointId, kEndpointId)))
128 .WillOnce(Return(ScopedAStatus::ok()))
129 .WillOnce(Return(ScopedAStatus::ok()));
130
131 halClient->connectEndpoint(kInfo);
132 halClient->connectEndpoint(kInfo);
133
134 EXPECT_THAT(halClient->getConnectedEndpointIds(),
135 UnorderedElementsAre(kEndpointId));
136 }
137
TEST(HalClientTest,EndpointDisconnectionBasic)138 TEST(HalClientTest, EndpointDisconnectionBasic) {
139 auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
140 auto halClient = std::make_unique<HalClientForTest>(
141 mockContextHub, std::vector<HostEndpointId>{kEndpointId});
142
143 EXPECT_THAT(halClient->getConnectedEndpointIds(),
144 UnorderedElementsAre(kEndpointId));
145
146 EXPECT_CALL(*mockContextHub, onHostEndpointDisconnected(kEndpointId))
147 .WillOnce(Return(ScopedAStatus::ok()));
148 halClient->disconnectEndpoint(kEndpointId);
149
150 EXPECT_THAT(halClient->getConnectedEndpointIds(), IsEmpty());
151 }
152
TEST(HalClientTest,EndpointDisconnectionMultipleRequest)153 TEST(HalClientTest, EndpointDisconnectionMultipleRequest) {
154 auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
155 auto halClient = std::make_unique<HalClientForTest>(
156 mockContextHub, std::vector<HostEndpointId>{kEndpointId});
157 EXPECT_THAT(halClient->getConnectedEndpointIds(),
158 UnorderedElementsAre(kEndpointId));
159
160 EXPECT_CALL(*mockContextHub, onHostEndpointDisconnected(kEndpointId))
161 .WillOnce(Return(ScopedAStatus::ok()))
162 .WillOnce(Return(ScopedAStatus::ok()));
163
164 halClient->disconnectEndpoint(kEndpointId);
165 halClient->disconnectEndpoint(kEndpointId);
166
167 EXPECT_THAT(halClient->getConnectedEndpointIds(), IsEmpty());
168 }
169
TEST(HalClientTest,SendMessageBasic)170 TEST(HalClientTest, SendMessageBasic) {
171 auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
172 const ContextHubMessage contextHubMessage = {
173 .nanoappId = 0xbeef,
174 .hostEndPoint = kEndpointId,
175 .messageBody = {},
176 .permissions = {},
177 };
178 auto halClient = std::make_unique<HalClientForTest>(
179 mockContextHub, std::vector<HostEndpointId>{kEndpointId});
180
181 EXPECT_CALL(*mockContextHub, sendMessageToHub(_, _))
182 .WillOnce(Return(ScopedAStatus::ok()));
183 halClient->sendMessage(contextHubMessage);
184 }
185
TEST(HalClientTest,QueryNanoapp)186 TEST(HalClientTest, QueryNanoapp) {
187 auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
188 auto halClient = std::make_unique<HalClientForTest>(
189 mockContextHub, std::vector<HostEndpointId>{});
190
191 EXPECT_CALL(*mockContextHub, queryNanoapps(HalClient::kDefaultContextHubId));
192 halClient->queryNanoapps();
193 }
194
TEST(HalClientTest,HandleChreRestart)195 TEST(HalClientTest, HandleChreRestart) {
196 auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
197
198 auto halClient = std::make_unique<HalClientForTest>(
199 mockContextHub,
200 std::vector<HostEndpointId>{kEndpointId, kEndpointId + 1});
201
202 EXPECT_CALL(*mockContextHub, onHostEndpointConnected(
203 Field(&HostEndpointInfo::hostEndpointId, _)))
204 .WillOnce(Return(ScopedAStatus::ok()))
205 .WillOnce(Return(ScopedAStatus::ok()));
206
207 halClient->getClientCallback()->handleContextHubAsyncEvent(
208 AsyncEventType::RESTARTED);
209 EXPECT_THAT(halClient->getConnectedEndpointIds(),
210 UnorderedElementsAre(kEndpointId, kEndpointId + 1));
211 }
212
TEST(HalClientTest,IsConnected)213 TEST(HalClientTest, IsConnected) {
214 auto mockContextHub = ndk::SharedRefBase::make<MockContextHub>();
215
216 auto halClient = std::make_unique<HalClientForTest>(
217 mockContextHub,
218 std::vector<HostEndpointId>{kEndpointId, kEndpointId + 1});
219
220 EXPECT_THAT(halClient->isConnected(), true);
221 }
222 } // namespace android::chre
223