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 #include "rpc_test.h"
18
19 #include <cstdint>
20
21 #include "chre/core/event_loop.h"
22 #include "chre/core/event_loop_manager.h"
23 #include "chre/core/settings.h"
24 #include "chre/util/nanoapp/log.h"
25 #include "chre/util/time.h"
26 #include "chre_api/chre/event.h"
27 #include "chre_api/chre/re.h"
28
29 #include "gtest/gtest.h"
30 #include "inc/test_util.h"
31 #include "test_base.h"
32 #include "test_event.h"
33 #include "test_event_queue.h"
34 #include "test_util.h"
35
36 namespace chre {
37
Increment(const chre_rpc_NumberMessage & request,chre_rpc_NumberMessage & response)38 pw::Status RpcTestService::Increment(const chre_rpc_NumberMessage &request,
39 chre_rpc_NumberMessage &response) {
40 EnvSingleton::get()->mServer.setPermissionForNextMessage(
41 CHRE_MESSAGE_PERMISSION_NONE);
42 response.number = request.number + 1;
43 return pw::OkStatus();
44 }
45
46 namespace {
47
48 class RpcTest : public TestBase {};
49
TEST_F(RpcTest,PwRpcCanPublishServicesInNanoappStart)50 TEST_F(RpcTest, PwRpcCanPublishServicesInNanoappStart) {
51 class App : public TestNanoapp {
52 public:
53 bool start() override {
54 struct chreNanoappRpcService servicesA[] = {
55 {.id = 1, .version = 0},
56 {.id = 2, .version = 0},
57 };
58
59 struct chreNanoappRpcService servicesB[] = {
60 {.id = 3, .version = 0},
61 {.id = 4, .version = 0},
62 };
63
64 return chrePublishRpcServices(servicesA, 2 /* numServices */) &&
65 chrePublishRpcServices(servicesB, 2 /* numServices */);
66 }
67 };
68
69 uint64_t appId = loadNanoapp(MakeUnique<App>());
70 Nanoapp *napp = getNanoappByAppId(appId);
71 ASSERT_NE(napp, nullptr);
72
73 EXPECT_EQ(napp->getRpcServices().size(), 4);
74 EXPECT_EQ(napp->getRpcServices()[0].id, 1);
75 EXPECT_EQ(napp->getRpcServices()[1].id, 2);
76 EXPECT_EQ(napp->getRpcServices()[2].id, 3);
77 EXPECT_EQ(napp->getRpcServices()[3].id, 4);
78 }
79
TEST_F(RpcTest,PwRpcCanNotPublishDuplicateServices)80 TEST_F(RpcTest, PwRpcCanNotPublishDuplicateServices) {
81 class App : public TestNanoapp {
82 bool start() override {
83 struct chreNanoappRpcService servicesA[] = {
84 {.id = 1, .version = 0},
85 {.id = 2, .version = 0},
86 };
87
88 bool success = chrePublishRpcServices(servicesA, 2 /* numServices */);
89
90 EXPECT_FALSE(chrePublishRpcServices(servicesA, 2 /* numServices */));
91
92 struct chreNanoappRpcService servicesB[] = {
93 {.id = 5, .version = 0},
94 {.id = 5, .version = 0},
95 };
96
97 EXPECT_FALSE(chrePublishRpcServices(servicesB, 2 /* numServices */));
98
99 return success;
100 }
101 };
102
103 uint64_t appId = loadNanoapp(MakeUnique<App>());
104 Nanoapp *napp = getNanoappByAppId(appId);
105 ASSERT_NE(napp, nullptr);
106
107 EXPECT_EQ(napp->getRpcServices().size(), 2);
108 EXPECT_EQ(napp->getRpcServices()[0].id, 1);
109 EXPECT_EQ(napp->getRpcServices()[1].id, 2);
110 }
111
TEST_F(RpcTest,PwRpcDifferentAppCanPublishSameServices)112 TEST_F(RpcTest, PwRpcDifferentAppCanPublishSameServices) {
113 class App : public TestNanoapp {
114 public:
115 explicit App(uint64_t id) : TestNanoapp(TestNanoappInfo{.id = id}) {}
116
117 bool start() override {
118 struct chreNanoappRpcService services[] = {
119 {.id = 1, .version = 0},
120 {.id = 2, .version = 0},
121 };
122
123 return chrePublishRpcServices(services, 2 /* numServices */);
124 }
125 };
126
127 uint64_t app1Id = loadNanoapp(MakeUnique<App>(0x01));
128 uint64_t app2Id = loadNanoapp(MakeUnique<App>(0x02));
129 Nanoapp *napp1 = getNanoappByAppId(app1Id);
130 ASSERT_NE(napp1, nullptr);
131
132 EXPECT_EQ(napp1->getRpcServices().size(), 2);
133 EXPECT_EQ(napp1->getRpcServices()[0].id, 1);
134 EXPECT_EQ(napp1->getRpcServices()[1].id, 2);
135
136 Nanoapp *napp2 = getNanoappByAppId(app2Id);
137 ASSERT_NE(napp2, nullptr);
138
139 EXPECT_EQ(napp2->getRpcServices().size(), 2);
140 EXPECT_EQ(napp2->getRpcServices()[0].id, 1);
141 EXPECT_EQ(napp2->getRpcServices()[1].id, 2);
142 }
143
TEST_F(RpcTest,PwRpcCanNotPublishServicesOutsideOfNanoappStart)144 TEST_F(RpcTest, PwRpcCanNotPublishServicesOutsideOfNanoappStart) {
145 CREATE_CHRE_TEST_EVENT(PUBLISH_SERVICES, 0);
146
147 class App : public TestNanoapp {
148 public:
149 void handleEvent(uint32_t, uint16_t eventType,
150 const void *eventData) override {
151 switch (eventType) {
152 case CHRE_EVENT_TEST_EVENT: {
153 auto event = static_cast<const TestEvent *>(eventData);
154 switch (event->type) {
155 case PUBLISH_SERVICES: {
156 struct chreNanoappRpcService services[] = {
157 {.id = 1, .version = 0},
158 {.id = 2, .version = 0},
159 };
160
161 bool success =
162 chrePublishRpcServices(services, 2 /* numServices */);
163 TestEventQueueSingleton::get()->pushEvent(PUBLISH_SERVICES,
164 success);
165 break;
166 }
167 }
168 }
169 }
170 }
171 };
172
173 uint64_t appId = loadNanoapp(MakeUnique<App>());
174
175 bool success = true;
176 sendEventToNanoapp(appId, PUBLISH_SERVICES);
177 waitForEvent(PUBLISH_SERVICES, &success);
178 EXPECT_FALSE(success);
179
180 Nanoapp *napp = getNanoappByAppId(appId);
181 ASSERT_NE(napp, nullptr);
182
183 EXPECT_EQ(napp->getRpcServices().size(), 0);
184 }
185
TEST_F(RpcTest,PwRpcRegisterServicesShouldGracefullyFailOnDuplicatedService)186 TEST_F(RpcTest, PwRpcRegisterServicesShouldGracefullyFailOnDuplicatedService) {
187 class App : public TestNanoapp {
188 public:
189 bool start() override {
190 static RpcTestService testService;
191
192 chre::RpcServer::Service service = {.service = testService,
193 .id = 0xca8f7150a3f05847,
194 .version = 0x01020034};
195
196 chre::RpcServer &server = EnvSingleton::get()->mServer;
197
198 bool status = server.registerServices(1, &service);
199
200 EXPECT_TRUE(status);
201
202 EXPECT_FALSE(server.registerServices(1, &service));
203
204 return status;
205 }
206
207 void end() override {
208 EnvSingleton::get()->closeServer();
209 }
210 };
211
212 EnvSingleton::init();
213 uint64_t appId = loadNanoapp(MakeUnique<App>());
214 unloadNanoapp(appId);
215 EnvSingleton::deinit();
216 }
217
TEST_F(RpcTest,PwRpcGetNanoappInfoByAppIdReturnsServices)218 TEST_F(RpcTest, PwRpcGetNanoappInfoByAppIdReturnsServices) {
219 CREATE_CHRE_TEST_EVENT(QUERY_INFO, 0);
220
221 class App : public TestNanoapp {
222 public:
223 bool start() override {
224 struct chreNanoappRpcService services[] = {
225 {.id = 1, .version = 2},
226 {.id = 2, .version = 3},
227 };
228
229 return chrePublishRpcServices(services, 2 /* numServices */);
230 }
231
232 void handleEvent(uint32_t, uint16_t eventType,
233 const void *eventData) override {
234 switch (eventType) {
235 case CHRE_EVENT_TEST_EVENT: {
236 auto event = static_cast<const TestEvent *>(eventData);
237 switch (event->type) {
238 case QUERY_INFO: {
239 auto id = static_cast<uint64_t *>(event->data);
240 bool success = chreGetNanoappInfoByAppId(*id, &mInfo);
241 const struct chreNanoappInfo *pInfo = success ? &mInfo : nullptr;
242 TestEventQueueSingleton::get()->pushEvent(QUERY_INFO, pInfo);
243 break;
244 }
245 }
246 }
247 }
248 }
249
250 protected:
251 struct chreNanoappInfo mInfo;
252 };
253
254 uint64_t appId = loadNanoapp(MakeUnique<App>());
255
256 struct chreNanoappInfo *pInfo = nullptr;
257 sendEventToNanoapp(appId, QUERY_INFO, appId);
258 waitForEvent(QUERY_INFO, &pInfo);
259 EXPECT_TRUE(pInfo != nullptr);
260 EXPECT_EQ(pInfo->rpcServiceCount, 2);
261 EXPECT_EQ(pInfo->rpcServices[0].id, 1);
262 EXPECT_EQ(pInfo->rpcServices[0].version, 2);
263 EXPECT_EQ(pInfo->rpcServices[1].id, 2);
264 EXPECT_EQ(pInfo->rpcServices[1].version, 3);
265 EXPECT_EQ(pInfo->reserved[0], 0);
266 EXPECT_EQ(pInfo->reserved[1], 0);
267 EXPECT_EQ(pInfo->reserved[2], 0);
268 }
269
TEST_F(RpcTest,PwRpcClientNanoappCanRequestServerNanoapp)270 TEST_F(RpcTest, PwRpcClientNanoappCanRequestServerNanoapp) {
271 CREATE_CHRE_TEST_EVENT(INCREMENT_REQUEST, 0);
272
273 class ClientApp : public TestNanoapp {
274 public:
275 ClientApp() : TestNanoapp(TestNanoappInfo{.id = kPwRcpClientAppId}) {}
276
277 void handleEvent(uint32_t senderInstanceId, uint16_t eventType,
278 const void *eventData) override {
279 Env *env = EnvSingleton::get();
280
281 env->mClient.handleEvent(senderInstanceId, eventType, eventData);
282 switch (eventType) {
283 case CHRE_EVENT_TEST_EVENT: {
284 auto event = static_cast<const TestEvent *>(eventData);
285 switch (event->type) {
286 case INCREMENT_REQUEST: {
287 auto client =
288 env->mClient
289 .get<rpc::pw_rpc::nanopb::RpcTestService::Client>();
290 if (client.has_value()) {
291 chre_rpc_NumberMessage incrementRequest;
292 incrementRequest.number = *static_cast<uint32_t *>(event->data);
293 env->mIncrementCall = client->Increment(
294 incrementRequest, [](const chre_rpc_NumberMessage &response,
295 pw::Status status) {
296 if (status.ok()) {
297 EnvSingleton::get()->mNumber = response.number;
298 TestEventQueueSingleton::get()->pushEvent(
299 INCREMENT_REQUEST, true);
300 } else {
301 TestEventQueueSingleton::get()->pushEvent(
302 INCREMENT_REQUEST, false);
303 }
304 });
305 } else {
306 TestEventQueueSingleton::get()->pushEvent(INCREMENT_REQUEST,
307 false);
308 }
309 }
310 }
311 }
312 }
313 }
314
315 void end() {
316 EnvSingleton::get()->closeClient();
317 }
318 };
319
320 class ServerApp : public TestNanoapp {
321 public:
322 ServerApp() : TestNanoapp(TestNanoappInfo{.id = kPwRcpServerAppId}) {}
323
324 bool start() override {
325 chre::RpcServer::Service service = {
326 .service = EnvSingleton::get()->mRpcTestService,
327 .id = 0xca8f7150a3f05847,
328 .version = 0x01020034};
329 return EnvSingleton::get()->mServer.registerServices(1, &service);
330 }
331
332 void handleEvent(uint32_t senderInstanceId, uint16_t eventType,
333 const void *eventData) override {
334 EnvSingleton::get()->mServer.handleEvent(senderInstanceId, eventType,
335 eventData);
336 }
337
338 void end() {
339 EnvSingleton::get()->closeServer();
340 }
341 };
342
343 EnvSingleton::init();
344 uint64_t serverId = loadNanoapp(MakeUnique<ServerApp>());
345 uint64_t clientId = loadNanoapp(MakeUnique<ClientApp>());
346 bool status;
347 constexpr uint32_t kNumber = 101;
348
349 sendEventToNanoapp(clientId, INCREMENT_REQUEST, kNumber);
350 waitForEvent(INCREMENT_REQUEST, &status);
351 EXPECT_TRUE(status);
352 EXPECT_EQ(EnvSingleton::get()->mNumber, kNumber + 1);
353 unloadNanoapp(serverId);
354 unloadNanoapp(clientId);
355 EnvSingleton::deinit();
356 }
357
TEST_F(RpcTest,PwRpcRpcClientHasServiceCheckForAMatchingService)358 TEST_F(RpcTest, PwRpcRpcClientHasServiceCheckForAMatchingService) {
359 CREATE_CHRE_TEST_EVENT(QUERY_HAS_SERVICE, 0);
360
361 struct ServiceInfo {
362 uint64_t id;
363 uint32_t version;
364 uint64_t appId;
365 };
366
367 class App : public TestNanoapp {
368 public:
369 bool start() override {
370 struct chreNanoappRpcService services[] = {{.id = 1, .version = 2}};
371
372 return chrePublishRpcServices(services, 1 /* numServices */);
373 }
374
375 void handleEvent(uint32_t, uint16_t eventType, const void *eventData) {
376 switch (eventType) {
377 case CHRE_EVENT_TEST_EVENT: {
378 auto event = static_cast<const TestEvent *>(eventData);
379 switch (event->type) {
380 case QUERY_HAS_SERVICE: {
381 auto service =
382 static_cast<const struct ServiceInfo *>(event->data);
383 RpcClient client{service->appId};
384 bool hasService =
385 client.hasService(service->id, service->version);
386 TestEventQueueSingleton::get()->pushEvent(QUERY_HAS_SERVICE,
387 hasService);
388 break;
389 }
390 }
391 break;
392 }
393 }
394 }
395 };
396
397 uint64_t appId = loadNanoapp(MakeUnique<App>());
398
399 ServiceInfo service;
400 bool hasService = false;
401
402 service = {.id = 1, .version = 2, .appId = appId};
403 sendEventToNanoapp(appId, QUERY_HAS_SERVICE, service);
404 waitForEvent(QUERY_HAS_SERVICE, &hasService);
405 EXPECT_TRUE(hasService);
406 service = {.id = 10, .version = 2, .appId = appId};
407 sendEventToNanoapp(appId, QUERY_HAS_SERVICE, service);
408 waitForEvent(QUERY_HAS_SERVICE, &hasService);
409 EXPECT_FALSE(hasService);
410 }
411
412 } // namespace
413
414 } // namespace chre
415