• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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