• 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 #ifdef CHRE_MESSAGE_ROUTER_SUPPORT_ENABLED
18 
19 #include "chre/core/chre_message_hub_manager.h"
20 #include "chre/core/event_loop.h"
21 #include "chre/core/event_loop_manager.h"
22 #include "chre/core/nanoapp.h"
23 #include "chre/platform/context.h"
24 #include "chre/platform/fatal_error.h"
25 #include "chre/target_platform/log.h"
26 #include "chre/util/conditional_lock_guard.h"
27 #include "chre/util/lock_guard.h"
28 #include "chre/util/nested_data_ptr.h"
29 #include "chre/util/system/event_callbacks.h"
30 #include "chre/util/system/message_common.h"
31 #include "chre/util/system/message_router.h"
32 #include "chre/util/system/service_helpers.h"
33 #include "chre/util/system/system_callback_type.h"
34 #include "chre/util/unique_ptr.h"
35 #include "chre_api/chre.h"
36 
37 #include "pw_allocator/unique_ptr.h"
38 #include "pw_intrusive_ptr/intrusive_ptr.h"
39 
40 #include <cinttypes>
41 #include <cstddef>
42 #include <cstdlib>
43 #include <cstring>
44 #include <optional>
45 
46 using ::chre::message::Endpoint;
47 using ::chre::message::ENDPOINT_ID_ANY;
48 using ::chre::message::ENDPOINT_ID_INVALID;
49 using ::chre::message::EndpointId;
50 using ::chre::message::EndpointInfo;
51 using ::chre::message::EndpointType;
52 using ::chre::message::extractNanoappIdAndServiceId;
53 using ::chre::message::Message;
54 using ::chre::message::MESSAGE_HUB_ID_ANY;
55 using ::chre::message::MESSAGE_HUB_ID_INVALID;
56 using ::chre::message::MessageHubId;
57 using ::chre::message::MessageHubInfo;
58 using ::chre::message::MessageRouter;
59 using ::chre::message::MessageRouterSingleton;
60 using ::chre::message::Reason;
61 using ::chre::message::RpcFormat;
62 using ::chre::message::ServiceInfo;
63 using ::chre::message::Session;
64 using ::chre::message::SESSION_ID_INVALID;
65 using ::chre::message::SessionId;
66 
67 namespace chre {
68 
69 namespace {
70 
71 //! Sends a ready event to the nanoapp with the given instance ID. If
72 //! serviceDescriptor is null, then the ready event is for an endpoint, else it
73 //! is for a service.
74 template <typename T>
sendReadyEventToNanoapp(uint16_t nanoappInstanceId,MessageHubId messageHubId,EndpointId endpointId,const char * serviceDescriptor)75 void sendReadyEventToNanoapp(uint16_t nanoappInstanceId,
76                              MessageHubId messageHubId, EndpointId endpointId,
77                              const char *serviceDescriptor) {
78   static_assert(std::is_same_v<T, chreMsgServiceReadyEvent> ||
79                 std::is_same_v<T, chreMsgEndpointReadyEvent>);
80 
81   UniquePtr<T> event = MakeUnique<T>();
82   if (event.isNull()) {
83     FATAL_ERROR_OOM();
84     return;
85   }
86 
87   event->hubId = messageHubId;
88   event->endpointId = endpointId;
89   if constexpr (std::is_same_v<T, chreMsgServiceReadyEvent>) {
90     std::strncpy(event->serviceDescriptor, serviceDescriptor,
91                  CHRE_MSG_MAX_SERVICE_DESCRIPTOR_LEN);
92     event->serviceDescriptor[CHRE_MSG_MAX_SERVICE_DESCRIPTOR_LEN - 1] = '\0';
93   }
94 
95   EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
96       std::is_same_v<T, chreMsgServiceReadyEvent>
97           ? CHRE_EVENT_MSG_SERVICE_READY
98           : CHRE_EVENT_MSG_ENDPOINT_READY,
99       event.release(), freeEventDataCallback, nanoappInstanceId);
100 }
101 
102 //! Sends a ready event to the nanoapp with the given instance ID. If
103 //! serviceDescriptor is null, then the ready event is for an endpoint, else it
104 //! is for a service.
sendReadyEventToNanoapp(uint16_t nanoappInstanceId,MessageHubId messageHubId,EndpointId endpointId,const char * serviceDescriptor)105 void sendReadyEventToNanoapp(uint16_t nanoappInstanceId,
106                              MessageHubId messageHubId, EndpointId endpointId,
107                              const char *serviceDescriptor) {
108   if (serviceDescriptor == nullptr) {
109     sendReadyEventToNanoapp<chreMsgEndpointReadyEvent>(
110         nanoappInstanceId, messageHubId, endpointId, serviceDescriptor);
111   } else {
112     sendReadyEventToNanoapp<chreMsgServiceReadyEvent>(
113         nanoappInstanceId, messageHubId, endpointId, serviceDescriptor);
114   }
115 }
116 
117 }  // anonymous namespace
118 
ChreMessageHubManager()119 ChreMessageHubManager::ChreMessageHubManager()
120     : mAllocator(ChreMessageHubManager::onMessageFreeCallback,
121                  mFreeCallbackRecords, /* doEraseRecord= */ false) {}
122 
~ChreMessageHubManager()123 ChreMessageHubManager::~ChreMessageHubManager() {
124   mChreMessageHub.unregister();
125   mChreMessageHubCallback->clearManager();
126 }
127 
init()128 void ChreMessageHubManager::init() {
129   ChreMessageHubCallback *callbackPtr =
130       memoryAlloc<ChreMessageHubCallback>(*this);
131   if (callbackPtr == nullptr) {
132     FATAL_ERROR_OOM();
133     return;
134   }
135   mChreMessageHubCallback =
136       pw::IntrusivePtr<ChreMessageHubCallback>(callbackPtr);
137 
138   std::optional<MessageRouter::MessageHub> chreMessageHub =
139       MessageRouterSingleton::get()->registerMessageHub(
140           "CHRE", kChreMessageHubId, mChreMessageHubCallback);
141   if (chreMessageHub.has_value()) {
142     mChreMessageHub = std::move(*chreMessageHub);
143   } else {
144     FATAL_ERROR("Failed to register the CHRE MessageHub");
145   }
146 }
147 
getEndpointInfo(MessageHubId hubId,EndpointId endpointId,chreMsgEndpointInfo & info)148 bool ChreMessageHubManager::getEndpointInfo(MessageHubId hubId,
149                                             EndpointId endpointId,
150                                             chreMsgEndpointInfo &info) {
151   std::optional<EndpointInfo> endpointInfo =
152       MessageRouterSingleton::get()->getEndpointInfo(hubId, endpointId);
153   if (!endpointInfo.has_value()) {
154     return false;
155   }
156 
157   info.hubId = hubId;
158   info.endpointId = endpointId;
159   info.type = toChreEndpointType(endpointInfo->type);
160   info.version = endpointInfo->version;
161   info.requiredPermissions = endpointInfo->requiredPermissions;
162   // TODO(b/404241918): populate maxMessageSize from MessageRouter
163   info.maxMessageSize = chreGetMessageToHostMaxSize();
164   std::strncpy(info.name, endpointInfo->name, CHRE_MAX_ENDPOINT_NAME_LEN);
165   info.name[CHRE_MAX_ENDPOINT_NAME_LEN - 1] = '\0';
166   return true;
167 }
168 
configureReadyEvents(uint16_t nanoappInstanceId,EndpointId fromEndpointId,MessageHubId hubId,EndpointId endpointId,const char * serviceDescriptor,bool enable)169 bool ChreMessageHubManager::configureReadyEvents(
170     uint16_t nanoappInstanceId, EndpointId fromEndpointId, MessageHubId hubId,
171     EndpointId endpointId, const char *serviceDescriptor, bool enable) {
172   CHRE_ASSERT(inEventLoopThread());
173 
174   if (hubId == MESSAGE_HUB_ID_INVALID && endpointId == ENDPOINT_ID_INVALID &&
175       serviceDescriptor == nullptr) {
176     LOGE(
177         "Invalid arguments to configureReadyEvents: hubId, endpointId and "
178         "serviceDescriptor cannot all be invalid");
179     return false;
180   }
181 
182   if (!enable) {
183     disableReadyEvents(fromEndpointId, hubId, endpointId, serviceDescriptor);
184     return true;
185   }
186 
187   if (!mEndpointReadyEventRequests.push_back(
188           EndpointReadyEventData{.fromEndpointId = fromEndpointId,
189                                  .messageHubId = hubId,
190                                  .endpointId = endpointId,
191                                  .serviceDescriptor = serviceDescriptor})) {
192     LOG_OOM();
193     return false;
194   }
195 
196   std::optional<Endpoint> endpoint =
197       searchForEndpoint(hubId, endpointId, serviceDescriptor);
198   if (endpoint.has_value()) {
199     sendReadyEventToNanoapp(nanoappInstanceId, endpoint->messageHubId,
200                             endpoint->endpointId, serviceDescriptor);
201   }
202   return true;
203 }
204 
getSessionInfo(EndpointId fromEndpointId,SessionId sessionId,chreMsgSessionInfo & info)205 bool ChreMessageHubManager::getSessionInfo(EndpointId fromEndpointId,
206                                            SessionId sessionId,
207                                            chreMsgSessionInfo &info) {
208   std::optional<Session> session = mChreMessageHub.getSessionWithId(sessionId);
209   if (!session.has_value()) {
210     return false;
211   }
212 
213   bool initiatorIsNanoapp =
214       session->initiator.messageHubId == kChreMessageHubId &&
215       session->initiator.endpointId == fromEndpointId;
216   bool peerIsNanoapp = session->peer.messageHubId == kChreMessageHubId &&
217                        session->peer.endpointId == fromEndpointId;
218   if (!initiatorIsNanoapp && !peerIsNanoapp) {
219     LOGE("Nanoapp with ID 0x%" PRIx64
220          " is not the initiator or peer of session with ID %" PRIu16,
221          fromEndpointId, sessionId);
222     return false;
223   }
224 
225   info.hubId = initiatorIsNanoapp ? session->peer.messageHubId
226                                   : session->initiator.messageHubId;
227   info.endpointId = initiatorIsNanoapp ? session->peer.endpointId
228                                        : session->initiator.endpointId;
229 
230   if (session->hasServiceDescriptor) {
231     std::strncpy(info.serviceDescriptor, session->serviceDescriptor,
232                  CHRE_MSG_MAX_SERVICE_DESCRIPTOR_LEN);
233     info.serviceDescriptor[CHRE_MSG_MAX_SERVICE_DESCRIPTOR_LEN - 1] = '\0';
234   } else {
235     info.serviceDescriptor[0] = '\0';
236   }
237 
238   info.sessionId = sessionId;
239   info.reason = chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_UNSPECIFIED;
240   return true;
241 }
242 
openSessionAsync(EndpointId fromEndpointId,MessageHubId toHubId,EndpointId toEndpointId,const char * serviceDescriptor)243 bool ChreMessageHubManager::openSessionAsync(EndpointId fromEndpointId,
244                                              MessageHubId toHubId,
245                                              EndpointId toEndpointId,
246                                              const char *serviceDescriptor) {
247   SessionId sessionId = EventLoopManagerSingleton::get()
248                             ->getChreMessageHubManager()
249                             .getMessageHub()
250                             .openSession(fromEndpointId, toHubId, toEndpointId,
251                                          serviceDescriptor);
252   return sessionId != SESSION_ID_INVALID;
253 }
254 
openDefaultSessionAsync(EndpointId fromEndpointId,MessageHubId toHubId,EndpointId toEndpointId,const char * serviceDescriptor)255 bool ChreMessageHubManager::openDefaultSessionAsync(
256     EndpointId fromEndpointId, MessageHubId toHubId, EndpointId toEndpointId,
257     const char *serviceDescriptor) {
258   std::optional<Endpoint> endpoint =
259       searchForEndpoint(toHubId, toEndpointId, serviceDescriptor);
260   return endpoint.has_value() &&
261          openSessionAsync(fromEndpointId, endpoint->messageHubId,
262                           endpoint->endpointId, serviceDescriptor);
263 }
264 
closeSession(EndpointId fromEndpointId,SessionId sessionId)265 bool ChreMessageHubManager::closeSession(EndpointId fromEndpointId,
266                                          SessionId sessionId) {
267   std::optional<Session> session = mChreMessageHub.getSessionWithId(sessionId);
268   if (!session.has_value()) {
269     LOGE("Failed to close session with ID %" PRIu16 ": session not found",
270          sessionId);
271     return false;
272   }
273 
274   Endpoint nanoapp(kChreMessageHubId, fromEndpointId);
275   if (session->initiator != nanoapp && session->peer != nanoapp) {
276     LOGE("Nanoapp with ID 0x%" PRIx64
277          " is not the initiator or peer of session with ID %" PRIu16,
278          fromEndpointId, sessionId);
279     return false;
280   }
281   return mChreMessageHub.closeSession(sessionId);
282 }
283 
sendMessage(void * message,size_t messageSize,uint32_t messageType,uint16_t sessionId,uint32_t messagePermissions,chreMessageFreeFunction * freeCallback,EndpointId fromEndpointId)284 bool ChreMessageHubManager::sendMessage(void *message, size_t messageSize,
285                                         uint32_t messageType,
286                                         uint16_t sessionId,
287                                         uint32_t messagePermissions,
288                                         chreMessageFreeFunction *freeCallback,
289                                         EndpointId fromEndpointId) {
290   bool success = false;
291   if ((message == nullptr) != (freeCallback == nullptr)) {
292     // We don't allow this because a null callback with non-null message is
293     // susceptible to bugs where the nanoapp modifies the data while it is still
294     // being used by the system, and a non-null callback with null message is
295     // not meaningful since there is no data to release and we make no
296     // guarantees about when the callback is invoked.
297     LOGE("Mixing null and non-null message and free callback is not allowed");
298   } else {
299     pw::UniquePtr<std::byte[]> messageData =
300         mAllocator.MakeUniqueArrayWithCallback(
301             reinterpret_cast<std::byte *>(message), messageSize,
302             MessageFreeCallbackData{.freeCallback = freeCallback,
303                                     .nanoappId = fromEndpointId});
304     if (messageData == nullptr) {
305       LOG_OOM();
306     } else {
307       success = mChreMessageHub.sendMessage(std::move(messageData), messageType,
308                                             messagePermissions, sessionId,
309                                             fromEndpointId);
310     }
311   }
312 
313   if (!success && freeCallback != nullptr) {
314     freeCallback(message, messageSize);
315   }
316   return success;
317 }
318 
publishServices(EndpointId fromEndpointId,const chreMsgServiceInfo * serviceInfos,size_t numServices)319 bool ChreMessageHubManager::publishServices(
320     EndpointId fromEndpointId, const chreMsgServiceInfo *serviceInfos,
321     size_t numServices) {
322   CHRE_ASSERT(inEventLoopThread());
323 
324   LockGuard<Mutex> lockGuard(mNanoappPublishedServicesMutex);
325   if (!validateServicesLocked(fromEndpointId, serviceInfos, numServices)) {
326     return false;
327   }
328 
329   if (!mNanoappPublishedServices.reserve(mNanoappPublishedServices.size() +
330                                          numServices)) {
331     LOG_OOM();
332     return false;
333   }
334 
335   for (size_t i = 0; i < numServices; ++i) {
336     // Cannot fail as we reserved space for the push above
337     mNanoappPublishedServices.push_back(NanoappServiceData{
338         .nanoappId = fromEndpointId, .serviceInfo = serviceInfos[i]});
339   }
340   return true;
341 }
342 
unregisterEndpoint(EndpointId endpointId)343 void ChreMessageHubManager::unregisterEndpoint(EndpointId endpointId) {
344   UniquePtr<EndpointId> endpointIdPtr = MakeUnique<EndpointId>(endpointId);
345   if (endpointIdPtr.isNull()) {
346     FATAL_ERROR_OOM();
347     return;
348   }
349 
350   EventLoopManagerSingleton::get()->deferCallback(
351       SystemCallbackType::EndpointCleanupNanoappEvent, std::move(endpointIdPtr),
352       [](SystemCallbackType /* type */, UniquePtr<EndpointId> &&endpointId) {
353         EventLoopManagerSingleton::get()
354             ->getChreMessageHubManager()
355             .cleanupEndpointResources(*endpointId);
356       });
357 
358   mChreMessageHub.unregisterEndpoint(endpointId);
359 }
360 
cleanupEndpointResources(EndpointId endpointId)361 void ChreMessageHubManager::cleanupEndpointResources(EndpointId endpointId) {
362   CHRE_ASSERT(inEventLoopThread());
363 
364   {
365     LockGuard<Mutex> lockGuard(mNanoappPublishedServicesMutex);
366     for (size_t i = 0; i < mNanoappPublishedServices.size();) {
367       if (mNanoappPublishedServices[i].nanoappId == endpointId) {
368         mNanoappPublishedServices.erase(i);
369       } else {
370         ++i;
371       }
372     }
373   }
374 
375   for (size_t i = 0; i < mEndpointReadyEventRequests.size(); ++i) {
376     if (mEndpointReadyEventRequests[i].fromEndpointId == endpointId) {
377       mEndpointReadyEventRequests.erase(i);
378     } else {
379       ++i;
380     }
381   }
382 }
383 
toChreEndpointType(EndpointType type)384 chreMsgEndpointType ChreMessageHubManager::toChreEndpointType(
385     EndpointType type) {
386   switch (type) {
387     case EndpointType::HOST_FRAMEWORK:
388       return chreMsgEndpointType::CHRE_MSG_ENDPOINT_TYPE_HOST_FRAMEWORK;
389     case EndpointType::HOST_APP:
390       return chreMsgEndpointType::CHRE_MSG_ENDPOINT_TYPE_HOST_APP;
391     case EndpointType::HOST_NATIVE:
392       return chreMsgEndpointType::CHRE_MSG_ENDPOINT_TYPE_HOST_NATIVE;
393     case EndpointType::NANOAPP:
394       return chreMsgEndpointType::CHRE_MSG_ENDPOINT_TYPE_NANOAPP;
395     case EndpointType::GENERIC:
396       return chreMsgEndpointType::CHRE_MSG_ENDPOINT_TYPE_GENERIC;
397     default:
398       LOGE("Unknown endpoint type: %" PRIu8, type);
399       return chreMsgEndpointType::CHRE_MSG_ENDPOINT_TYPE_INVALID;
400   }
401 }
402 
toChreEndpointReason(Reason reason)403 chreMsgEndpointReason ChreMessageHubManager::toChreEndpointReason(
404     Reason reason) {
405   switch (reason) {
406     case Reason::UNSPECIFIED:
407       return chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_UNSPECIFIED;
408     case Reason::OUT_OF_MEMORY:
409       return chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_OUT_OF_MEMORY;
410     case Reason::TIMEOUT:
411       return chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_TIMEOUT;
412     case Reason::OPEN_ENDPOINT_SESSION_REQUEST_REJECTED:
413       return chreMsgEndpointReason::
414           CHRE_MSG_ENDPOINT_REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED;
415     case Reason::CLOSE_ENDPOINT_SESSION_REQUESTED:
416       return chreMsgEndpointReason::
417           CHRE_MSG_ENDPOINT_REASON_CLOSE_ENDPOINT_SESSION_REQUESTED;
418     case Reason::ENDPOINT_INVALID:
419       return chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_ENDPOINT_INVALID;
420     case Reason::ENDPOINT_GONE:
421       return chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_ENDPOINT_GONE;
422     case Reason::ENDPOINT_CRASHED:
423       return chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_ENDPOINT_CRASHED;
424     case Reason::HUB_RESET:
425       return chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_HUB_RESET;
426     case Reason::PERMISSION_DENIED:
427       return chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_PERMISSION_DENIED;
428     default:
429       LOGE("Unknown endpoint reason: %" PRIu8, reason);
430       return chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_UNSPECIFIED;
431   }
432 }
433 
onMessageToNanoappCallback(SystemCallbackType,UniquePtr<MessageCallbackData> && data)434 void ChreMessageHubManager::onMessageToNanoappCallback(
435     SystemCallbackType /* type */, UniquePtr<MessageCallbackData> &&data) {
436   bool success = false;
437   Nanoapp *nanoapp =
438       EventLoopManagerSingleton::get()->getEventLoop().findNanoappByAppId(
439           data->nanoappId);
440   uint32_t messagePermissions = data->messageToNanoapp.messagePermissions;
441   if (nanoapp == nullptr) {
442     LOGE("Unable to find nanoapp with ID 0x%" PRIx64
443          " to receive message with type %" PRIu32 " and permissions %" PRIu32
444          " with session ID %" PRIu16,
445          data->nanoappId, data->messageToNanoapp.messageType,
446          data->messageToNanoapp.messagePermissions,
447          data->messageToNanoapp.sessionId);
448   } else if (!nanoapp->hasPermissions(messagePermissions)) {
449     LOGE("nanoapp with ID 0x%" PRIx64
450          " does not have permissions to receive "
451          "message with type %" PRIu32 " and permissions 0x%" PRIx32,
452          nanoapp->getAppId(), data->messageToNanoapp.messageType,
453          data->messageToNanoapp.messagePermissions);
454   } else if (!EventLoopManagerSingleton::get()
455                   ->getEventLoop()
456                   .distributeEventSync(CHRE_EVENT_MSG_FROM_ENDPOINT,
457                                        &data->messageToNanoapp,
458                                        nanoapp->getInstanceId())) {
459     LOGE("Unable to distribute message to nanoapp with ID 0x%" PRIx64,
460          nanoapp->getAppId());
461   } else {
462     success = true;
463   }
464 
465   // Close session on failure so sender knows there was an issue
466   if (!success) {
467     EventLoopManagerSingleton::get()
468         ->getChreMessageHubManager()
469         .getMessageHub()
470         .closeSession(data->messageToNanoapp.sessionId);
471   }
472 }
473 
onSessionStateChangedCallback(SystemCallbackType,UniquePtr<SessionCallbackData> && data)474 void ChreMessageHubManager::onSessionStateChangedCallback(
475     SystemCallbackType /* type */, UniquePtr<SessionCallbackData> &&data) {
476   Nanoapp *nanoapp =
477       EventLoopManagerSingleton::get()->getEventLoop().findNanoappByAppId(
478           data->nanoappId);
479   if (nanoapp == nullptr) {
480     LOGE("Unable to find nanoapp with ID 0x%" PRIx64
481          " to close the session with ID %" PRIu16,
482          data->nanoappId, data->sessionData.sessionId);
483     return;
484   }
485 
486   bool success =
487       EventLoopManagerSingleton::get()->getEventLoop().distributeEventSync(
488           data->isClosed ? CHRE_EVENT_MSG_SESSION_CLOSED
489                          : CHRE_EVENT_MSG_SESSION_OPENED,
490           &data->sessionData, nanoapp->getInstanceId());
491   if (!success) {
492     LOGE("Unable to process session closed event to nanoapp with ID 0x%" PRIx64,
493          nanoapp->getAppId());
494   }
495 }
496 
onSessionOpenCompleteCallback(uint16_t,void * data,void *)497 void ChreMessageHubManager::onSessionOpenCompleteCallback(
498     uint16_t /* type */, void *data, void * /* extraData */) {
499   NestedDataPtr<SessionId> sessionId(data);
500   EventLoopManagerSingleton::get()
501       ->getChreMessageHubManager()
502       .getMessageHub()
503       .onSessionOpenComplete(sessionId);
504 }
505 
onMessageFreeCallback(std::byte * message,size_t,MessageFreeCallbackData &&)506 void ChreMessageHubManager::onMessageFreeCallback(
507     std::byte *message, size_t /* length */,
508     MessageFreeCallbackData && /* callbackData */) {
509   EventLoopManagerSingleton::get()->deferCallback(
510       SystemCallbackType::EndpointMessageFreeEvent, message,
511       ChreMessageHubManager::handleMessageFreeCallback);
512 }
513 
handleMessageFreeCallback(uint16_t,void * data,void *)514 void ChreMessageHubManager::handleMessageFreeCallback(uint16_t /* type */,
515                                                       void *data,
516                                                       void * /* extraData */) {
517   std::optional<CallbackAllocator<MessageFreeCallbackData>::CallbackRecord>
518       record = EventLoopManagerSingleton::get()
519                    ->getChreMessageHubManager()
520                    .getAndRemoveFreeCallbackRecord(data);
521   if (!record.has_value()) {
522     LOGE("Unable to find free callback record for message with message: %p",
523          data);
524     return;
525   }
526 
527   if (record->metadata.freeCallback == nullptr) {
528     return;
529   }
530 
531   EventLoopManagerSingleton::get()->getEventLoop().invokeMessageFreeFunction(
532       record->metadata.nanoappId, record->metadata.freeCallback,
533       record->message, record->messageSize);
534 }
535 
onSessionStateChanged(const Session & session,std::optional<Reason> reason)536 void ChreMessageHubManager::onSessionStateChanged(
537     const Session &session, std::optional<Reason> reason) {
538   for (const Endpoint &endpoint : {session.initiator, session.peer}) {
539     if (endpoint.messageHubId != kChreMessageHubId) {
540       continue;
541     }
542 
543     auto sessionCallbackData = MakeUnique<SessionCallbackData>();
544     if (sessionCallbackData.isNull()) {
545       FATAL_ERROR_OOM();
546       return;
547     }
548 
549     const Endpoint &otherParty =
550         session.initiator == endpoint ? session.peer : session.initiator;
551     uint64_t nanoappId = endpoint.endpointId;
552     sessionCallbackData->nanoappId = nanoappId;
553     sessionCallbackData->isClosed = reason.has_value();
554     sessionCallbackData->sessionData = {
555         .hubId = otherParty.messageHubId,
556         .endpointId = otherParty.endpointId,
557         .sessionId = session.sessionId,
558     };
559     sessionCallbackData->sessionData.reason =
560         reason.has_value()
561             ? toChreEndpointReason(*reason)
562             : chreMsgEndpointReason::CHRE_MSG_ENDPOINT_REASON_UNSPECIFIED;
563     if (session.serviceDescriptor[0] != '\0') {
564       std::strncpy(sessionCallbackData->sessionData.serviceDescriptor,
565                    session.serviceDescriptor,
566                    CHRE_MSG_MAX_SERVICE_DESCRIPTOR_LEN);
567       sessionCallbackData->sessionData
568           .serviceDescriptor[CHRE_MSG_MAX_SERVICE_DESCRIPTOR_LEN - 1] = '\0';
569     } else {
570       sessionCallbackData->sessionData.serviceDescriptor[0] = '\0';
571     }
572 
573     EventLoopManagerSingleton::get()->deferCallback(
574         SystemCallbackType::EndpointSessionStateChangedEvent,
575         std::move(sessionCallbackData),
576         ChreMessageHubManager::onSessionStateChangedCallback);
577 
578     if (session.initiator == session.peer) {
579       // Session between self - only deliver one event
580       return;
581     }
582   }
583 }
584 
585 //! Called when a session open is requested.
onSessionOpenComplete(message::SessionId sessionId)586 void ChreMessageHubManager::onSessionOpenComplete(
587     message::SessionId sessionId) {
588   EventLoopManagerSingleton::get()->deferCallback(
589       SystemCallbackType::EndpointSessionRequestedEvent,
590       NestedDataPtr<SessionId>(sessionId),
591       ChreMessageHubManager::onSessionOpenCompleteCallback);
592 }
593 
onEndpointReadyEvent(MessageHubId messageHubId,EndpointId endpointId)594 void ChreMessageHubManager::onEndpointReadyEvent(MessageHubId messageHubId,
595                                                  EndpointId endpointId) {
596   CHRE_ASSERT(inEventLoopThread());
597 
598   for (size_t i = 0; i < mEndpointReadyEventRequests.size(); ++i) {
599     EndpointReadyEventData &data = mEndpointReadyEventRequests[i];
600     bool messageHubIdMatches = data.messageHubId == MESSAGE_HUB_ID_ANY ||
601                                data.messageHubId == messageHubId;
602     bool endpointIdMatches =
603         data.endpointId == ENDPOINT_ID_ANY || data.endpointId == endpointId;
604     if (messageHubIdMatches && endpointIdMatches) {
605       Nanoapp *nanoapp =
606           EventLoopManagerSingleton::get()->getEventLoop().findNanoappByAppId(
607               data.fromEndpointId);
608       if (nanoapp == nullptr) {
609         LOGW("Could not find nanoapp with ID 0x%" PRIx64 " to send ready event",
610              data.fromEndpointId);
611         continue;
612       }
613 
614       if (data.serviceDescriptor == nullptr ||
615           MessageRouterSingleton::get()->doesEndpointHaveService(
616               messageHubId, endpointId, data.serviceDescriptor)) {
617         sendReadyEventToNanoapp(nanoapp->getInstanceId(), messageHubId,
618                                 endpointId, data.serviceDescriptor);
619       }
620     }
621   }
622 }
623 
findDefaultMessageHubId(EndpointId endpointId)624 MessageHubId ChreMessageHubManager::findDefaultMessageHubId(
625     EndpointId endpointId) {
626   struct SearchContext {
627     MessageHubId toMessageHubId = MESSAGE_HUB_ID_INVALID;
628     EndpointId toEndpointId;
629   };
630   SearchContext context = {
631       .toEndpointId = endpointId,
632   };
633 
634   MessageRouterSingleton::get()->forEachEndpoint(
635       [&context](const MessageHubInfo &hubInfo,
636                  const EndpointInfo &endpointInfo) {
637         if (context.toMessageHubId == MESSAGE_HUB_ID_INVALID &&
638             endpointInfo.id == context.toEndpointId) {
639           context.toMessageHubId = hubInfo.id;
640         }
641       });
642   return context.toMessageHubId;
643 }
644 
doesNanoappHaveLegacyService(uint64_t nanoappId,uint64_t serviceId)645 bool ChreMessageHubManager::doesNanoappHaveLegacyService(uint64_t nanoappId,
646                                                          uint64_t serviceId) {
647   struct SearchContext {
648     uint64_t nanoappId;
649     uint64_t serviceId;
650     bool found;
651   };
652   SearchContext context = {
653       .nanoappId = nanoappId,
654       .serviceId = serviceId,
655       .found = false,
656   };
657 
658   EventLoopManagerSingleton::get()->getEventLoop().forEachNanoapp(
659       [](const Nanoapp *nanoapp, void *data) {
660         SearchContext *context = static_cast<SearchContext *>(data);
661         if (!context->found && nanoapp->getAppId() == context->nanoappId) {
662           context->found = nanoapp->hasRpcService(context->serviceId);
663         }
664       },
665       &context);
666   return context.found;
667 }
668 
validateServicesLocked(uint64_t nanoappId,const chreMsgServiceInfo * serviceInfos,size_t numServices)669 bool ChreMessageHubManager::validateServicesLocked(
670     uint64_t nanoappId, const chreMsgServiceInfo *serviceInfos,
671     size_t numServices) {
672   if (serviceInfos == nullptr || numServices == 0) {
673     LOGE("Failed to publish service for nanoapp with ID 0x%" PRIx64
674          ": serviceInfos is null or numServices is 0",
675          nanoappId);
676     return false;
677   }
678 
679   for (size_t i = 0; i < numServices; ++i) {
680     const chreMsgServiceInfo &serviceInfo = serviceInfos[i];
681 
682     if (serviceInfo.serviceDescriptor == nullptr ||
683         serviceInfo.serviceDescriptor[0] == '\0') {
684       LOGE("Failed to publish service for nanoapp with ID 0x%" PRIx64
685            ": service descriptor is null or empty",
686            nanoappId);
687       return false;
688     }
689 
690     uint64_t unused;
691     if (extractNanoappIdAndServiceId(serviceInfo.serviceDescriptor, unused,
692                                      unused)) {
693       LOGE("Failed to publish service for nanoapp with ID 0x%" PRIx64
694            ": service descriptor is in the legacy format",
695            nanoappId);
696       return false;
697     }
698 
699     for (const NanoappServiceData &service : mNanoappPublishedServices) {
700       if (std::strcmp(service.serviceInfo.serviceDescriptor,
701                       serviceInfo.serviceDescriptor) == 0) {
702         LOGE("Failed to publish service for nanoapp with ID 0x%" PRIx64
703              ": service descriptor: %s is already published by another "
704              "nanoapp",
705              nanoappId, service.serviceInfo.serviceDescriptor);
706         return false;
707       }
708     }
709 
710     for (size_t j = i + 1; j < numServices; ++j) {
711       if (std::strcmp(serviceInfo.serviceDescriptor,
712                       serviceInfos[j].serviceDescriptor)) {
713         LOGE("Failed to publish service for nanoapp with ID 0x%" PRIx64
714              ": service descriptor: %s repeats in list of services to publish",
715              nanoappId, serviceInfo.serviceDescriptor);
716         return false;
717       }
718     }
719   }
720   return true;
721 }
722 
searchForEndpoint(MessageHubId messageHubId,EndpointId endpointId,const char * serviceDescriptor)723 std::optional<Endpoint> ChreMessageHubManager::searchForEndpoint(
724     MessageHubId messageHubId, EndpointId endpointId,
725     const char *serviceDescriptor) {
726   if (endpointId == ENDPOINT_ID_INVALID) {
727     if (serviceDescriptor == nullptr) {
728       LOGD(
729           "Failed to search for an endpoint: no endpoint ID or service "
730           "descriptor");
731       return std::nullopt;
732     }
733     return MessageRouterSingleton::get()->getEndpointForService(
734         messageHubId, serviceDescriptor);
735   }
736 
737   if (serviceDescriptor != nullptr) {
738     if (messageHubId == MESSAGE_HUB_ID_INVALID) {
739       LOGD(
740           "Failed to search for an endpoint: no message hub ID provided with "
741           "endpoint and service descriptor");
742       return std::nullopt;
743     }
744 
745     if (!MessageRouterSingleton::get()->doesEndpointHaveService(
746             messageHubId, endpointId, serviceDescriptor)) {
747       LOGD("Failed to search for an endpoint: endpoint 0x%" PRIx64
748            " on hub 0x%" PRIx64 " does not have service %s",
749            messageHubId, endpointId, serviceDescriptor);
750       return std::nullopt;
751     }
752     return Endpoint(messageHubId, endpointId);
753   }
754 
755   if (messageHubId == MESSAGE_HUB_ID_INVALID) {
756     messageHubId = findDefaultMessageHubId(endpointId);
757     if (messageHubId == MESSAGE_HUB_ID_INVALID) {
758       LOGD(
759           "Failed to search for an endpoint: no default message hub ID "
760           "found");
761       return std::nullopt;
762     }
763   } else if (!MessageRouterSingleton::get()
764                   ->getEndpointInfo(messageHubId, endpointId)
765                   .has_value()) {
766     LOGD("Failed to search for an endpoint: endpoint 0x%" PRIx64
767          " on hub 0x%" PRIx64 " does not exist",
768          messageHubId, endpointId);
769     return std::nullopt;
770   }
771   return Endpoint(messageHubId, endpointId);
772 }
773 
disableReadyEvents(EndpointId fromEndpointId,MessageHubId hubId,EndpointId endpointId,const char * serviceDescriptor)774 void ChreMessageHubManager::disableReadyEvents(EndpointId fromEndpointId,
775                                                MessageHubId hubId,
776                                                EndpointId endpointId,
777                                                const char *serviceDescriptor) {
778   for (size_t i = 0; i < mEndpointReadyEventRequests.size(); ++i) {
779     EndpointReadyEventData &request = mEndpointReadyEventRequests[i];
780     if (request.fromEndpointId == fromEndpointId &&
781         request.messageHubId == hubId && request.endpointId == endpointId) {
782       bool servicesAreNull =
783           request.serviceDescriptor == nullptr && serviceDescriptor == nullptr;
784       bool servicesAreSame =
785           request.serviceDescriptor != nullptr &&
786           serviceDescriptor != nullptr &&
787           std::strcmp(request.serviceDescriptor, serviceDescriptor) == 0;
788       if (servicesAreNull || servicesAreSame) {
789         mEndpointReadyEventRequests.erase(i);
790         break;
791       }
792     }
793   }
794 }
795 
toMessageRpcFormat(chreMsgEndpointServiceFormat format)796 RpcFormat ChreMessageHubManager::toMessageRpcFormat(
797     chreMsgEndpointServiceFormat format) {
798   switch (format) {
799     case chreMsgEndpointServiceFormat::CHRE_MSG_ENDPOINT_SERVICE_FORMAT_AIDL:
800       return RpcFormat::AIDL;
801     case chreMsgEndpointServiceFormat::
802         CHRE_MSG_ENDPOINT_SERVICE_FORMAT_PW_RPC_PROTOBUF:
803       return RpcFormat::PW_RPC_PROTOBUF;
804     default:
805       return RpcFormat::CUSTOM;
806   }
807 }
808 
clearManager()809 void ChreMessageHubManager::ChreMessageHubCallback::clearManager() {
810   LockGuard<Mutex> managerLock(mManagerLock);
811   mChreMessageHubManager = nullptr;
812 }
813 
onMessageReceived(pw::UniquePtr<std::byte[]> && data,uint32_t messageType,uint32_t messagePermissions,const Session & session,bool sentBySessionInitiator)814 bool ChreMessageHubManager::ChreMessageHubCallback::onMessageReceived(
815     pw::UniquePtr<std::byte[]> &&data, uint32_t messageType,
816     uint32_t messagePermissions, const Session &session,
817     bool sentBySessionInitiator) {
818   Endpoint receiver = sentBySessionInitiator ? session.peer : session.initiator;
819   auto messageCallbackData = MakeUnique<MessageCallbackData>();
820   if (messageCallbackData.isNull()) {
821     LOG_OOM();
822     return false;
823   }
824 
825   messageCallbackData->messageToNanoapp = {
826       .messageType = messageType,
827       .messagePermissions = messagePermissions,
828       .message = data.get(),
829       .messageSize = data.size(),
830       .sessionId = session.sessionId,
831   };
832   messageCallbackData->data = std::move(data);
833   messageCallbackData->nanoappId = receiver.endpointId;
834 
835   return EventLoopManagerSingleton::get()->deferCallback(
836       SystemCallbackType::EndpointMessageToNanoappEvent,
837       std::move(messageCallbackData),
838       ChreMessageHubManager::onMessageToNanoappCallback);
839 }
840 
onSessionOpenRequest(const Session & session)841 void ChreMessageHubManager::ChreMessageHubCallback::onSessionOpenRequest(
842     const Session &session) {
843   LockGuard<Mutex> managerLock(mManagerLock);
844   if (mChreMessageHubManager == nullptr) {
845     LOGW("The ChreMessageHubManager has been destroyed.");
846     return;
847   }
848 
849   mChreMessageHubManager->onSessionOpenComplete(session.sessionId);
850 }
851 
onSessionOpened(const Session & session)852 void ChreMessageHubManager::ChreMessageHubCallback::onSessionOpened(
853     const Session &session) {
854   LockGuard<Mutex> managerLock(mManagerLock);
855   if (mChreMessageHubManager == nullptr) {
856     LOGW("The ChreMessageHubManager has been destroyed.");
857     return;
858   }
859 
860   mChreMessageHubManager->onSessionStateChanged(session,
861                                                 /* reason= */ std::nullopt);
862 }
863 
onSessionClosed(const Session & session,Reason reason)864 void ChreMessageHubManager::ChreMessageHubCallback::onSessionClosed(
865     const Session &session, Reason reason) {
866   LockGuard<Mutex> managerLock(mManagerLock);
867   if (mChreMessageHubManager == nullptr) {
868     LOGW("The ChreMessageHubManager has been destroyed.");
869     return;
870   }
871 
872   mChreMessageHubManager->onSessionStateChanged(session, reason);
873 }
874 
forEachEndpoint(const pw::Function<bool (const EndpointInfo &)> & function)875 void ChreMessageHubManager::ChreMessageHubCallback::forEachEndpoint(
876     const pw::Function<bool(const EndpointInfo &)> &function) {
877   EventLoopManagerSingleton::get()->getEventLoop().onMatchingNanoappEndpoint(
878       function);
879 }
880 
881 std::optional<EndpointInfo>
getEndpointInfo(EndpointId endpointId)882 ChreMessageHubManager::ChreMessageHubCallback::getEndpointInfo(
883     EndpointId endpointId) {
884   return EventLoopManagerSingleton::get()->getEventLoop().getEndpointInfo(
885       endpointId);
886 }
887 
888 std::optional<EndpointId>
getEndpointForService(const char * serviceDescriptor)889 ChreMessageHubManager::ChreMessageHubCallback::getEndpointForService(
890     const char *serviceDescriptor) {
891   LockGuard<Mutex> managerLock(mManagerLock);
892   if (mChreMessageHubManager == nullptr) {
893     LOGW("The ChreMessageHubManager has been destroyed.");
894     return std::nullopt;
895   }
896 
897   if (serviceDescriptor == nullptr || serviceDescriptor[0] == '\0') {
898     return std::nullopt;
899   }
900 
901   {
902     ConditionalLockGuard<Mutex> lockGuard(
903         mChreMessageHubManager->mNanoappPublishedServicesMutex,
904         !inEventLoopThread());
905     for (const NanoappServiceData &service :
906          mChreMessageHubManager->mNanoappPublishedServices) {
907       if (std::strcmp(serviceDescriptor,
908                       service.serviceInfo.serviceDescriptor) == 0) {
909         return service.nanoappId;
910       }
911     }
912   }
913 
914   // Check for the legacy service format
915   uint64_t nanoappId;
916   uint64_t serviceId;
917   return extractNanoappIdAndServiceId(serviceDescriptor, nanoappId,
918                                       serviceId) &&
919                  mChreMessageHubManager->doesNanoappHaveLegacyService(nanoappId,
920                                                                       serviceId)
921              ? std::make_optional(nanoappId)
922              : std::nullopt;
923 }
924 
doesEndpointHaveService(EndpointId endpointId,const char * serviceDescriptor)925 bool ChreMessageHubManager::ChreMessageHubCallback::doesEndpointHaveService(
926     EndpointId endpointId, const char *serviceDescriptor) {
927   // Endpoints are unique, so if we find it, then the endpoint has the service
928   // if and only if the endpoint ID matches the endpoint ID we are looking for
929   std::optional<EndpointId> endpoint = getEndpointForService(serviceDescriptor);
930   return endpoint.has_value() && endpoint.value() == endpointId;
931 }
932 
forEachService(const pw::Function<bool (const EndpointInfo &,const ServiceInfo &)> & function)933 void ChreMessageHubManager::ChreMessageHubCallback::forEachService(
934     const pw::Function<bool(const EndpointInfo &, const ServiceInfo &)>
935         &function) {
936   LockGuard<Mutex> managerLock(mManagerLock);
937   if (mChreMessageHubManager == nullptr) {
938     LOGW("The ChreMessageHubManager has been destroyed.");
939     return;
940   }
941 
942   {
943     ConditionalLockGuard<Mutex> lockGuard(
944         mChreMessageHubManager->mNanoappPublishedServicesMutex,
945         !inEventLoopThread());
946     for (const NanoappServiceData &service :
947          mChreMessageHubManager->mNanoappPublishedServices) {
948       std::optional<EndpointInfo> endpointInfo =
949           EventLoopManagerSingleton::get()->getEventLoop().getEndpointInfo(
950               service.nanoappId);
951       if (endpointInfo.has_value()) {
952         ServiceInfo serviceInfo(service.serviceInfo.serviceDescriptor,
953                                 service.serviceInfo.majorVersion,
954                                 service.serviceInfo.minorVersion,
955                                 mChreMessageHubManager->toMessageRpcFormat(
956                                     static_cast<chreMsgEndpointServiceFormat>(
957                                         service.serviceInfo.serviceFormat)));
958         if (function(endpointInfo.value(), serviceInfo)) {
959           return;
960         }
961       }
962     }
963   }
964 
965   EventLoopManagerSingleton::get()->getEventLoop().onMatchingNanoappService(
966       function);
967 }
968 
onHubRegistered(const MessageHubInfo &)969 void ChreMessageHubManager::ChreMessageHubCallback::onHubRegistered(
970     const MessageHubInfo & /*info*/) {
971   // We don't depend on this notification.
972 }
973 
onHubUnregistered(MessageHubId)974 void ChreMessageHubManager::ChreMessageHubCallback::onHubUnregistered(
975     MessageHubId /*id*/) {
976   // We don't depend on this notification.
977 }
978 
onEndpointRegistered(MessageHubId messageHubId,EndpointId endpointId)979 void ChreMessageHubManager::ChreMessageHubCallback::onEndpointRegistered(
980     MessageHubId messageHubId, EndpointId endpointId) {
981   if (messageHubId == MESSAGE_HUB_ID_INVALID ||
982       endpointId == ENDPOINT_ID_INVALID) {
983     LOGE(
984         "Invalid input to onEndpointRegistered: %s %s",
985         messageHubId == MESSAGE_HUB_ID_INVALID ? "messageHubId is invalid" : "",
986         endpointId == ENDPOINT_ID_INVALID ? "endpointId is invalid" : "");
987     return;
988   }
989 
990   UniquePtr<Endpoint> endpoint = MakeUnique<Endpoint>(messageHubId, endpointId);
991   if (endpoint.isNull()) {
992     FATAL_ERROR_OOM();
993     return;
994   }
995 
996   // We defer here to do all processing in the event loop thread. This allows
997   // for no locks as well as fast callbacks due to the potentially large
998   // number of nanoapps that may be waiting for events generated by this
999   // callback.
1000   EventLoopManagerSingleton::get()->deferCallback(
1001       SystemCallbackType::EndpointRegisteredEvent, std::move(endpoint),
1002       [](SystemCallbackType /* type */, UniquePtr<Endpoint> &&data) {
1003         EventLoopManagerSingleton::get()
1004             ->getChreMessageHubManager()
1005             .onEndpointReadyEvent(data->messageHubId, data->endpointId);
1006       });
1007 }
1008 
onEndpointUnregistered(MessageHubId,EndpointId)1009 void ChreMessageHubManager::ChreMessageHubCallback::onEndpointUnregistered(
1010     MessageHubId /* messageHubId */, EndpointId /* endpointId */) {
1011   // Ignore - we only care about registered endpoints
1012 }
1013 
pw_recycle()1014 void ChreMessageHubManager::ChreMessageHubCallback::pw_recycle() {
1015   memoryFreeAndDestroy(this);
1016 }
1017 
1018 }  // namespace chre
1019 
1020 #endif  // CHRE_MESSAGE_ROUTER_SUPPORT_ENABLED
1021