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