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