• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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/host_message_hub_manager.h"
18 #include "chre/target_platform/log.h"
19 
20 #ifdef CHRE_MESSAGE_ROUTER_SUPPORT_ENABLED
21 
22 #include <cstring>
23 #include <optional>
24 
25 #include "chre/core/event_loop_manager.h"
26 #include "chre/platform/assert.h"
27 #include "chre/platform/log.h"
28 #include "chre/platform/memory.h"
29 #include "chre/platform/mutex.h"
30 #include "chre/platform/shared/fbs/host_messages_generated.h"
31 #include "chre/platform/shared/host_protocol_chre.h"
32 #include "chre/util/lock_guard.h"
33 #include "chre/util/memory.h"
34 #include "chre/util/system/message_common.h"
35 #include "chre/util/system/message_router.h"
36 
37 #include "pw_allocator/unique_ptr.h"
38 #include "pw_function/function.h"
39 #include "pw_intrusive_ptr/intrusive_ptr.h"
40 #include "pw_span/span.h"
41 
42 namespace chre {
43 
44 using ::chre::message::EndpointId;
45 using ::chre::message::EndpointInfo;
46 using ::chre::message::MESSAGE_HUB_ID_INVALID;
47 using ::chre::message::MessageHubId;
48 using ::chre::message::MessageHubInfo;
49 using ::chre::message::MessageRouter;
50 using ::chre::message::MessageRouterSingleton;
51 using ::chre::message::Reason;
52 using ::chre::message::ServiceInfo;
53 using ::chre::message::Session;
54 using ::chre::message::SessionId;
55 
~HostMessageHubManager()56 HostMessageHubManager::~HostMessageHubManager() {
57   LockGuard<Mutex> hostLock(mHubsLock);
58   clearHubsLocked();
59 }
60 
onHostTransportReady(HostCallback & cb)61 void HostMessageHubManager::onHostTransportReady(HostCallback &cb) {
62   CHRE_ASSERT_LOG(mCb == nullptr,
63                   "HostMessageHubManager::init() called more than once");
64   mCb = &cb;
65 }
66 
reset()67 void HostMessageHubManager::reset() {
68   LOGI("Resetting HostMessageHubManager");
69   CHRE_ASSERT_NOT_NULL(mCb);
70   LockGuard<Mutex> hostLock(mHubsLock);
71   clearHubsLocked();
72 
73   // Serialize the following against any other embedded hub or endpoint
74   // registration events.
75   LockGuard<Mutex> embeddedLock(mEmbeddedHubOpLock);
76 
77   // Notify the HAL to accept embedded hub/endpoint registrations.
78   mCb->onReset();
79   MessageRouterSingleton::get()->forEachMessageHub(
80       [this](const MessageHubInfo &info) {
81         mCb->onHubRegistered(info);
82         return false;
83       });
84   MessageRouterSingleton::get()->forEachEndpoint(
85       [this](const MessageHubInfo &hub, const EndpointInfo &endpoint) {
86         mCb->onEndpointRegistered(hub.id, endpoint);
87       });
88   MessageRouterSingleton::get()->forEachService(
89       [this](const MessageHubInfo &hub, const EndpointInfo &endpoint,
90              const ServiceInfo &service) {
91         mCb->onEndpointService(hub.id, endpoint.id, service);
92         return false;
93       });
94   MessageRouterSingleton::get()->forEachEndpoint(
95       [this](const MessageHubInfo &hub, const EndpointInfo &endpoint) {
96         mCb->onEndpointReady(hub.id, endpoint.id);
97       });
98   LOGI("Initialized HostMessageHubManager");
99 }
100 
registerHub(const MessageHubInfo & info)101 void HostMessageHubManager::registerHub(const MessageHubInfo &info) {
102   LockGuard<Mutex> lock(mHubsLock);
103   pw::IntrusiveList<Endpoint> endpoints;
104   HostMessageHubManager::Hub::createLocked(this, info, endpoints);
105 }
106 
unregisterHub(MessageHubId id)107 void HostMessageHubManager::unregisterHub(MessageHubId id) {
108   LockGuard<Mutex> lock(mHubsLock);
109 
110   for (auto it = mHubs.begin(); it != mHubs.end(); ++it) {
111     if ((*it)->getMessageHub().getId() == id) {
112       (*it)->clear();
113       mHubs.erase(it);
114       return;
115     }
116   }
117   LOGE("No host hub 0x%" PRIx64 " for unregister", id);
118 }
119 
registerEndpoint(MessageHubId hubId,const EndpointInfo & info,DynamicVector<ServiceInfo> && services)120 void HostMessageHubManager::registerEndpoint(
121     MessageHubId hubId, const EndpointInfo &info,
122     DynamicVector<ServiceInfo> &&services) {
123   LockGuard<Mutex> lock(mHubsLock);
124   for (auto &hub : mHubs) {
125     if (hub->getMessageHub().getId() != hubId) continue;
126     hub->addEndpoint(info, std::move(services));
127     return;
128   }
129   LOGE("No host hub 0x%" PRIx64 " for add endpoint", hubId);
130 }
131 
unregisterEndpoint(MessageHubId hubId,EndpointId id)132 void HostMessageHubManager::unregisterEndpoint(MessageHubId hubId,
133                                                EndpointId id) {
134   LockGuard<Mutex> lock(mHubsLock);
135   for (auto &hub : mHubs) {
136     if (hub->getMessageHub().getId() != hubId) continue;
137     hub->removeEndpoint(id);
138     hub->getMessageHub().unregisterEndpoint(id);
139     return;
140   }
141   LOGE("No host hub 0x%" PRIx64 " for unregister endpoint", hubId);
142 }
143 
openSession(MessageHubId hubId,EndpointId endpointId,MessageHubId destinationHubId,EndpointId destinationEndpointId,SessionId sessionId,const char * serviceDescriptor)144 void HostMessageHubManager::openSession(MessageHubId hubId,
145                                         EndpointId endpointId,
146                                         MessageHubId destinationHubId,
147                                         EndpointId destinationEndpointId,
148                                         SessionId sessionId,
149                                         const char *serviceDescriptor) {
150   LockGuard<Mutex> lock(mHubsLock);
151   for (auto &hub : mHubs) {
152     if (hub->getMessageHub().getId() != hubId) continue;
153     if (hub->getMessageHub().openSession(
154             endpointId, destinationHubId, destinationEndpointId,
155             serviceDescriptor, sessionId) != sessionId) {
156       mCb->onSessionClosed(hubId, sessionId,
157                            Reason::OPEN_ENDPOINT_SESSION_REQUEST_REJECTED);
158     }
159     return;
160   }
161   LOGE("No host hub 0x%" PRIx64 " for open session", hubId);
162 }
163 
ackSession(MessageHubId hubId,SessionId sessionId)164 void HostMessageHubManager::ackSession(MessageHubId hubId,
165                                        SessionId sessionId) {
166   LockGuard<Mutex> lock(mHubsLock);
167   for (auto &hub : mHubs) {
168     if (hub->getMessageHub().getId() != hubId) continue;
169     hub->getMessageHub().onSessionOpenComplete(sessionId);
170     mCb->onSessionOpened(hubId, sessionId);
171     return;
172   }
173   LOGE("No host hub 0x%" PRIx64 " for ack session", hubId);
174 }
175 
closeSession(MessageHubId hubId,SessionId sessionId,Reason reason)176 void HostMessageHubManager::closeSession(MessageHubId hubId,
177                                          SessionId sessionId, Reason reason) {
178   LockGuard<Mutex> lock(mHubsLock);
179   for (auto &hub : mHubs) {
180     if (hub->getMessageHub().getId() != hubId) continue;
181     hub->getMessageHub().closeSession(sessionId, reason);
182     return;
183   }
184   LOGE("No host hub 0x%" PRIx64 " for close session", hubId);
185 }
186 
sendMessage(MessageHubId hubId,SessionId sessionId,pw::span<const std::byte> data,uint32_t type,uint32_t permissions)187 void HostMessageHubManager::sendMessage(MessageHubId hubId, SessionId sessionId,
188                                         pw::span<const std::byte> data,
189                                         uint32_t type, uint32_t permissions) {
190   LockGuard<Mutex> lock(mHubsLock);
191   for (auto &hub : mHubs) {
192     if (hub->getMessageHub().getId() != hubId) continue;
193     auto dataCopy = mMsgAllocator.MakeUniqueArray<std::byte>(data.size());
194     if (dataCopy == nullptr) {
195       LOGE("Failed to allocate endpoint message from host hub 0x%" PRIx64
196            " over session %" PRIu16,
197            hubId, sessionId);
198       return;
199     }
200     std::memcpy(dataCopy.get(), data.data(), data.size());
201 
202     // Note: We are assuming here that no host hubs will create sessions with
203     // themselves as it is not allowed by the HAL API.
204     hub->getMessageHub().sendMessage(std::move(dataCopy), type, permissions,
205                                      sessionId);
206     return;
207   }
208   LOGE("No host hub 0x%" PRIx64 " for send message", hubId);
209 }
210 
createLocked(HostMessageHubManager * manager,const MessageHubInfo & info,pw::IntrusiveList<Endpoint> & endpoints)211 bool HostMessageHubManager::Hub::createLocked(
212     HostMessageHubManager *manager, const MessageHubInfo &info,
213     pw::IntrusiveList<Endpoint> &endpoints) {
214   CHRE_ASSERT(manager != nullptr);
215 
216   // If there is an available slot, create a new Hub and try to register it with
217   // MessageRouter, cleaning it up on failure.
218   if (manager->mHubs.full()) {
219     LOGE("No space to register new host hub 0x%" PRIx64, info.id);
220     deallocateEndpoints(endpoints);
221     return false;
222   }
223 
224   Hub *hubPtr = memoryAlloc<Hub>(manager, info.name, endpoints);
225   if (hubPtr == nullptr) {
226     LOGE("Failed to allocate storage for new host hub %" PRIu64, info.id);
227     deallocateEndpoints(endpoints);
228     return false;
229   }
230 
231   pw::IntrusivePtr<Hub> hub(hubPtr);
232   manager->mHubs.push_back(hub);
233   std::optional<MessageRouter::MessageHub> maybeHub =
234       MessageRouterSingleton::get()->registerMessageHub(hub->kName, info.id,
235                                                         hub);
236   if (!maybeHub) {
237     LOGE("Failed to register host hub 0x%" PRIx64, info.id);
238     manager->mHubs.pop_back();
239     return false;
240   }
241   hub->mMessageHub = std::move(*maybeHub);
242   return true;
243 }
244 
Hub(HostMessageHubManager * manager,const char * name,pw::IntrusiveList<Endpoint> & endpoints)245 HostMessageHubManager::Hub::Hub(HostMessageHubManager *manager,
246                                 const char *name,
247                                 pw::IntrusiveList<Endpoint> &endpoints)
248     : mManager(manager) {
249   std::strncpy(kName, name, kNameMaxLen);
250   kName[kNameMaxLen] = 0;
251   mEndpoints.splice_after(mEndpoints.before_begin(), endpoints);
252 }
253 
~Hub()254 HostMessageHubManager::Hub::~Hub() {
255   // clear() should be explicitly called before destruction.
256   CHRE_ASSERT_LOG(!mMessageHub.isRegistered(),
257                   "Hub destroyed while registered");
258 }
259 
clear()260 void HostMessageHubManager::Hub::clear() {
261   getMessageHub().unregister();
262 
263   // This lock needs to be held to ensure the manager does not destruct
264   // while deallocating endpoints are called.
265   LockGuard<Mutex> managerLock(mManagerLock);
266   mManager = nullptr;
267 
268   LockGuard<Mutex> lock(mEndpointsLock);
269   deallocateEndpoints(mEndpoints);
270 }
271 
addEndpoint(const EndpointInfo & info,DynamicVector<ServiceInfo> && services)272 void HostMessageHubManager::Hub::addEndpoint(
273     const EndpointInfo &info, DynamicVector<ServiceInfo> &&services) {
274   Endpoint *endpoint = nullptr;
275   {
276     LockGuard<Mutex> managerLock(mManagerLock);
277     CHRE_ASSERT_LOG(mManager != nullptr,
278                     "The HostMessageHubManager has been destroyed.");
279 
280     endpoint = mManager->mEndpointAllocator.allocate(info, std::move(services));
281     if (endpoint == nullptr) {
282       LOGE("Failed to allocate storage for endpoint (0x%" PRIx64 ", 0x%" PRIx64
283            ")",
284            mMessageHub.getId(), info.id);
285       for (const auto &service : services)
286         memoryFree(const_cast<char *>(service.serviceDescriptor));
287       return;
288     }
289   }
290 
291   {
292     LockGuard<Mutex> lock(mEndpointsLock);
293     mEndpoints.push_back(*endpoint);
294   }
295   mMessageHub.registerEndpoint(info.id);
296 }
297 
removeEndpoint(EndpointId id)298 void HostMessageHubManager::Hub::removeEndpoint(EndpointId id) {
299   Endpoint *endpoint = nullptr;
300   {
301     LockGuard<Mutex> lock(mEndpointsLock);
302     for (auto it = mEndpoints.begin(), eraseIt = mEndpoints.before_begin();
303          it != mEndpoints.end(); ++it, ++eraseIt) {
304       if (it->kInfo.id == id) {
305         mEndpoints.erase_after(eraseIt);
306         endpoint = &(*it);
307         break;
308       }
309     }
310   }
311   if (endpoint) {
312     LockGuard<Mutex> managerLock(mManagerLock);
313     CHRE_ASSERT_LOG(mManager != nullptr,
314                     "The HostMessageHubManager has been destroyed.");
315     mManager->mEndpointAllocator.deallocate(endpoint);
316   }
317 }
318 
onMessageReceived(pw::UniquePtr<std::byte[]> && data,uint32_t messageType,uint32_t messagePermissions,const Session & session,bool)319 bool HostMessageHubManager::Hub::onMessageReceived(
320     pw::UniquePtr<std::byte[]> &&data, uint32_t messageType,
321     uint32_t messagePermissions, const Session &session,
322     bool /*sentBySessionInitiator*/) {
323   LockGuard<Mutex> managerLock(mManagerLock);
324   if (mManager == nullptr) {
325     LOGW("The HostMessageHubManager has been destroyed.");
326     return false;
327   }
328 
329   return mManager->mCb->onMessageReceived(mMessageHub.getId(),
330                                           session.sessionId, std::move(data),
331                                           messageType, messagePermissions);
332 }
333 
onSessionOpenRequest(const Session & session)334 void HostMessageHubManager::Hub::onSessionOpenRequest(const Session &session) {
335   LockGuard<Mutex> managerLock(mManagerLock);
336   if (mManager == nullptr) {
337     LOGW("The HostMessageHubManager has been destroyed.");
338     return;
339   }
340 
341   return mManager->mCb->onSessionOpenRequest(session);
342 }
343 
onSessionOpened(const Session & session)344 void HostMessageHubManager::Hub::onSessionOpened(const Session &session) {
345   LockGuard<Mutex> managerLock(mManagerLock);
346   if (mManager == nullptr) {
347     LOGW("The HostMessageHubManager has been destroyed.");
348     return;
349   }
350 
351   return mManager->mCb->onSessionOpened(mMessageHub.getId(), session.sessionId);
352 }
353 
onSessionClosed(const Session & session,Reason reason)354 void HostMessageHubManager::Hub::onSessionClosed(const Session &session,
355                                                  Reason reason) {
356   LockGuard<Mutex> managerLock(mManagerLock);
357   if (mManager == nullptr) {
358     LOGW("The HostMessageHubManager has been destroyed.");
359     return;
360   }
361 
362   return mManager->mCb->onSessionClosed(mMessageHub.getId(), session.sessionId,
363                                         reason);
364 }
365 
forEachEndpoint(const pw::Function<bool (const EndpointInfo &)> & function)366 void HostMessageHubManager::Hub::forEachEndpoint(
367     const pw::Function<bool(const EndpointInfo &)> &function) {
368   LockGuard<Mutex> lock(mEndpointsLock);
369   for (const auto &endpoint : mEndpoints)
370     if (function(endpoint.kInfo)) break;
371 }
372 
getEndpointInfo(EndpointId endpointId)373 std::optional<EndpointInfo> HostMessageHubManager::Hub::getEndpointInfo(
374     EndpointId endpointId) {
375   LockGuard<Mutex> lock(mEndpointsLock);
376   for (const auto &endpoint : mEndpoints)
377     if (endpoint.kInfo.id == endpointId) return endpoint.kInfo;
378   return {};
379 }
380 
getEndpointForService(const char * serviceDescriptor)381 std::optional<EndpointId> HostMessageHubManager::Hub::getEndpointForService(
382     const char *serviceDescriptor) {
383   LockGuard<Mutex> lock(mEndpointsLock);
384   for (const auto &endpoint : mEndpoints) {
385     for (const auto &service : endpoint.mServices) {
386       if (!std::strcmp(serviceDescriptor, service.serviceDescriptor))
387         return endpoint.kInfo.id;
388     }
389   }
390   return {};
391 }
392 
doesEndpointHaveService(EndpointId endpointId,const char * serviceDescriptor)393 bool HostMessageHubManager::Hub::doesEndpointHaveService(
394     EndpointId endpointId, const char *serviceDescriptor) {
395   LockGuard<Mutex> lock(mEndpointsLock);
396   for (const auto &endpoint : mEndpoints) {
397     if (endpoint.kInfo.id != endpointId) continue;
398     for (const auto &service : endpoint.mServices) {
399       if (!std::strcmp(serviceDescriptor, service.serviceDescriptor))
400         return true;
401     }
402     return false;
403   }
404   return false;
405 }
406 
forEachService(const pw::Function<bool (const message::EndpointInfo &,const message::ServiceInfo &)> & function)407 void HostMessageHubManager::Hub::forEachService(
408     const pw::Function<bool(const message::EndpointInfo &,
409                             const message::ServiceInfo &)> &function) {
410   LockGuard<Mutex> lock(mEndpointsLock);
411   for (const auto &endpoint : mEndpoints) {
412     for (const auto &service : endpoint.mServices)
413       function(endpoint.kInfo, service);
414   }
415 }
416 
onHubRegistered(const MessageHubInfo & info)417 void HostMessageHubManager::Hub::onHubRegistered(const MessageHubInfo &info) {
418   LockGuard<Mutex> managerLock(mManagerLock);
419   if (mManager == nullptr) {
420     LOGW("The HostMessageHubManager has been destroyed.");
421     return;
422   }
423 
424   LockGuard<Mutex> lock(mManager->mEmbeddedHubOpLock);
425   mManager->mCb->onHubRegistered(info);
426 }
427 
onHubUnregistered(MessageHubId id)428 void HostMessageHubManager::Hub::onHubUnregistered(MessageHubId id) {
429   LockGuard<Mutex> managerLock(mManagerLock);
430   if (mManager == nullptr) {
431     LOGW("The HostMessageHubManager has been destroyed.");
432     return;
433   }
434 
435   LockGuard<Mutex> lock(mManager->mEmbeddedHubOpLock);
436   mManager->mCb->onHubUnregistered(id);
437 }
438 
onEndpointRegistered(MessageHubId messageHubId,EndpointId endpointId)439 void HostMessageHubManager::Hub::onEndpointRegistered(MessageHubId messageHubId,
440                                                       EndpointId endpointId) {
441   std::optional<EndpointInfo> endpoint =
442       MessageRouterSingleton::get()->getEndpointInfo(messageHubId, endpointId);
443   if (!endpoint) return;
444   LockGuard<Mutex> managerLock(mManagerLock);
445   if (mManager == nullptr) {
446     LOGW("The HostMessageHubManager has been destroyed.");
447     return;
448   }
449   LockGuard<Mutex> lock(mManager->mEmbeddedHubOpLock);
450 
451   mManager->mCb->onEndpointRegistered(messageHubId, *endpoint);
452   struct {
453     HostCallback *cb;
454     MessageHubId hub;
455     EndpointId endpoint;
456   } context = {
457       .cb = mManager->mCb, .hub = messageHubId, .endpoint = endpointId};
458   MessageRouterSingleton::get()->forEachService(
459       [&context](const MessageHubInfo &hub, const EndpointInfo &endpoint,
460                  const ServiceInfo &service) {
461         if (context.hub != hub.id) return false;
462         if (context.endpoint != endpoint.id) return false;
463         context.cb->onEndpointService(hub.id, endpoint.id, service);
464         return false;
465       });
466   mManager->mCb->onEndpointReady(messageHubId, endpointId);
467 }
468 
onEndpointUnregistered(MessageHubId messageHubId,EndpointId endpointId)469 void HostMessageHubManager::Hub::onEndpointUnregistered(
470     MessageHubId messageHubId, EndpointId endpointId) {
471   LockGuard<Mutex> managerLock(mManagerLock);
472   if (mManager == nullptr) {
473     LOGW("The HostMessageHubManager has been destroyed.");
474     return;
475   }
476 
477   LockGuard<Mutex> lock(mManager->mEmbeddedHubOpLock);
478   mManager->mCb->onEndpointUnregistered(messageHubId, endpointId);
479 }
480 
pw_recycle()481 void HostMessageHubManager::Hub::pw_recycle() {
482   memoryFreeAndDestroy(this);
483 }
484 
DoAllocate(Layout layout)485 void *HostMessageHubManager::ChreAllocator::DoAllocate(Layout layout) {
486   return memoryAlloc(layout.size());
487 }
488 
DoDeallocate(void * ptr)489 void HostMessageHubManager::ChreAllocator::DoDeallocate(void *ptr) {
490   memoryFree(ptr);
491 }
492 
deallocateEndpoints(pw::IntrusiveList<Endpoint> & endpoints)493 void HostMessageHubManager::deallocateEndpoints(
494     pw::IntrusiveList<Endpoint> &endpoints) {
495   while (!endpoints.empty()) {
496     auto &endpoint = endpoints.front();
497     endpoints.pop_front();
498     EventLoopManagerSingleton::get()
499         ->getHostMessageHubManager()
500         .mEndpointAllocator.deallocate(&endpoint);
501   }
502 }
503 
clearHubsLocked()504 void HostMessageHubManager::clearHubsLocked() {
505   // Deactivate all existing message hubs. We need to call clear() on each hub
506   // to unregister it from MessageRouter as both MessageRouter and the
507   // HostMessageHubManager have a pw::IntrusivePtr to the Hub, which will not
508   // deallocate the Hub until both references are gone.
509   for (auto &hub : mHubs) {
510     hub->clear();
511   }
512   mHubs.clear();
513 }
514 
515 }  // namespace chre
516 
517 #endif  // CHRE_MESSAGE_ROUTER_SUPPORT_ENABLED
518