1 /*
2 * Copyright (C) 2024 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 "chre/core/event_loop_manager.h"
18 #include "chre/util/dynamic_vector.h"
19 #include "chre/util/system/message_common.h"
20 #include "chre/util/system/message_router.h"
21 #include "chre/util/system/napp_permissions.h"
22 #include "chre_api/chre.h"
23 #include "chre_api/chre/event.h"
24
25 #include "pw_allocator/allocator.h"
26 #include "pw_allocator/libc_allocator.h"
27 #include "pw_allocator/unique_ptr.h"
28 #include "pw_function/function.h"
29 #include "pw_intrusive_ptr/intrusive_ptr.h"
30
31 #include "gtest/gtest.h"
32 #include "inc/test_util.h"
33 #include "test_base.h"
34 #include "test_event.h"
35 #include "test_util.h"
36
37 #include <condition_variable>
38 #include <cstdint>
39 #include <cstring>
40 #include <mutex>
41 #include <optional>
42
43 namespace chre::message {
44 namespace {
45
46 CREATE_CHRE_TEST_EVENT(TEST_GET_EVENT_INFO, 0);
47 CREATE_CHRE_TEST_EVENT(TEST_OPEN_SESSION, 1);
48 CREATE_CHRE_TEST_EVENT(TEST_OPEN_DEFAULT_SESSION, 2);
49 CREATE_CHRE_TEST_EVENT(TEST_OPEN_SESSION_NANOAPP_TO_NANOAPP, 3);
50 CREATE_CHRE_TEST_EVENT(TEST_CLOSE_SESSION, 4);
51 CREATE_CHRE_TEST_EVENT(TEST_CLOSE_SESSION_NON_PARTY, 5);
52 CREATE_CHRE_TEST_EVENT(TEST_GET_SESSION_INFO_INVALID_SESSION, 6);
53 CREATE_CHRE_TEST_EVENT(TEST_SEND_MESSAGE, 7);
54 CREATE_CHRE_TEST_EVENT(TEST_SEND_MESSAGE_NO_FREE_CALLBACK, 8);
55 CREATE_CHRE_TEST_EVENT(TEST_SEND_MESSAGE_NANOAPP_TO_NANOAPP, 9);
56 CREATE_CHRE_TEST_EVENT(TEST_PUBLISH_SERVICE, 10);
57 CREATE_CHRE_TEST_EVENT(TEST_BAD_LEGACY_SERVICE_NAME, 11);
58 CREATE_CHRE_TEST_EVENT(TEST_OPEN_SESSION_WITH_SERVICE, 12);
59 CREATE_CHRE_TEST_EVENT(TEST_SUBSCRIBE_TO_READY_EVENT, 13);
60 CREATE_CHRE_TEST_EVENT(TEST_SUBSCRIBE_TO_READY_EVENT_ALREADY_EXISTS, 14);
61 CREATE_CHRE_TEST_EVENT(TEST_UNSUBSCRIBE_FROM_READY_EVENT, 15);
62 CREATE_CHRE_TEST_EVENT(TEST_SUBSCRIBE_TO_SERVICE_READY_EVENT, 16);
63 CREATE_CHRE_TEST_EVENT(TEST_UNSUBSCRIBE_FROM_SERVICE_READY_EVENT, 17);
64
65 constexpr size_t kNumEndpoints = 3;
66 constexpr size_t kMessageSize = 5;
67 constexpr MessageHubId kOtherMessageHubId = 0xDEADBEEFBEEFDEAD;
68
69 EndpointInfo kEndpointInfos[kNumEndpoints] = {
70 EndpointInfo(/* id= */ 1, /* name= */ "endpoint1", /* version= */ 1,
71 EndpointType::NANOAPP, CHRE_MESSAGE_PERMISSION_NONE),
72 EndpointInfo(/* id= */ 2, /* name= */ "endpoint2", /* version= */ 10,
73 EndpointType::HOST_NATIVE, CHRE_MESSAGE_PERMISSION_BLE),
74 EndpointInfo(/* id= */ 3, /* name= */ "endpoint3", /* version= */ 100,
75 EndpointType::GENERIC, CHRE_MESSAGE_PERMISSION_AUDIO)};
76 EndpointInfo kDynamicEndpointInfo = EndpointInfo(
77 /* id= */ 4, /* name= */ "DynamicallyRegisteredEndpoint",
78 /* version= */ 1, EndpointType::NANOAPP, CHRE_MESSAGE_PERMISSION_NONE);
79
80 const char kServiceDescriptorForEndpoint2[] = "TEST_SERVICE.TEST";
81 const char kServiceDescriptorForDynamicEndpoint[] = "TEST_DYNAMIC_SERVICE";
82 const char kServiceDescriptorForNanoapp[] = "TEST_NANOAPP.TEST_SERVICE";
83 const uint64_t kLegacyServiceId = 0xDEADBEEFDEADBEEF;
84 const uint32_t kLegacyServiceVersion = 1;
85 const uint64_t kLegacyServiceNanoappId = 0xCAFECAFECAFECAFE;
86 const char kLegacyServiceName[] =
87 "chre.nanoapp_0xCAFECAFECAFECAFE.service_0xDEADBEEFDEADBEEF";
88 const char kBadLegacyServiceName[] =
89 "chre.nanoapp_0xCAFECAFECAFECAFE.service_0x0123456789ABCDEF";
90
91 //! Base class for MessageHubCallbacks used in tests
92 class MessageHubCallbackBase : public MessageRouter::MessageHubCallback {
93 public:
forEachEndpoint(const pw::Function<bool (const EndpointInfo &)> & function)94 void forEachEndpoint(
95 const pw::Function<bool(const EndpointInfo &)> &function) override {
96 for (const EndpointInfo &endpointInfo : kEndpointInfos) {
97 if (function(endpointInfo)) {
98 return;
99 }
100 }
101 }
102
getEndpointInfo(EndpointId endpointId)103 std::optional<EndpointInfo> getEndpointInfo(EndpointId endpointId) override {
104 for (const EndpointInfo &endpointInfo : kEndpointInfos) {
105 if (endpointInfo.id == endpointId) {
106 return endpointInfo;
107 }
108 }
109 return std::nullopt;
110 }
111
onSessionOpened(const Session & session)112 void onSessionOpened(const Session &session) override {
113 bool shouldNotify = false;
114 {
115 std::unique_lock<std::mutex> lock(mSessionOpenedMutex);
116 if (mSessionId == SESSION_ID_INVALID) {
117 return;
118 }
119 if (mSessionId == session.sessionId) {
120 shouldNotify = true;
121 mSessionId = SESSION_ID_INVALID;
122 }
123 }
124 if (shouldNotify) {
125 mSessionOpenedCondVar.notify_one();
126 }
127 }
128
getEndpointForService(const char * serviceDescriptor)129 std::optional<EndpointId> getEndpointForService(
130 const char *serviceDescriptor) override {
131 if (serviceDescriptor != nullptr &&
132 std::strcmp(serviceDescriptor, kServiceDescriptorForEndpoint2) == 0) {
133 return kEndpointInfos[1].id;
134 }
135 return std::nullopt;
136 }
137
doesEndpointHaveService(EndpointId endpointId,const char * serviceDescriptor)138 bool doesEndpointHaveService(EndpointId endpointId,
139 const char *serviceDescriptor) override {
140 if (serviceDescriptor == nullptr) {
141 return false;
142 }
143 if (endpointId == kEndpointInfos[1].id) {
144 return std::strcmp(serviceDescriptor, kServiceDescriptorForEndpoint2) ==
145 0;
146 }
147 if (endpointId == kDynamicEndpointInfo.id) {
148 return std::strcmp(serviceDescriptor,
149 kServiceDescriptorForDynamicEndpoint) == 0;
150 }
151 return false;
152 }
153
forEachService(const pw::Function<bool (const EndpointInfo &,const ServiceInfo &)> & function)154 void forEachService(
155 const pw::Function<bool(const EndpointInfo &, const ServiceInfo &)>
156 &function) override {
157 if (function(
158 kEndpointInfos[1],
159 ServiceInfo(kServiceDescriptorForEndpoint2, /* majorVersion= */ 1,
160 /* minorVersion= */ 0, RpcFormat::CUSTOM))) {
161 return;
162 }
163
164 function(kDynamicEndpointInfo,
165 ServiceInfo(kServiceDescriptorForDynamicEndpoint,
166 /* majorVersion= */ 1,
167 /* minorVersion= */ 0, RpcFormat::CUSTOM));
168 }
169
onHubRegistered(const MessageHubInfo &)170 void onHubRegistered(const MessageHubInfo & /*info*/) override {}
171
onHubUnregistered(MessageHubId)172 void onHubUnregistered(MessageHubId /*id*/) override {}
173
onEndpointRegistered(MessageHubId messageHubId,EndpointId endpointId)174 void onEndpointRegistered(MessageHubId messageHubId,
175 EndpointId endpointId) override {
176 mRegisteredEndpoints.insert(std::make_pair(messageHubId, endpointId));
177 }
178
onEndpointUnregistered(MessageHubId messageHubId,EndpointId endpointId)179 void onEndpointUnregistered(MessageHubId messageHubId,
180 EndpointId endpointId) override {
181 mRegisteredEndpoints.erase(std::make_pair(messageHubId, endpointId));
182 }
183
hasEndpointBeenRegistered(MessageHubId messageHubId,EndpointId endpointId)184 bool hasEndpointBeenRegistered(MessageHubId messageHubId,
185 EndpointId endpointId) {
186 return mRegisteredEndpoints.find(std::make_pair(
187 messageHubId, endpointId)) != mRegisteredEndpoints.end();
188 }
189
pw_recycle()190 void pw_recycle() override {
191 delete this;
192 }
193
openSessionAndWaitForOpen(const std::function<SessionId ()> & openSession)194 void openSessionAndWaitForOpen(
195 const std::function<SessionId()> &openSession) {
196 std::unique_lock<std::mutex> lock(mSessionOpenedMutex);
197 mSessionId = openSession();
198 mSessionOpenedCondVar.wait(
199 lock, [this]() { return mSessionId == SESSION_ID_INVALID; });
200 }
201
202 private:
203 std::set<std::pair<MessageHubId, EndpointId>> mRegisteredEndpoints;
204
205 std::mutex mSessionOpenedMutex;
206 std::condition_variable mSessionOpenedCondVar;
207 SessionId mSessionId = SESSION_ID_INVALID;
208 };
209
210 //! MessageHubCallback that stores the data passed to onMessageReceived and
211 //! onSessionClosed
212 class MessageHubCallbackStoreData : public MessageHubCallbackBase {
213 public:
MessageHubCallbackStoreData(Message * message,Session * session)214 MessageHubCallbackStoreData(Message *message, Session *session)
215 : mMessage(message), mSession(session), mMessageHub(nullptr) {}
216
onMessageReceived(pw::UniquePtr<std::byte[]> && data,uint32_t messageType,uint32_t messagePermissions,const Session & session,bool sentBySessionInitiator)217 bool onMessageReceived(pw::UniquePtr<std::byte[]> &&data,
218 uint32_t messageType, uint32_t messagePermissions,
219 const Session &session,
220 bool sentBySessionInitiator) override {
221 if (mMessage != nullptr) {
222 mMessage->sender =
223 sentBySessionInitiator ? session.initiator : session.peer;
224 mMessage->recipient =
225 sentBySessionInitiator ? session.peer : session.initiator;
226 mMessage->sessionId = session.sessionId;
227 mMessage->data = std::move(data);
228 mMessage->messageType = messageType;
229 mMessage->messagePermissions = messagePermissions;
230 }
231 return true;
232 }
233
onSessionClosed(const Session & session,Reason)234 void onSessionClosed(const Session &session, Reason /* reason */) override {
235 if (mSession != nullptr) {
236 *mSession = session;
237 }
238 }
239
onSessionOpenRequest(const Session & session)240 void onSessionOpenRequest(const Session &session) override {
241 if (mMessageHub != nullptr) {
242 mMessageHub->onSessionOpenComplete(session.sessionId);
243 }
244 }
245
setMessageHub(MessageRouter::MessageHub * messageHub)246 void setMessageHub(MessageRouter::MessageHub *messageHub) {
247 mMessageHub = messageHub;
248 }
249
250 private:
251 Message *mMessage;
252 Session *mSession;
253 MessageRouter::MessageHub *mMessageHub;
254 };
255
256 // Creates a message with data from 1 to messageSize
createMessageData(pw::allocator::Allocator & allocator,size_t messageSize)257 pw::UniquePtr<std::byte[]> createMessageData(
258 pw::allocator::Allocator &allocator, size_t messageSize) {
259 pw::UniquePtr<std::byte[]> messageData =
260 allocator.MakeUniqueArray<std::byte>(messageSize);
261 EXPECT_NE(messageData.get(), nullptr);
262 for (size_t i = 0; i < messageSize; ++i) {
263 messageData[i] = static_cast<std::byte>(i + 1);
264 }
265 return messageData;
266 }
267
268 class ChreMessageHubTest : public TestBase {};
269
TEST_F(ChreMessageHubTest,NanoappsAreEndpointsToChreMessageHub)270 TEST_F(ChreMessageHubTest, NanoappsAreEndpointsToChreMessageHub) {
271 class App : public TestNanoapp {
272 public:
273 App() : TestNanoapp(TestNanoappInfo{.name = "TEST1", .id = 0x1234}) {}
274 };
275
276 uint64_t appId = loadNanoapp(MakeUnique<App>());
277
278 std::optional<EndpointInfo> endpointInfoForApp =
279 MessageRouterSingleton::get()->getEndpointInfo(
280 EventLoopManagerSingleton::get()
281 ->getChreMessageHubManager()
282 .kChreMessageHubId,
283 appId);
284 ASSERT_TRUE(endpointInfoForApp.has_value());
285
286 Nanoapp *nanoapp = getNanoappByAppId(appId);
287 ASSERT_NE(nanoapp, nullptr);
288
289 EXPECT_EQ(endpointInfoForApp->id, nanoapp->getAppId());
290 EXPECT_STREQ(endpointInfoForApp->name, nanoapp->getAppName());
291 EXPECT_EQ(endpointInfoForApp->version, nanoapp->getAppVersion());
292 EXPECT_EQ(endpointInfoForApp->type, EndpointType::NANOAPP);
293 EXPECT_EQ(endpointInfoForApp->requiredPermissions,
294 nanoapp->getAppPermissions());
295 }
296
297 //! Nanoapp used to test getting endpoint info
298 class EndpointInfoTestApp : public TestNanoapp {
299 public:
EndpointInfoTestApp(const TestNanoappInfo & info)300 EndpointInfoTestApp(const TestNanoappInfo &info) : TestNanoapp(info) {}
301
handleEvent(uint32_t,uint16_t eventType,const void * eventData)302 void handleEvent(uint32_t, uint16_t eventType,
303 const void *eventData) override {
304 switch (eventType) {
305 case CHRE_EVENT_TEST_EVENT: {
306 auto event = static_cast<const TestEvent *>(eventData);
307 switch (event->type) {
308 case TEST_GET_EVENT_INFO: {
309 for (size_t i = 0; i < kNumEndpoints; ++i) {
310 chreMsgEndpointInfo info = {};
311 EXPECT_TRUE(chreMsgGetEndpointInfo(kOtherMessageHubId,
312 kEndpointInfos[i].id, &info));
313
314 EXPECT_EQ(info.hubId, kOtherMessageHubId);
315 EXPECT_EQ(info.endpointId, kEndpointInfos[i].id);
316 EXPECT_EQ(info.version, kEndpointInfos[i].version);
317 EXPECT_EQ(info.type,
318 EventLoopManagerSingleton::get()
319 ->getChreMessageHubManager()
320 .toChreEndpointType(kEndpointInfos[i].type));
321 EXPECT_EQ(info.requiredPermissions,
322 kEndpointInfos[i].requiredPermissions);
323 EXPECT_STREQ(info.name, kEndpointInfos[i].name);
324 }
325 triggerWait(TEST_GET_EVENT_INFO);
326 break;
327 }
328 }
329 break;
330 }
331 default: {
332 break;
333 }
334 }
335 }
336 };
337
TEST_F(ChreMessageHubTest,NanoappGetsEndpointInfo)338 TEST_F(ChreMessageHubTest, NanoappGetsEndpointInfo) {
339 // Load the nanoapp
340 uint64_t appId = loadNanoapp(MakeUnique<EndpointInfoTestApp>(
341
342 TestNanoappInfo{.name = "TEST_GET_ENDPOINT_INFO", .id = 0x1234}));
343 Nanoapp *nanoapp = getNanoappByAppId(appId);
344 ASSERT_NE(nanoapp, nullptr);
345
346 // Create the other hub
347 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
348 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
349 /* session= */ nullptr);
350 std::optional<MessageRouter::MessageHub> messageHub =
351 MessageRouterSingleton::get()->registerMessageHub(
352 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
353 ASSERT_TRUE(messageHub.has_value());
354 callback->setMessageHub(&(*messageHub));
355
356 // Test getting endpoint info
357 sendEventToNanoappAndWait(appId, TEST_GET_EVENT_INFO, TEST_GET_EVENT_INFO);
358 }
359
TEST_F(ChreMessageHubTest,MultipleNanoappsAreEndpointsToChreMessageHub)360 TEST_F(ChreMessageHubTest, MultipleNanoappsAreEndpointsToChreMessageHub) {
361 class App : public TestNanoapp {
362 public:
363 App() : TestNanoapp(TestNanoappInfo{.name = "TEST1", .id = 0x1234}) {}
364 };
365
366 class App2 : public TestNanoapp {
367 public:
368 App2() : TestNanoapp(TestNanoappInfo{.name = "TEST2", .id = 0x2}) {}
369 };
370
371 uint64_t appId = loadNanoapp(MakeUnique<App>());
372 uint64_t appId2 = loadNanoapp(MakeUnique<App2>());
373 constexpr size_t kNumNanoapps = 2;
374 Nanoapp *nanoapps[kNumNanoapps] = {getNanoappByAppId(appId),
375 getNanoappByAppId(appId2)};
376 ASSERT_NE(nanoapps[0], nullptr);
377 ASSERT_NE(nanoapps[1], nullptr);
378
379 DynamicVector<EndpointInfo> endpointInfos;
380 EXPECT_TRUE(MessageRouterSingleton::get()->forEachEndpointOfHub(
381 EventLoopManagerSingleton::get()
382 ->getChreMessageHubManager()
383 .kChreMessageHubId,
384 [&endpointInfos](const EndpointInfo &endpointInfo) {
385 endpointInfos.push_back(endpointInfo);
386 return false;
387 }));
388 EXPECT_EQ(endpointInfos.size(), 2);
389
390 // Endpoint information should be nanoapp information
391 for (size_t i = 0; i < kNumNanoapps; ++i) {
392 EXPECT_EQ(endpointInfos[i].id, nanoapps[i]->getAppId());
393 EXPECT_STREQ(endpointInfos[i].name, nanoapps[i]->getAppName());
394 EXPECT_EQ(endpointInfos[i].version, nanoapps[i]->getAppVersion());
395 EXPECT_EQ(endpointInfos[i].type, EndpointType::NANOAPP);
396 EXPECT_EQ(endpointInfos[i].requiredPermissions,
397 nanoapps[i]->getAppPermissions());
398 }
399 }
400
401 //! Nanoapp used to test sending messages from a generic endpoint to a nanoapp
402 class MessageTestApp : public TestNanoapp {
403 public:
MessageTestApp(bool & messageReceivedAndValidated,bool & sessionClosed,const TestNanoappInfo & info)404 MessageTestApp(bool &messageReceivedAndValidated, bool &sessionClosed,
405 const TestNanoappInfo &info)
406 : TestNanoapp(info),
407 mMessageReceivedAndValidated(messageReceivedAndValidated),
408 mSessionClosed(sessionClosed) {}
409
handleEvent(uint32_t,uint16_t eventType,const void * eventData)410 void handleEvent(uint32_t, uint16_t eventType,
411 const void *eventData) override {
412 switch (eventType) {
413 case CHRE_EVENT_MSG_FROM_ENDPOINT: {
414 auto *message =
415 static_cast<const struct chreMsgMessageFromEndpointData *>(
416 eventData);
417 EXPECT_EQ(message->messageType, 1);
418 EXPECT_EQ(message->messagePermissions, 0);
419 EXPECT_EQ(message->messageSize, kMessageSize);
420
421 auto *messageData = static_cast<const std::byte *>(message->message);
422 for (size_t i = 0; i < kMessageSize; ++i) {
423 EXPECT_EQ(messageData[i], static_cast<std::byte>(i + 1));
424 }
425 mMessageReceivedAndValidated = true;
426 triggerWait(CHRE_EVENT_MSG_FROM_ENDPOINT);
427 break;
428 }
429 case CHRE_EVENT_MSG_SESSION_CLOSED: {
430 auto *session =
431 static_cast<const struct chreMsgSessionInfo *>(eventData);
432 EXPECT_EQ(session->hubId, kOtherMessageHubId);
433 EXPECT_EQ(session->endpointId, kEndpointInfos[0].id);
434 mSessionClosed = true;
435 triggerWait(CHRE_EVENT_MSG_SESSION_CLOSED);
436 break;
437 }
438 default: {
439 break;
440 }
441 }
442 }
443
444 bool &mMessageReceivedAndValidated;
445 bool &mSessionClosed;
446 };
447
TEST_F(ChreMessageHubTest,SendMessageToNanoapp)448 TEST_F(ChreMessageHubTest, SendMessageToNanoapp) {
449 constexpr uint64_t kNanoappId = 0x1234;
450
451 bool messageReceivedAndValidated = false;
452 bool sessionClosed = false;
453
454 // Create the message
455 pw::allocator::LibCAllocator allocator = pw::allocator::GetLibCAllocator();
456 pw::UniquePtr<std::byte[]> messageData =
457 createMessageData(allocator, kMessageSize);
458
459 // Load the nanoapp
460 uint64_t appId = loadNanoapp(MakeUnique<MessageTestApp>(
461 messageReceivedAndValidated, sessionClosed,
462 TestNanoappInfo{.name = "TEST1", .id = kNanoappId}));
463 TestNanoapp *testNanoapp = queryNanoapp(appId);
464 ASSERT_NE(testNanoapp, nullptr);
465
466 // Create the other hub
467 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
468 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
469 /* session= */ nullptr);
470 std::optional<MessageRouter::MessageHub> messageHub =
471 MessageRouterSingleton::get()->registerMessageHub(
472 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
473 ASSERT_TRUE(messageHub.has_value());
474 callback->setMessageHub(&(*messageHub));
475
476 // Open the session from the other hub:1 to the nanoapp
477 SessionId sessionId = SESSION_ID_INVALID;
478 callback->openSessionAndWaitForOpen([&sessionId, &messageHub]() {
479 sessionId = messageHub->openSession(kEndpointInfos[0].id,
480 EventLoopManagerSingleton::get()
481 ->getChreMessageHubManager()
482 .kChreMessageHubId,
483 kNanoappId);
484 EXPECT_NE(sessionId, SESSION_ID_INVALID);
485 return sessionId;
486 });
487
488 // Send the message to the nanoapp
489 ASSERT_TRUE(messageHub->sendMessage(std::move(messageData),
490 /* messageType= */ 1,
491 /* messagePermissions= */ 0, sessionId));
492 testNanoapp->wait(CHRE_EVENT_MSG_FROM_ENDPOINT);
493 EXPECT_TRUE(messageReceivedAndValidated);
494
495 // Close the session
496 EXPECT_TRUE(messageHub->closeSession(sessionId));
497 testNanoapp->wait(CHRE_EVENT_MSG_SESSION_CLOSED);
498 EXPECT_TRUE(sessionClosed);
499 }
500
501 //! Nanoapp used to test sending messages from a generic endpoint to a nanoapp
502 //! with a different permissions set
503 class MessagePermissionTestApp : public MessageTestApp {
504 public:
MessagePermissionTestApp(bool & messageReceivedAndValidated,bool & sessionClosed,const TestNanoappInfo & info)505 MessagePermissionTestApp(bool &messageReceivedAndValidated,
506 bool &sessionClosed, const TestNanoappInfo &info)
507 : MessageTestApp(messageReceivedAndValidated, sessionClosed, info) {}
508 };
509
TEST_F(ChreMessageHubTest,SendMessageToNanoappPermissionFailure)510 TEST_F(ChreMessageHubTest, SendMessageToNanoappPermissionFailure) {
511 constexpr uint64_t kNanoappId = 0x1234;
512
513 bool messageReceivedAndValidated = false;
514 bool sessionClosed = false;
515
516 pw::allocator::LibCAllocator allocator = pw::allocator::GetLibCAllocator();
517 pw::UniquePtr<std::byte[]> messageData =
518 allocator.MakeUniqueArray<std::byte>(kMessageSize);
519 for (size_t i = 0; i < kMessageSize; ++i) {
520 messageData[i] = static_cast<std::byte>(i + 1);
521 }
522
523 // Load the nanoapp
524 uint64_t appId = loadNanoapp(MakeUnique<MessagePermissionTestApp>(
525 messageReceivedAndValidated, sessionClosed,
526 TestNanoappInfo{
527 .name = "TEST1", .id = kNanoappId, .perms = CHRE_PERMS_BLE}));
528 TestNanoapp *testNanoapp = queryNanoapp(appId);
529 ASSERT_NE(testNanoapp, nullptr);
530
531 // Create the other hub
532 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
533 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
534 /* session= */ nullptr);
535 std::optional<MessageRouter::MessageHub> messageHub =
536 MessageRouterSingleton::get()->registerMessageHub(
537 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
538 ASSERT_TRUE(messageHub.has_value());
539 callback->setMessageHub(&(*messageHub));
540
541 // Open the session from the other hub:1 to the nanoapp
542 SessionId sessionId = SESSION_ID_INVALID;
543 callback->openSessionAndWaitForOpen([&sessionId, &messageHub]() {
544 sessionId = messageHub->openSession(kEndpointInfos[0].id,
545 EventLoopManagerSingleton::get()
546 ->getChreMessageHubManager()
547 .kChreMessageHubId,
548 kNanoappId);
549 EXPECT_NE(sessionId, SESSION_ID_INVALID);
550 return sessionId;
551 });
552
553 // Send the message to the nanoapp
554 ASSERT_TRUE(messageHub->sendMessage(
555 std::move(messageData),
556 /* messageType= */ 1,
557 /* messagePermissions= */ CHRE_PERMS_AUDIO | CHRE_PERMS_GNSS, sessionId));
558
559 // Wait for the session to close due to the permission failure
560 testNanoapp->wait(CHRE_EVENT_MSG_SESSION_CLOSED);
561 EXPECT_FALSE(messageReceivedAndValidated);
562 EXPECT_TRUE(sessionClosed);
563 }
564
565 //! Nanoapp used to test opening sessions and sending messages from a nanoapp
566 //! to a generic endpoint
567 class SessionAndMessageTestApp : public TestNanoapp {
568 public:
SessionAndMessageTestApp(SessionId & sessionId,const TestNanoappInfo & info)569 SessionAndMessageTestApp(SessionId &sessionId, const TestNanoappInfo &info)
570 : TestNanoapp(info), mSessionId(sessionId) {}
571
handleEvent(uint32_t,uint16_t eventType,const void * eventData)572 void handleEvent(uint32_t, uint16_t eventType,
573 const void *eventData) override {
574 switch (eventType) {
575 case CHRE_EVENT_MSG_SESSION_OPENED: {
576 // Verify the session info from the event is correct
577 auto sessionInfo = static_cast<const chreMsgSessionInfo *>(eventData);
578 EXPECT_EQ(sessionInfo->hubId, mToMessageHubId);
579 EXPECT_EQ(sessionInfo->endpointId, mToEndpointId);
580 EXPECT_STREQ(sessionInfo->serviceDescriptor, "");
581 EXPECT_NE(sessionInfo->sessionId, UINT16_MAX);
582 EXPECT_EQ(sessionInfo->reason,
583 chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_UNSPECIFIED);
584 mSessionId = sessionInfo->sessionId;
585
586 // Get the session info and verify it is correct
587 struct chreMsgSessionInfo sessionInfo2;
588 EXPECT_TRUE(chreMsgSessionGetInfo(mSessionId, &sessionInfo2));
589 EXPECT_EQ(sessionInfo2.hubId, mToMessageHubId);
590 EXPECT_EQ(sessionInfo2.endpointId, mToEndpointId);
591 EXPECT_STREQ(sessionInfo2.serviceDescriptor, "");
592 EXPECT_EQ(sessionInfo2.sessionId, mSessionId);
593 EXPECT_EQ(sessionInfo2.reason,
594 chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_UNSPECIFIED);
595 triggerWait(CHRE_EVENT_MSG_SESSION_OPENED);
596 break;
597 }
598 case CHRE_EVENT_MSG_SESSION_CLOSED: {
599 // Verify the session info from the event is correct
600 auto sessionInfo = static_cast<const chreMsgSessionInfo *>(eventData);
601 EXPECT_EQ(sessionInfo->hubId, mToMessageHubId);
602 EXPECT_EQ(sessionInfo->endpointId, mToEndpointId);
603 EXPECT_STREQ(sessionInfo->serviceDescriptor, "");
604 EXPECT_EQ(sessionInfo->sessionId, mSessionId);
605 triggerWait(CHRE_EVENT_MSG_SESSION_CLOSED);
606 break;
607 }
608 case CHRE_EVENT_MSG_FROM_ENDPOINT: {
609 auto messageData =
610 static_cast<const chreMsgMessageFromEndpointData *>(eventData);
611 EXPECT_EQ(messageData->messageType, 1);
612 EXPECT_EQ(messageData->messagePermissions,
613 CHRE_MESSAGE_PERMISSION_NONE);
614 EXPECT_EQ(messageData->messageSize, kMessageSize);
615
616 auto message = reinterpret_cast<const uint8_t *>(messageData->message);
617 for (size_t i = 0; i < kMessageSize; ++i) {
618 EXPECT_EQ(message[i], i + 1);
619 }
620 EXPECT_EQ(messageData->sessionId, mSessionId);
621 triggerWait(CHRE_EVENT_MSG_FROM_ENDPOINT);
622 break;
623 }
624 case CHRE_EVENT_TEST_EVENT: {
625 auto event = static_cast<const TestEvent *>(eventData);
626 switch (event->type) {
627 case TEST_OPEN_SESSION: {
628 // Open the session from the nanoapp to the other hub:0
629 mToMessageHubId = kOtherMessageHubId;
630 mToEndpointId = kEndpointInfos[0].id;
631 EXPECT_TRUE(
632 chreMsgSessionOpenAsync(mToMessageHubId, mToEndpointId,
633 /* serviceDescriptor= */ nullptr));
634 mSessionId = UINT16_MAX;
635 break;
636 }
637 case TEST_OPEN_DEFAULT_SESSION: {
638 // Open the default session from the nanoapp to the other hub:1
639 mToMessageHubId = kOtherMessageHubId;
640 mToEndpointId = kEndpointInfos[1].id;
641 EXPECT_TRUE(
642 chreMsgSessionOpenAsync(CHRE_MSG_HUB_ID_ANY, mToEndpointId,
643 /* serviceDescriptor= */ nullptr));
644 mSessionId = UINT16_MAX;
645 break;
646 }
647 case TEST_OPEN_SESSION_NANOAPP_TO_NANOAPP: {
648 // Open a session from the nanoapp to itself
649 mToMessageHubId = CHRE_PLATFORM_ID;
650 mToEndpointId = id();
651 EXPECT_TRUE(
652 chreMsgSessionOpenAsync(mToMessageHubId, mToEndpointId,
653 /* serviceDescriptor= */ nullptr));
654 mSessionId = UINT16_MAX;
655 break;
656 }
657 case TEST_CLOSE_SESSION: {
658 // Close the session
659 EXPECT_TRUE(chreMsgSessionCloseAsync(mSessionId));
660 break;
661 }
662 case TEST_CLOSE_SESSION_NON_PARTY: {
663 ASSERT_NE(event->data, nullptr);
664 SessionId sessionId = *static_cast<SessionId *>(event->data);
665
666 // Close the session that was opened by the other nanoapp
667 EXPECT_FALSE(chreMsgSessionCloseAsync(sessionId));
668 triggerWait(TEST_CLOSE_SESSION_NON_PARTY);
669 break;
670 }
671 case TEST_GET_SESSION_INFO_INVALID_SESSION: {
672 struct chreMsgSessionInfo sessionInfo;
673 EXPECT_NE(mSessionId, SESSION_ID_INVALID);
674 EXPECT_FALSE(chreMsgSessionGetInfo(mSessionId, &sessionInfo));
675 triggerWait(TEST_GET_SESSION_INFO_INVALID_SESSION);
676 break;
677 }
678 case TEST_SEND_MESSAGE: {
679 EXPECT_TRUE(chreMsgSend(
680 reinterpret_cast<void *>(kMessage), kMessageSize,
681 /* messageType= */ 1, mSessionId, CHRE_MESSAGE_PERMISSION_NONE,
682 [](void *message, size_t length) {
683 EXPECT_EQ(message, kMessage);
684 EXPECT_EQ(length, kMessageSize);
685 }));
686 triggerWait(TEST_SEND_MESSAGE);
687 break;
688 }
689 case TEST_SEND_MESSAGE_NO_FREE_CALLBACK: {
690 EXPECT_TRUE(chreMsgSend(
691 reinterpret_cast<void *>(kMessage), kMessageSize,
692 /* messageType= */ 1, mSessionId, CHRE_MESSAGE_PERMISSION_NONE,
693 /* freeCallback= */ [](void * /*message*/, size_t /*length*/) {
694 }));
695 triggerWait(TEST_SEND_MESSAGE_NO_FREE_CALLBACK);
696 break;
697 }
698 case TEST_SEND_MESSAGE_NANOAPP_TO_NANOAPP: {
699 EXPECT_TRUE(chreMsgSend(
700 reinterpret_cast<void *>(kMessage), kMessageSize,
701 /* messageType= */ 1, mSessionId, CHRE_MESSAGE_PERMISSION_NONE,
702 /* freeCallback= */ [](void * /*message*/, size_t /*length*/) {
703 }));
704 break;
705 }
706 }
707 break;
708 }
709 default: {
710 break;
711 }
712 }
713 }
714
715 static uint8_t kMessage[kMessageSize];
716
717 SessionId &mSessionId;
718 MessageHubId mToMessageHubId = MESSAGE_HUB_ID_INVALID;
719 EndpointId mToEndpointId = ENDPOINT_ID_INVALID;
720 };
721 uint8_t SessionAndMessageTestApp::kMessage[kMessageSize] = {1, 2, 3, 4, 5};
722
TEST_F(ChreMessageHubTest,NanoappOpensSessionWithGenericEndpoint)723 TEST_F(ChreMessageHubTest, NanoappOpensSessionWithGenericEndpoint) {
724 SessionId sessionId = SESSION_ID_INVALID;
725
726 // Load the nanoapp
727 uint64_t appId = loadNanoapp(MakeUnique<SessionAndMessageTestApp>(
728 sessionId, TestNanoappInfo{.name = "TEST_OPEN_SESSION", .id = 0x1234}));
729 Nanoapp *nanoapp = getNanoappByAppId(appId);
730 ASSERT_NE(nanoapp, nullptr);
731 TestNanoapp *testNanoapp = queryNanoapp(appId);
732 ASSERT_NE(testNanoapp, nullptr);
733
734 // Create the other hub
735 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
736 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
737 /* session= */ nullptr);
738 std::optional<MessageRouter::MessageHub> messageHub =
739 MessageRouterSingleton::get()->registerMessageHub(
740 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
741 ASSERT_TRUE(messageHub.has_value());
742 callback->setMessageHub(&(*messageHub));
743
744 // Test opening session
745 sendEventToNanoappAndWait(appId, TEST_OPEN_SESSION,
746 CHRE_EVENT_MSG_SESSION_OPENED);
747
748 // Verify the other hub received the correct session information
749 std::optional<Session> session = messageHub->getSessionWithId(sessionId);
750 ASSERT_TRUE(session.has_value());
751 EXPECT_EQ(session->sessionId, sessionId);
752 EXPECT_EQ(session->initiator.messageHubId, EventLoopManagerSingleton::get()
753 ->getChreMessageHubManager()
754 .kChreMessageHubId);
755 EXPECT_EQ(session->initiator.endpointId, nanoapp->getAppId());
756 EXPECT_EQ(session->peer.messageHubId, kOtherMessageHubId);
757 EXPECT_EQ(session->peer.endpointId, kEndpointInfos[0].id);
758
759 testNanoapp->doActionAndWait(
760 [&messageHub, &session]() {
761 messageHub->closeSession(session->sessionId);
762 return true;
763 },
764 CHRE_EVENT_MSG_SESSION_CLOSED);
765 }
766
TEST_F(ChreMessageHubTest,NanoappTriesToCloseNonPartySession)767 TEST_F(ChreMessageHubTest, NanoappTriesToCloseNonPartySession) {
768 SessionId sessionId = SESSION_ID_INVALID;
769
770 // Load the nanoapp
771 uint64_t appId = loadNanoapp(MakeUnique<SessionAndMessageTestApp>(
772 sessionId, TestNanoappInfo{.name = "TEST_OPEN_SESSION", .id = 0x1234}));
773 Nanoapp *nanoapp = getNanoappByAppId(appId);
774 ASSERT_NE(nanoapp, nullptr);
775 TestNanoapp *testNanoapp = queryNanoapp(appId);
776 ASSERT_NE(testNanoapp, nullptr);
777
778 // Load the nanoapp
779 uint64_t appId2 = loadNanoapp(MakeUnique<SessionAndMessageTestApp>(
780 sessionId,
781 TestNanoappInfo{.name = "TEST_OPEN_SESSION_NON_PARTY", .id = 0x1235}));
782 Nanoapp *nanoapp2 = getNanoappByAppId(appId);
783 ASSERT_NE(nanoapp2, nullptr);
784
785 // Create the other hub
786 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
787 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
788 /* session= */ nullptr);
789 std::optional<MessageRouter::MessageHub> messageHub =
790 MessageRouterSingleton::get()->registerMessageHub(
791 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
792 ASSERT_TRUE(messageHub.has_value());
793 callback->setMessageHub(&(*messageHub));
794
795 // Test opening session
796 sendEventToNanoappAndWait(appId, TEST_OPEN_SESSION,
797 CHRE_EVENT_MSG_SESSION_OPENED);
798
799 // Now close the session and expect failure
800 sendEventToNanoappAndWait(appId, TEST_CLOSE_SESSION_NON_PARTY, &sessionId,
801 TEST_CLOSE_SESSION_NON_PARTY);
802
803 testNanoapp->doActionAndWait(
804 [&messageHub, &sessionId]() {
805 messageHub->closeSession(sessionId);
806 return true;
807 },
808 CHRE_EVENT_MSG_SESSION_CLOSED);
809 }
810
TEST_F(ChreMessageHubTest,NanoappOpensDefaultSessionWithGenericEndpoint)811 TEST_F(ChreMessageHubTest, NanoappOpensDefaultSessionWithGenericEndpoint) {
812 SessionId sessionId = SESSION_ID_INVALID;
813
814 // Load the nanoapp
815 uint64_t appId = loadNanoapp(MakeUnique<SessionAndMessageTestApp>(
816 sessionId,
817 TestNanoappInfo{.name = "TEST_OPEN_DEFAULT_SESSION", .id = 0x1234}));
818 Nanoapp *nanoapp = getNanoappByAppId(appId);
819 ASSERT_NE(nanoapp, nullptr);
820 TestNanoapp *testNanoapp = queryNanoapp(appId);
821 ASSERT_NE(testNanoapp, nullptr);
822
823 // Create the other hub
824 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
825 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
826 /* session= */ nullptr);
827 std::optional<MessageRouter::MessageHub> messageHub =
828 MessageRouterSingleton::get()->registerMessageHub(
829 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
830 ASSERT_TRUE(messageHub.has_value());
831 callback->setMessageHub(&(*messageHub));
832
833 // Test opening the default session
834 sendEventToNanoappAndWait(appId, TEST_OPEN_DEFAULT_SESSION,
835 CHRE_EVENT_MSG_SESSION_OPENED);
836
837 // Verify the other hub received the correct session information
838 std::optional<Session> session = messageHub->getSessionWithId(sessionId);
839 ASSERT_TRUE(session.has_value());
840
841 EXPECT_EQ(session->sessionId, sessionId);
842 EXPECT_EQ(session->initiator.messageHubId, EventLoopManagerSingleton::get()
843 ->getChreMessageHubManager()
844 .kChreMessageHubId);
845 EXPECT_EQ(session->initiator.endpointId, nanoapp->getAppId());
846 EXPECT_EQ(session->peer.messageHubId, kOtherMessageHubId);
847 EXPECT_EQ(session->peer.endpointId, kEndpointInfos[1].id);
848
849 testNanoapp->doActionAndWait(
850 [&messageHub, &sessionId]() {
851 messageHub->closeSession(sessionId);
852 return true;
853 },
854 CHRE_EVENT_MSG_SESSION_CLOSED);
855 }
856
TEST_F(ChreMessageHubTest,NanoappClosesSessionWithGenericEndpoint)857 TEST_F(ChreMessageHubTest, NanoappClosesSessionWithGenericEndpoint) {
858 Session session;
859 SessionId sessionId = SESSION_ID_INVALID;
860
861 // Load the nanoapp
862 uint64_t appId = loadNanoapp(MakeUnique<SessionAndMessageTestApp>(
863 sessionId, TestNanoappInfo{.name = "TEST_OPEN_SESSION", .id = 0x1234}));
864 Nanoapp *nanoapp = getNanoappByAppId(appId);
865 ASSERT_NE(nanoapp, nullptr);
866
867 // Create the other hub
868 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
869 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
870 &session);
871 std::optional<MessageRouter::MessageHub> messageHub =
872 MessageRouterSingleton::get()->registerMessageHub(
873 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
874 ASSERT_TRUE(messageHub.has_value());
875 callback->setMessageHub(&(*messageHub));
876
877 // Test opening session
878 sendEventToNanoappAndWait(appId, TEST_OPEN_SESSION,
879 CHRE_EVENT_MSG_SESSION_OPENED);
880
881 // Now close the session
882 sendEventToNanoappAndWait(appId, TEST_CLOSE_SESSION,
883 CHRE_EVENT_MSG_SESSION_CLOSED);
884
885 // Verify the other hub received the correct session information
886 EXPECT_EQ(session.sessionId, sessionId);
887 EXPECT_EQ(session.initiator.messageHubId, EventLoopManagerSingleton::get()
888 ->getChreMessageHubManager()
889 .kChreMessageHubId);
890 EXPECT_EQ(session.initiator.endpointId, nanoapp->getAppId());
891 EXPECT_EQ(session.peer.messageHubId, kOtherMessageHubId);
892 EXPECT_EQ(session.peer.endpointId, kEndpointInfos[0].id);
893 }
894
TEST_F(ChreMessageHubTest,OtherHubClosesNanoappSessionWithGenericEndpoint)895 TEST_F(ChreMessageHubTest, OtherHubClosesNanoappSessionWithGenericEndpoint) {
896 Session session;
897 SessionId sessionId = SESSION_ID_INVALID;
898
899 // Load the nanoapp
900 uint64_t appId = loadNanoapp(MakeUnique<SessionAndMessageTestApp>(
901 sessionId, TestNanoappInfo{.name = "TEST_OPEN_SESSION", .id = 0x1234}));
902 Nanoapp *nanoapp = getNanoappByAppId(appId);
903 ASSERT_NE(nanoapp, nullptr);
904 TestNanoapp *testNanoapp = queryNanoapp(appId);
905 ASSERT_NE(testNanoapp, nullptr);
906
907 // Create the other hub
908 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
909 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
910 &session);
911 std::optional<MessageRouter::MessageHub> messageHub =
912 MessageRouterSingleton::get()->registerMessageHub(
913 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
914 ASSERT_TRUE(messageHub.has_value());
915 callback->setMessageHub(&(*messageHub));
916
917 // Test opening session
918 sendEventToNanoappAndWait(appId, TEST_OPEN_SESSION,
919 CHRE_EVENT_MSG_SESSION_OPENED);
920
921 // Now close the session and wait for the event to be processed
922 EXPECT_TRUE(messageHub->closeSession(sessionId));
923 testNanoapp->wait(CHRE_EVENT_MSG_SESSION_CLOSED);
924
925 // Verify the other hub received the correct session information
926 EXPECT_EQ(session.sessionId, sessionId);
927 EXPECT_EQ(session.initiator.messageHubId, EventLoopManagerSingleton::get()
928 ->getChreMessageHubManager()
929 .kChreMessageHubId);
930 EXPECT_EQ(session.initiator.endpointId, nanoapp->getAppId());
931 EXPECT_EQ(session.peer.messageHubId, kOtherMessageHubId);
932 EXPECT_EQ(session.peer.endpointId, kEndpointInfos[0].id);
933 }
934
TEST_F(ChreMessageHubTest,NanoappGetSessionInfoForNonPartySession)935 TEST_F(ChreMessageHubTest, NanoappGetSessionInfoForNonPartySession) {
936 Session session;
937 SessionId sessionId = SESSION_ID_INVALID;
938
939 // Load the nanoapp
940 uint64_t appId = loadNanoapp(MakeUnique<SessionAndMessageTestApp>(
941 sessionId, TestNanoappInfo{.name = "TEST_OPEN_SESSION", .id = 0x1234}));
942 Nanoapp *nanoapp = getNanoappByAppId(appId);
943 ASSERT_NE(nanoapp, nullptr);
944
945 // Create the other hubs
946 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
947 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
948 &session);
949 std::optional<MessageRouter::MessageHub> messageHub =
950 MessageRouterSingleton::get()->registerMessageHub(
951 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
952 ASSERT_TRUE(messageHub.has_value());
953 callback->setMessageHub(&(*messageHub));
954
955 pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
956 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
957 &session);
958 std::optional<MessageRouter::MessageHub> messageHub2 =
959 MessageRouterSingleton::get()->registerMessageHub(
960 "OTHER_TEST_HUB2", kOtherMessageHubId + 1, callback2);
961 ASSERT_TRUE(messageHub2.has_value());
962 callback2->setMessageHub(&(*messageHub2));
963
964 // Open a session not involving the nanoapps
965 sessionId = messageHub->openSession(
966 kEndpointInfos[0].id, kOtherMessageHubId + 1, kEndpointInfos[1].id);
967 EXPECT_NE(sessionId, SESSION_ID_INVALID);
968
969 // Tell the nanoapp to get the session info for our session
970 sendEventToNanoappAndWait(appId, TEST_GET_SESSION_INFO_INVALID_SESSION,
971 TEST_GET_SESSION_INFO_INVALID_SESSION);
972 }
973
TEST_F(ChreMessageHubTest,NanoappSendsMessageToGenericEndpoint)974 TEST_F(ChreMessageHubTest, NanoappSendsMessageToGenericEndpoint) {
975 SessionId sessionId = SESSION_ID_INVALID;
976 Message message;
977
978 // Load the nanoapp
979 uint64_t appId = loadNanoapp(MakeUnique<SessionAndMessageTestApp>(
980 sessionId, TestNanoappInfo{.name = "TEST_OPEN_SESSION", .id = 0x1234}));
981 Nanoapp *nanoapp = getNanoappByAppId(appId);
982 ASSERT_NE(nanoapp, nullptr);
983 TestNanoapp *testNanoapp = queryNanoapp(appId);
984 ASSERT_NE(testNanoapp, nullptr);
985
986 // Create the other hub
987 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
988 pw::MakeRefCounted<MessageHubCallbackStoreData>(&message,
989 /* session= */ nullptr);
990 std::optional<MessageRouter::MessageHub> messageHub =
991 MessageRouterSingleton::get()->registerMessageHub(
992 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
993 ASSERT_TRUE(messageHub.has_value());
994 callback->setMessageHub(&(*messageHub));
995
996 // Test opening session
997 sendEventToNanoappAndWait(appId, TEST_OPEN_SESSION,
998 CHRE_EVENT_MSG_SESSION_OPENED);
999
1000 // Send the message to the other hub and verify it was received
1001 sendEventToNanoappAndWait(appId, TEST_SEND_MESSAGE,
1002 TEST_SEND_MESSAGE);
1003
1004 EXPECT_EQ(message.data.size(), kMessageSize);
1005 for (size_t i = 0; i < kMessageSize; ++i) {
1006 EXPECT_EQ(message.data[i],
1007 static_cast<std::byte>(SessionAndMessageTestApp::kMessage[i]));
1008 }
1009 EXPECT_EQ(message.messageType, 1);
1010 EXPECT_EQ(message.messagePermissions, CHRE_MESSAGE_PERMISSION_NONE);
1011
1012 testNanoapp->doActionAndWait(
1013 [&messageHub, &sessionId]() {
1014 messageHub->closeSession(sessionId);
1015 return true;
1016 },
1017 CHRE_EVENT_MSG_SESSION_CLOSED);
1018 }
1019
TEST_F(ChreMessageHubTest,NanoappSendsMessageWithNoFreeCallbackToGenericEndpoint)1020 TEST_F(ChreMessageHubTest,
1021 NanoappSendsMessageWithNoFreeCallbackToGenericEndpoint) {
1022 SessionId sessionId = SESSION_ID_INVALID;
1023 Message message;
1024
1025 // Load the nanoapp
1026 uint64_t appId = loadNanoapp(MakeUnique<SessionAndMessageTestApp>(
1027 sessionId, TestNanoappInfo{.name = "TEST_OPEN_SESSION", .id = 0x1234}));
1028 Nanoapp *nanoapp = getNanoappByAppId(appId);
1029 ASSERT_NE(nanoapp, nullptr);
1030 TestNanoapp *testNanoapp = queryNanoapp(appId);
1031 ASSERT_NE(testNanoapp, nullptr);
1032
1033 // Create the other hub
1034 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1035 pw::MakeRefCounted<MessageHubCallbackStoreData>(&message,
1036 /* session= */ nullptr);
1037 std::optional<MessageRouter::MessageHub> messageHub =
1038 MessageRouterSingleton::get()->registerMessageHub(
1039 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1040 ASSERT_TRUE(messageHub.has_value());
1041 callback->setMessageHub(&(*messageHub));
1042
1043 // Test opening session
1044 sendEventToNanoappAndWait(appId, TEST_OPEN_SESSION,
1045 CHRE_EVENT_MSG_SESSION_OPENED);
1046
1047 // Send the message to the other hub and verify it was received
1048 sendEventToNanoappAndWait(appId, TEST_SEND_MESSAGE_NO_FREE_CALLBACK,
1049 TEST_SEND_MESSAGE_NO_FREE_CALLBACK);
1050
1051 EXPECT_EQ(message.data.size(), kMessageSize);
1052 for (size_t i = 0; i < kMessageSize; ++i) {
1053 EXPECT_EQ(message.data[i],
1054 static_cast<std::byte>(SessionAndMessageTestApp::kMessage[i]));
1055 }
1056 EXPECT_EQ(message.messageType, 1);
1057 EXPECT_EQ(message.messagePermissions, CHRE_MESSAGE_PERMISSION_NONE);
1058
1059 testNanoapp->doActionAndWait(
1060 [&messageHub, &sessionId]() {
1061 messageHub->closeSession(sessionId);
1062 return true;
1063 },
1064 CHRE_EVENT_MSG_SESSION_CLOSED);
1065 }
1066
TEST_F(ChreMessageHubTest,NanoappGetsMessageFromGenericEndpoint)1067 TEST_F(ChreMessageHubTest, NanoappGetsMessageFromGenericEndpoint) {
1068 SessionId sessionId = SESSION_ID_INVALID;
1069 Message message;
1070
1071 // Load the nanoapp
1072 uint64_t appId = loadNanoapp(MakeUnique<SessionAndMessageTestApp>(
1073 sessionId, TestNanoappInfo{.name = "TEST_OPEN_SESSION", .id = 0x1234}));
1074 Nanoapp *nanoapp = getNanoappByAppId(appId);
1075 ASSERT_NE(nanoapp, nullptr);
1076 TestNanoapp *testNanoapp = queryNanoapp(appId);
1077 ASSERT_NE(testNanoapp, nullptr);
1078
1079 // Create the other hub
1080 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1081 pw::MakeRefCounted<MessageHubCallbackStoreData>(&message,
1082 /* session= */ nullptr);
1083 std::optional<MessageRouter::MessageHub> messageHub =
1084 MessageRouterSingleton::get()->registerMessageHub(
1085 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1086 ASSERT_TRUE(messageHub.has_value());
1087 callback->setMessageHub(&(*messageHub));
1088
1089 // Test opening session
1090 sendEventToNanoappAndWait(appId, TEST_OPEN_SESSION,
1091 CHRE_EVENT_MSG_SESSION_OPENED);
1092
1093 // Send the message to the nanoapp and verify it was received
1094 pw::allocator::LibCAllocator allocator = pw::allocator::GetLibCAllocator();
1095 pw::UniquePtr<std::byte[]> messageData =
1096 createMessageData(allocator, kMessageSize);
1097 EXPECT_TRUE(messageHub->sendMessage(std::move(messageData),
1098 /* messageType= */ 1,
1099 CHRE_MESSAGE_PERMISSION_NONE, sessionId));
1100
1101 testNanoapp->wait(CHRE_EVENT_MSG_FROM_ENDPOINT);
1102
1103 testNanoapp->doActionAndWait(
1104 [&messageHub, &sessionId]() {
1105 messageHub->closeSession(sessionId);
1106 return true;
1107 },
1108 CHRE_EVENT_MSG_SESSION_CLOSED);
1109 }
1110
TEST_F(ChreMessageHubTest,NanoappSendsMessageToNanoapp)1111 TEST_F(ChreMessageHubTest, NanoappSendsMessageToNanoapp) {
1112 Session session;
1113 SessionId sessionId = SESSION_ID_INVALID;
1114
1115 // Load the nanoapp
1116 uint64_t appId = loadNanoapp(MakeUnique<SessionAndMessageTestApp>(
1117 sessionId, TestNanoappInfo{.name = "TEST_SEND_MESSAGE_NANOAPP_TO_NANOAPP",
1118 .id = 0x1234}));
1119 Nanoapp *nanoapp = getNanoappByAppId(appId);
1120 ASSERT_NE(nanoapp, nullptr);
1121
1122 // Test opening the session to itself
1123 sendEventToNanoappAndWait(appId, TEST_OPEN_SESSION_NANOAPP_TO_NANOAPP,
1124 CHRE_EVENT_MSG_SESSION_OPENED);
1125
1126 // Send the message to itself
1127 sendEventToNanoappAndWait(appId, TEST_SEND_MESSAGE_NANOAPP_TO_NANOAPP,
1128 CHRE_EVENT_MSG_FROM_ENDPOINT);
1129
1130 // Wait for the session to be closed
1131 sendEventToNanoappAndWait(appId, TEST_CLOSE_SESSION,
1132 CHRE_EVENT_MSG_SESSION_CLOSED);
1133 }
1134
1135 //! Nanoapp used to test opening sessions with services
1136 class ServiceSessionTestApp : public TestNanoapp {
1137 public:
ServiceSessionTestApp(const TestNanoappInfo & info)1138 ServiceSessionTestApp(const TestNanoappInfo &info) : TestNanoapp(info) {}
1139
start()1140 bool start() override {
1141 chreNanoappRpcService serviceInfo;
1142 serviceInfo.id = kLegacyServiceId;
1143 serviceInfo.version = kLegacyServiceVersion;
1144 EXPECT_TRUE(chrePublishRpcServices(&serviceInfo,
1145 /* numServices= */ 1));
1146 return true;
1147 }
1148
handleEvent(uint32_t,uint16_t eventType,const void * eventData)1149 void handleEvent(uint32_t, uint16_t eventType,
1150 const void *eventData) override {
1151 switch (eventType) {
1152 case CHRE_EVENT_MSG_SESSION_OPENED: {
1153 // Verify the session info from the event is correct
1154 auto sessionInfo = static_cast<const chreMsgSessionInfo *>(eventData);
1155 EXPECT_EQ(sessionInfo->hubId, kOtherMessageHubId);
1156 EXPECT_EQ(sessionInfo->reason,
1157 chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_UNSPECIFIED);
1158
1159 if (std::strcmp(sessionInfo->serviceDescriptor,
1160 kServiceDescriptorForEndpoint2) == 0) {
1161 EXPECT_EQ(sessionInfo->endpointId, kEndpointInfos[1].id);
1162 EXPECT_NE(sessionInfo->sessionId, UINT16_MAX);
1163 }
1164 triggerWait(CHRE_EVENT_MSG_SESSION_OPENED);
1165 break;
1166 }
1167 case CHRE_EVENT_MSG_SESSION_CLOSED: {
1168 triggerWait(CHRE_EVENT_MSG_SESSION_CLOSED);
1169 break;
1170 }
1171 case CHRE_EVENT_TEST_EVENT: {
1172 auto event = static_cast<const TestEvent *>(eventData);
1173 switch (event->type) {
1174 case TEST_PUBLISH_SERVICE: {
1175 chreMsgServiceInfo serviceInfo;
1176 serviceInfo.majorVersion = 1;
1177 serviceInfo.minorVersion = 0;
1178 serviceInfo.serviceDescriptor = kServiceDescriptorForNanoapp;
1179 serviceInfo.serviceFormat = CHRE_MSG_ENDPOINT_SERVICE_FORMAT_CUSTOM;
1180 EXPECT_TRUE(
1181 chreMsgPublishServices(&serviceInfo, /* numServices= */ 1));
1182 triggerWait(TEST_PUBLISH_SERVICE);
1183 break;
1184 }
1185 case TEST_BAD_LEGACY_SERVICE_NAME: {
1186 chreMsgServiceInfo serviceInfo;
1187 serviceInfo.majorVersion = 1;
1188 serviceInfo.minorVersion = 0;
1189 serviceInfo.serviceDescriptor = kBadLegacyServiceName;
1190 serviceInfo.serviceFormat = CHRE_MSG_ENDPOINT_SERVICE_FORMAT_CUSTOM;
1191 EXPECT_FALSE(
1192 chreMsgPublishServices(&serviceInfo, /* numServices= */ 1));
1193 triggerWait(TEST_BAD_LEGACY_SERVICE_NAME);
1194 break;
1195 }
1196 case TEST_OPEN_SESSION_WITH_SERVICE: {
1197 EXPECT_TRUE(chreMsgSessionOpenAsync(
1198 kOtherMessageHubId, kEndpointInfos[1].id,
1199 kServiceDescriptorForEndpoint2));
1200 break;
1201 }
1202 }
1203 break;
1204 }
1205 default: {
1206 break;
1207 }
1208 }
1209 }
1210 };
1211
TEST_F(ChreMessageHubTest,OpenSessionWithNanoappService)1212 TEST_F(ChreMessageHubTest, OpenSessionWithNanoappService) {
1213 constexpr uint64_t kNanoappId = 0x1234;
1214
1215 // Load the nanoapp
1216 uint64_t appId = loadNanoapp(MakeUnique<ServiceSessionTestApp>(
1217
1218 TestNanoappInfo{.name = "TEST_OPEN_SESSION_WITH_SERVICE",
1219 .id = kNanoappId}));
1220 Nanoapp *nanoapp = getNanoappByAppId(appId);
1221 ASSERT_NE(nanoapp, nullptr);
1222 TestNanoapp *testNanoapp = queryNanoapp(appId);
1223 ASSERT_NE(testNanoapp, nullptr);
1224
1225 // Create the other hub
1226 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1227 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
1228 /* session= */ nullptr);
1229 std::optional<MessageRouter::MessageHub> messageHub =
1230 MessageRouterSingleton::get()->registerMessageHub(
1231 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1232 ASSERT_TRUE(messageHub.has_value());
1233 callback->setMessageHub(&(*messageHub));
1234
1235 // Nanoapp publishes the service
1236 sendEventToNanoappAndWait(appId, TEST_PUBLISH_SERVICE, TEST_PUBLISH_SERVICE);
1237
1238 // Open the session from the other hub:1 to the nanoapp with the service
1239 SessionId sessionId = SESSION_ID_INVALID;
1240 callback->openSessionAndWaitForOpen([&sessionId, &messageHub]() {
1241 sessionId =
1242 messageHub->openSession(kEndpointInfos[0].id,
1243 EventLoopManagerSingleton::get()
1244 ->getChreMessageHubManager()
1245 .kChreMessageHubId,
1246 kNanoappId, kServiceDescriptorForNanoapp);
1247 EXPECT_NE(sessionId, SESSION_ID_INVALID);
1248 return sessionId;
1249 });
1250
1251 // Wait for the nanoapp to receive the session open event
1252 testNanoapp->wait(CHRE_EVENT_MSG_SESSION_OPENED);
1253
1254 testNanoapp->doActionAndWait(
1255 [&messageHub, &sessionId]() {
1256 messageHub->closeSession(sessionId);
1257 return true;
1258 },
1259 CHRE_EVENT_MSG_SESSION_CLOSED);
1260 }
1261
TEST_F(ChreMessageHubTest,OpenTwoSessionsWithNanoappServiceAndNoService)1262 TEST_F(ChreMessageHubTest, OpenTwoSessionsWithNanoappServiceAndNoService) {
1263 constexpr uint64_t kNanoappId = 0x1234;
1264
1265 // Load the nanoapp
1266 uint64_t appId = loadNanoapp(MakeUnique<ServiceSessionTestApp>(
1267
1268 TestNanoappInfo{.name = "TEST_OPEN_SESSION_WITH_SERVICE",
1269 .id = kNanoappId}));
1270 Nanoapp *nanoapp = getNanoappByAppId(appId);
1271 ASSERT_NE(nanoapp, nullptr);
1272 TestNanoapp *testNanoapp = queryNanoapp(appId);
1273 ASSERT_NE(testNanoapp, nullptr);
1274
1275 // Create the other hub
1276 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1277 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
1278 /* session= */ nullptr);
1279 std::optional<MessageRouter::MessageHub> messageHub =
1280 MessageRouterSingleton::get()->registerMessageHub(
1281 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1282 ASSERT_TRUE(messageHub.has_value());
1283 callback->setMessageHub(&(*messageHub));
1284
1285 // Nanoapp publishes the service
1286 sendEventToNanoappAndWait(appId, TEST_PUBLISH_SERVICE, TEST_PUBLISH_SERVICE);
1287
1288 // Open the session from the other hub:1 to the nanoapp with the service
1289 SessionId sessionId = SESSION_ID_INVALID;
1290 callback->openSessionAndWaitForOpen([&sessionId, &messageHub]() {
1291 sessionId =
1292 messageHub->openSession(kEndpointInfos[0].id,
1293 EventLoopManagerSingleton::get()
1294 ->getChreMessageHubManager()
1295 .kChreMessageHubId,
1296 kNanoappId, kServiceDescriptorForNanoapp);
1297 EXPECT_NE(sessionId, SESSION_ID_INVALID);
1298 return sessionId;
1299 });
1300
1301 // Wait for the nanoapp to receive the session open event
1302 testNanoapp->wait(CHRE_EVENT_MSG_SESSION_OPENED);
1303
1304 // Open the other session from the other hub:1 to the nanoapp
1305 SessionId sessionId2 = SESSION_ID_INVALID;
1306 callback->openSessionAndWaitForOpen([&sessionId, &sessionId2, &messageHub]() {
1307 sessionId2 = messageHub->openSession(kEndpointInfos[0].id,
1308 EventLoopManagerSingleton::get()
1309 ->getChreMessageHubManager()
1310 .kChreMessageHubId,
1311 kNanoappId);
1312 EXPECT_NE(sessionId2, SESSION_ID_INVALID);
1313 EXPECT_NE(sessionId, sessionId2);
1314 return sessionId2;
1315 });
1316
1317 // Wait for the nanoapp to receive the session open event
1318 testNanoapp->wait(CHRE_EVENT_MSG_SESSION_OPENED);
1319
1320 testNanoapp->doActionAndWait(
1321 [&messageHub, &sessionId]() {
1322 messageHub->closeSession(sessionId);
1323 return true;
1324 },
1325 CHRE_EVENT_MSG_SESSION_CLOSED);
1326
1327 testNanoapp->doActionAndWait(
1328 [&messageHub, &sessionId2]() {
1329 messageHub->closeSession(sessionId2);
1330 return true;
1331 },
1332 CHRE_EVENT_MSG_SESSION_CLOSED);
1333 }
1334
TEST_F(ChreMessageHubTest,OpenSessionWithNanoappLegacyService)1335 TEST_F(ChreMessageHubTest, OpenSessionWithNanoappLegacyService) {
1336 // Load the nanoapp
1337 uint64_t appId = loadNanoapp(MakeUnique<ServiceSessionTestApp>(
1338
1339 TestNanoappInfo{.name = "TEST_OPEN_SESSION_WITH_LEGACY_SERVICE",
1340 .id = kLegacyServiceNanoappId}));
1341 Nanoapp *nanoapp = getNanoappByAppId(appId);
1342 ASSERT_NE(nanoapp, nullptr);
1343 TestNanoapp *testNanoapp = queryNanoapp(appId);
1344 ASSERT_NE(testNanoapp, nullptr);
1345
1346 // Create the other hub
1347 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1348 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
1349 /* session= */ nullptr);
1350 std::optional<MessageRouter::MessageHub> messageHub =
1351 MessageRouterSingleton::get()->registerMessageHub(
1352 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1353 ASSERT_TRUE(messageHub.has_value());
1354 callback->setMessageHub(&(*messageHub));
1355
1356 // Open the session from the other hub:1 to the nanoapp with the service
1357 SessionId sessionId = SESSION_ID_INVALID;
1358 callback->openSessionAndWaitForOpen([&sessionId, &messageHub]() {
1359 sessionId =
1360 messageHub->openSession(kEndpointInfos[0].id,
1361 EventLoopManagerSingleton::get()
1362 ->getChreMessageHubManager()
1363 .kChreMessageHubId,
1364 kLegacyServiceNanoappId, kLegacyServiceName);
1365 EXPECT_NE(sessionId, SESSION_ID_INVALID);
1366 return sessionId;
1367 });
1368
1369 testNanoapp->doActionAndWait(
1370 [&messageHub, &sessionId]() {
1371 messageHub->closeSession(sessionId);
1372 return true;
1373 },
1374 CHRE_EVENT_MSG_SESSION_CLOSED);
1375 }
1376
TEST_F(ChreMessageHubTest,ForEachServiceNanoappLegacyService)1377 TEST_F(ChreMessageHubTest, ForEachServiceNanoappLegacyService) {
1378 // Load the nanoapp
1379 uint64_t appId = loadNanoapp(MakeUnique<ServiceSessionTestApp>(
1380
1381 TestNanoappInfo{.name = "TEST_FOR_EACH_SERVICE_LEGACY_SERVICE",
1382 .id = kLegacyServiceNanoappId}));
1383 Nanoapp *nanoapp = getNanoappByAppId(appId);
1384 ASSERT_NE(nanoapp, nullptr);
1385
1386 // Create the other hub
1387 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1388 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
1389 /* session= */ nullptr);
1390 std::optional<MessageRouter::MessageHub> messageHub =
1391 MessageRouterSingleton::get()->registerMessageHub(
1392 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1393 ASSERT_TRUE(messageHub.has_value());
1394 callback->setMessageHub(&(*messageHub));
1395
1396 // Find the service
1397 MessageRouterSingleton::get()->forEachService(
1398 [&](const MessageHubInfo &hub, const EndpointInfo &endpoint,
1399 const ServiceInfo &service) {
1400 if (hub.id == EventLoopManagerSingleton::get()
1401 ->getChreMessageHubManager()
1402 .kChreMessageHubId) {
1403 EXPECT_EQ(endpoint.id, kLegacyServiceNanoappId);
1404 EXPECT_STREQ(service.serviceDescriptor, kLegacyServiceName);
1405 EXPECT_EQ(service.majorVersion, 1);
1406 EXPECT_EQ(service.minorVersion, 0);
1407 EXPECT_EQ(service.format, RpcFormat::PW_RPC_PROTOBUF);
1408 return true;
1409 }
1410 return false;
1411 });
1412 }
1413
TEST_F(ChreMessageHubTest,NanoappFailsToPublishLegacyServiceInNewWay)1414 TEST_F(ChreMessageHubTest, NanoappFailsToPublishLegacyServiceInNewWay) {
1415 constexpr uint64_t kNanoappId = 0x1234;
1416
1417 // Load the nanoapp
1418 uint64_t appId = loadNanoapp(MakeUnique<ServiceSessionTestApp>(
1419
1420 TestNanoappInfo{.name = "TEST_BAD_LEGACY_SERVICE_NAME",
1421 .id = kNanoappId}));
1422 Nanoapp *nanoapp = getNanoappByAppId(appId);
1423 ASSERT_NE(nanoapp, nullptr);
1424
1425 // Create the other hub
1426 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1427 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
1428 /* session= */ nullptr);
1429 std::optional<MessageRouter::MessageHub> messageHub =
1430 MessageRouterSingleton::get()->registerMessageHub(
1431 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1432 ASSERT_TRUE(messageHub.has_value());
1433 callback->setMessageHub(&(*messageHub));
1434
1435 // Nanoapp publishes the service
1436 sendEventToNanoappAndWait(appId, TEST_BAD_LEGACY_SERVICE_NAME,
1437 TEST_BAD_LEGACY_SERVICE_NAME);
1438 }
1439
TEST_F(ChreMessageHubTest,NanoappOpensSessionWithService)1440 TEST_F(ChreMessageHubTest, NanoappOpensSessionWithService) {
1441 constexpr uint64_t kNanoappId = 0x1234;
1442
1443 // Load the nanoapp
1444 uint64_t appId = loadNanoapp(MakeUnique<ServiceSessionTestApp>(
1445
1446 TestNanoappInfo{.name = "TEST_OPEN_SESSION_WITH_SERVICE",
1447 .id = kNanoappId}));
1448 Nanoapp *nanoapp = getNanoappByAppId(appId);
1449 ASSERT_NE(nanoapp, nullptr);
1450
1451 // Create the other hub
1452 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1453 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
1454 /* session= */ nullptr);
1455 std::optional<MessageRouter::MessageHub> messageHub =
1456 MessageRouterSingleton::get()->registerMessageHub(
1457 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1458 ASSERT_TRUE(messageHub.has_value());
1459 callback->setMessageHub(&(*messageHub));
1460
1461 // Nanoapp opens the session with the service
1462 sendEventToNanoappAndWait(appId, TEST_OPEN_SESSION_WITH_SERVICE,
1463 CHRE_EVENT_MSG_SESSION_OPENED);
1464 }
1465
TEST_F(ChreMessageHubTest,NanoappUnloadUnregistersProvidedServices)1466 TEST_F(ChreMessageHubTest, NanoappUnloadUnregistersProvidedServices) {
1467 constexpr uint64_t kNanoappId = 0x1234;
1468
1469 // Create the other hub
1470 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1471 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
1472 /* session= */ nullptr);
1473 std::optional<MessageRouter::MessageHub> messageHub =
1474 MessageRouterSingleton::get()->registerMessageHub(
1475 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1476 ASSERT_TRUE(messageHub.has_value());
1477 callback->setMessageHub(&(*messageHub));
1478
1479 // Load the nanoapp
1480 uint64_t appId = loadNanoapp(MakeUnique<ServiceSessionTestApp>(
1481
1482 TestNanoappInfo{.name = "TEST_UNLOAD_UNREGISTERS_PROVIDED_SERVICES",
1483 .id = kNanoappId}));
1484 Nanoapp *nanoapp = getNanoappByAppId(appId);
1485 callback->setMessageHub(&(*messageHub));
1486
1487 // Nanoapp publishes the service
1488 sendEventToNanoappAndWait(appId, TEST_PUBLISH_SERVICE, TEST_PUBLISH_SERVICE);
1489
1490 // Get the endpoint ID for the service
1491 std::optional<Endpoint> endpoint =
1492 MessageRouterSingleton::get()->getEndpointForService(
1493 EventLoopManagerSingleton::get()
1494 ->getChreMessageHubManager()
1495 .kChreMessageHubId,
1496 kServiceDescriptorForNanoapp);
1497 EXPECT_TRUE(endpoint.has_value());
1498 EXPECT_EQ(endpoint->messageHubId, EventLoopManagerSingleton::get()
1499 ->getChreMessageHubManager()
1500 .kChreMessageHubId);
1501 EXPECT_EQ(endpoint->endpointId, kNanoappId);
1502
1503 // Unload the nanoapp
1504 unloadNanoapp(appId);
1505
1506 // Load another nanoapp. This forces this thread to wait for the finish
1507 // load nanoapp event to process, which is after the cleanup event.
1508 loadNanoapp(MakeUnique<TestNanoapp>());
1509
1510 // The service should be gone
1511 endpoint = MessageRouterSingleton::get()->getEndpointForService(
1512 EventLoopManagerSingleton::get()
1513 ->getChreMessageHubManager()
1514 .kChreMessageHubId,
1515 kServiceDescriptorForNanoapp);
1516 EXPECT_FALSE(endpoint.has_value());
1517 }
1518
1519 //! Nanoapp used to test endpoint registration and ready events
1520 class EndpointRegistrationTestApp : public TestNanoapp {
1521 public:
EndpointRegistrationTestApp(const TestNanoappInfo & info)1522 EndpointRegistrationTestApp(const TestNanoappInfo &info)
1523 : TestNanoapp(info) {}
1524
handleEvent(uint32_t,uint16_t eventType,const void * eventData)1525 void handleEvent(uint32_t, uint16_t eventType,
1526 const void *eventData) override {
1527 switch (eventType) {
1528 case CHRE_EVENT_MSG_ENDPOINT_READY: {
1529 auto event = static_cast<const chreMsgEndpointReadyEvent *>(eventData);
1530 EXPECT_EQ(event->hubId, kOtherMessageHubId);
1531 EXPECT_EQ(event->endpointId, mEndpointId);
1532 triggerWait(CHRE_EVENT_MSG_ENDPOINT_READY);
1533 break;
1534 }
1535 case CHRE_EVENT_MSG_SERVICE_READY: {
1536 auto event = static_cast<const chreMsgServiceReadyEvent *>(eventData);
1537 EXPECT_EQ(event->hubId, kOtherMessageHubId);
1538 EXPECT_EQ(event->endpointId, kDynamicEndpointInfo.id);
1539 EXPECT_STREQ(event->serviceDescriptor,
1540 kServiceDescriptorForDynamicEndpoint);
1541 triggerWait(CHRE_EVENT_MSG_SERVICE_READY);
1542 break;
1543 }
1544 case CHRE_EVENT_TEST_EVENT: {
1545 auto event = static_cast<const TestEvent *>(eventData);
1546 switch (event->type) {
1547 case TEST_SUBSCRIBE_TO_READY_EVENT: {
1548 mEndpointId = kDynamicEndpointInfo.id;
1549 EXPECT_TRUE(chreMsgConfigureEndpointReadyEvents(
1550 kOtherMessageHubId, mEndpointId,
1551 /* enable= */ true));
1552 triggerWait(TEST_SUBSCRIBE_TO_READY_EVENT);
1553 break;
1554 }
1555 case TEST_SUBSCRIBE_TO_READY_EVENT_ALREADY_EXISTS: {
1556 mEndpointId = kEndpointInfos[1].id;
1557 EXPECT_TRUE(chreMsgConfigureEndpointReadyEvents(
1558 kOtherMessageHubId, mEndpointId,
1559 /* enable= */ true));
1560 break;
1561 }
1562 case TEST_UNSUBSCRIBE_FROM_READY_EVENT: {
1563 EXPECT_TRUE(chreMsgConfigureEndpointReadyEvents(
1564 kOtherMessageHubId, mEndpointId,
1565 /* enable= */ false));
1566 triggerWait(TEST_UNSUBSCRIBE_FROM_READY_EVENT);
1567 break;
1568 }
1569 case TEST_SUBSCRIBE_TO_SERVICE_READY_EVENT: {
1570 EXPECT_TRUE(chreMsgConfigureServiceReadyEvents(
1571 kOtherMessageHubId, kServiceDescriptorForDynamicEndpoint,
1572 /* enable= */ true));
1573 triggerWait(TEST_SUBSCRIBE_TO_SERVICE_READY_EVENT);
1574 break;
1575 }
1576 case TEST_UNSUBSCRIBE_FROM_SERVICE_READY_EVENT: {
1577 EXPECT_TRUE(chreMsgConfigureServiceReadyEvents(
1578 kOtherMessageHubId, kServiceDescriptorForDynamicEndpoint,
1579 /* enable= */ false));
1580 triggerWait(TEST_UNSUBSCRIBE_FROM_SERVICE_READY_EVENT);
1581 break;
1582 }
1583 }
1584 break;
1585 }
1586 default: {
1587 break;
1588 }
1589 }
1590 }
1591
1592 EndpointId mEndpointId = ENDPOINT_ID_INVALID;
1593 };
1594
TEST_F(ChreMessageHubTest,NanoappSubscribesToEndpointReadyEvent)1595 TEST_F(ChreMessageHubTest, NanoappSubscribesToEndpointReadyEvent) {
1596 // Load the nanoapp
1597 uint64_t appId = loadNanoapp(MakeUnique<EndpointRegistrationTestApp>(
1598
1599 TestNanoappInfo{.name = "TEST_ENDPOINT_READY_EVENT", .id = 0x1234}));
1600 Nanoapp *nanoapp = getNanoappByAppId(appId);
1601 ASSERT_NE(nanoapp, nullptr);
1602 TestNanoapp *testNanoapp = queryNanoapp(appId);
1603 ASSERT_NE(testNanoapp, nullptr);
1604
1605 // Create the other hub
1606 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1607 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
1608 /* session= */ nullptr);
1609 std::optional<MessageRouter::MessageHub> messageHub =
1610 MessageRouterSingleton::get()->registerMessageHub(
1611 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1612 ASSERT_TRUE(messageHub.has_value());
1613 callback->setMessageHub(&(*messageHub));
1614
1615 // Test subscribing to the ready event
1616 sendEventToNanoappAndWait(appId, TEST_SUBSCRIBE_TO_READY_EVENT,
1617 TEST_SUBSCRIBE_TO_READY_EVENT);
1618
1619 // Register the endpoint and wait for the ready event
1620 EXPECT_TRUE(messageHub->registerEndpoint(kDynamicEndpointInfo.id));
1621 testNanoapp->wait(CHRE_EVENT_MSG_ENDPOINT_READY);
1622
1623 // Unsubscribe from the ready event
1624 sendEventToNanoappAndWait(appId, TEST_UNSUBSCRIBE_FROM_READY_EVENT,
1625 TEST_UNSUBSCRIBE_FROM_READY_EVENT);
1626 }
1627
TEST_F(ChreMessageHubTest,NanoappSubscribesToEndpointReadyEventAlreadyExists)1628 TEST_F(ChreMessageHubTest, NanoappSubscribesToEndpointReadyEventAlreadyExists) {
1629 // Load the nanoapp
1630 uint64_t appId = loadNanoapp(MakeUnique<EndpointRegistrationTestApp>(
1631
1632 TestNanoappInfo{.name = "TEST_ENDPOINT_READY_EVENT", .id = 0x1234}));
1633 Nanoapp *nanoapp = getNanoappByAppId(appId);
1634 ASSERT_NE(nanoapp, nullptr);
1635
1636 // Create the other hub
1637 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1638 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
1639 /* session= */ nullptr);
1640 std::optional<MessageRouter::MessageHub> messageHub =
1641 MessageRouterSingleton::get()->registerMessageHub(
1642 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1643 ASSERT_TRUE(messageHub.has_value());
1644 callback->setMessageHub(&(*messageHub));
1645
1646 // Test subscribing to the ready event - endpoint should already exist
1647 sendEventToNanoappAndWait(appId, TEST_SUBSCRIBE_TO_READY_EVENT_ALREADY_EXISTS,
1648 CHRE_EVENT_MSG_ENDPOINT_READY);
1649
1650 // Unsubscribe from the ready event
1651 sendEventToNanoappAndWait(appId, TEST_UNSUBSCRIBE_FROM_READY_EVENT,
1652 TEST_UNSUBSCRIBE_FROM_READY_EVENT);
1653 }
1654
TEST_F(ChreMessageHubTest,NanoappSubscribesToServiceReadyEvent)1655 TEST_F(ChreMessageHubTest, NanoappSubscribesToServiceReadyEvent) {
1656 // Load the nanoapp
1657 uint64_t appId = loadNanoapp(MakeUnique<EndpointRegistrationTestApp>(
1658 TestNanoappInfo{.name = "TEST_SERVICE_READY_EVENT", .id = 0x1234}));
1659 Nanoapp *nanoapp = getNanoappByAppId(appId);
1660 ASSERT_NE(nanoapp, nullptr);
1661 TestNanoapp *testNanoapp = queryNanoapp(appId);
1662 ASSERT_NE(testNanoapp, nullptr);
1663
1664 // Create the other hub
1665 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1666 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
1667 /* session= */ nullptr);
1668 std::optional<MessageRouter::MessageHub> messageHub =
1669 MessageRouterSingleton::get()->registerMessageHub(
1670 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1671 ASSERT_TRUE(messageHub.has_value());
1672 callback->setMessageHub(&(*messageHub));
1673
1674 // Test subscribing to the service ready event
1675 sendEventToNanoappAndWait(appId, TEST_SUBSCRIBE_TO_SERVICE_READY_EVENT,
1676 TEST_SUBSCRIBE_TO_SERVICE_READY_EVENT);
1677
1678 // Register the endpoint and wait for the service ready event
1679 EXPECT_TRUE(messageHub->registerEndpoint(kDynamicEndpointInfo.id));
1680 testNanoapp->wait(CHRE_EVENT_MSG_SERVICE_READY);
1681
1682 // Unsubscribe from the service ready event
1683 sendEventToNanoappAndWait(appId, TEST_UNSUBSCRIBE_FROM_SERVICE_READY_EVENT,
1684 TEST_UNSUBSCRIBE_FROM_SERVICE_READY_EVENT);
1685 }
1686
TEST_F(ChreMessageHubTest,NanoappLoadAndUnloadAreRegisteredAndUnregistered)1687 TEST_F(ChreMessageHubTest, NanoappLoadAndUnloadAreRegisteredAndUnregistered) {
1688 // Create the other hub
1689 pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
1690 pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
1691 /* session= */ nullptr);
1692 std::optional<MessageRouter::MessageHub> messageHub =
1693 MessageRouterSingleton::get()->registerMessageHub(
1694 "OTHER_TEST_HUB", kOtherMessageHubId, callback);
1695 ASSERT_TRUE(messageHub.has_value());
1696 callback->setMessageHub(&(*messageHub));
1697
1698 // Load the nanoapp
1699 uint64_t appId = loadNanoapp(MakeUnique<EndpointRegistrationTestApp>(
1700 TestNanoappInfo{.name = "TEST_NANOAPP_REGISTRATION", .id = 0x1234}));
1701 Nanoapp *nanoapp = getNanoappByAppId(appId);
1702 ASSERT_NE(nanoapp, nullptr);
1703
1704 // The nanoapp should be registered as an endpoint
1705 EXPECT_TRUE(
1706 callback->hasEndpointBeenRegistered(EventLoopManagerSingleton::get()
1707 ->getChreMessageHubManager()
1708 .kChreMessageHubId,
1709 appId));
1710
1711 // Unload the nanoapp
1712 unloadNanoapp(appId);
1713
1714 // The nanoapp should be unregistered as an endpoint
1715 EXPECT_FALSE(
1716 callback->hasEndpointBeenRegistered(EventLoopManagerSingleton::get()
1717 ->getChreMessageHubManager()
1718 .kChreMessageHubId,
1719 appId));
1720 }
1721
1722 } // namespace
1723 } // namespace chre::message
1724